#include "Ptr.h"
#include "PtrInterface.h"
#include <string>
#include <vector>

namespace CS349WebServer {
  template<typename T, typename S>
  class Integer {
    private:
      T value_;

    public:
      operator T() { return value_; }
      Integer(const T &t = 0) : value_(t) {}
      Integer operator++() { return ++value_; }
  };

  class IPAddress_;
  typedef Integer<unsigned int, IPAddress_> IPAddress;

  class TCPPort_;
  typedef Integer<unsigned short, TCPPort_> TCPPort;

  class SocketFileDescriptor_;
  typedef Integer<int, SocketFileDescriptor_> SocketFileDescriptor;

  class UnsignedInteger_;
  typedef Integer<unsigned int, UnsignedInteger_> UnsignedInteger;

  class Cookie : public std::string {};
  class URL : public std::string {};

  template<typename T>
  class List : public std::vector<T> {};

  class Thread : public PtrInterface<Thread> {
    /* ASSUME HIDDEN IMPLEMENTATION */
  };

  class Connection : public PtrInterface<Connection> {
    public:
      class Manager;
      enum ConnectionStatus {
        Uninitialized,
        Connected,
        Disconnected,
        /*** Feel free to extend as desired ***/
      };

      IPAddress             clientIP() const { return clientIP_; }
      TCPPort               clientPort() const { return clientPort_; }
      SocketFileDescriptor  clientSocket() const { return clientSocket_; }
      List<URL>             visitHistory() const { return visitHistory_; }
      Cookie                authenticationToken() const { return authenticationToken_; }
      UnsignedInteger       bytesSent() const { return bytesSent_; }
      URL                   pendingRequest( UnsignedInteger i ) const { return pendingRequests_[i]; }
      UnsignedInteger       pendingRequests() const { return UnsignedInteger( pendingRequests_.size() ); }
      enum ConnectionStatus status() const { return status_; }
      Ptr<Manager>          manager() const { return manager_; }
      Ptr<Thread>           thread() const { return thread_; }

    private:
      IPAddress             clientIP_;
      TCPPort               clientPort_;
      SocketFileDescriptor  clientSocket_;
      List<URL>             visitHistory_;
      Cookie                authenticationToken_;
      UnsignedInteger       bytesSent_;
      List<URL>             pendingRequests_;
      enum ConnectionStatus status_;
      Ptr<Manager>          manager_;
      Ptr<Thread>           thread_;
  };

  class Connection::Manager : public PtrInterface<Connection::Manager> {
    public:
      void newConnection( Ptr<Connection> c ) {
        ++numNewConnections_;
        connections_.push_back( c );
      }

      void deleteConnection( Ptr<Connection> c ) {
        ++numDeletedConnections_;
        for ( UnsignedInteger i = 0 ; i < connections_.size() ; ++i ) {
          if ( connections_[i] == c ) {
            connections_.erase( connections_.begin() + i );
            break;
          }
        }
      }

      Ptr<Connection> connection( UnsignedInteger i ) const { return connections_[i]; }
      UnsignedInteger connections() const { return connections_.size(); }

      IPAddress serverIP() const { return serverIP_; }
      TCPPort serverPort() const { return serverPort_; }
      SocketFileDescriptor serverSocket() const { return serverSocket_; }
      UnsignedInteger maxNumConnections() const { return maxNumConnections_; }
      UnsignedInteger numNewConnections() const { return numNewConnections_; }
      UnsignedInteger numDeletedConnections() const { return numDeletedConnections_; }
      UnsignedInteger numThreads() const { return numThreads_; }
      List<Thread> idleThreadPool() const { return idleThreadPool_; }

    private:
      List< Ptr<Connection> > connections_;
      IPAddress               serverIP_;
      TCPPort                 serverPort_;
      SocketFileDescriptor    serverSocket_;
      UnsignedInteger         maxNumConnections_;
      UnsignedInteger         numNewConnections_;
      UnsignedInteger         numDeletedConnections_;
      UnsignedInteger         numThreads_;
      List<Thread>            idleThreadPool_;
  };
};

using namespace CS349WebServer;

