
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <signal.h>
#include <limits.h>
#include <iostream.h>
#include <fstream.h>
#include <strings.h>
#include <string.h>
#include <new>
#include <list>
#include <arpa/telnet.h>

#include "server.h"
#include "ego.h"
using namespace std;

list<Ego*> Elist;
Ego::Ego( char *name, int descriptor )
{
   desc = descriptor;
   inputbufferlen = 0;
   idle = 0;
   strcpy( username, name );
   state = NEWCONNECTION;
}


Ego::~Ego()
{
   if( desc )
      close( desc );
   if( inputbufferlen )
      free( inputbuffer );
}

int Ego::descriptor()
{
   return desc;
}

bool Ego::input()
{
   return !inBuffer.empty();
}
bool Ego::output()
{
   return !outBuffer.empty();
}

Message* Ego::command()
{
   Message* temp = inBuffer.front();
   inBuffer.pop();
   return temp;
}

states Ego::getstate()
{
   return state;
}

void Ego::setstate( states newstate )
{
   state = newstate;
}

void Ego::setuser( char *name )
{
   strcpy( username, name );
}

char* Ego::getuser()
{
   return username;
}

void Ego::setpass( char *pass )
{
   strcpy( password, pass );
}

bool Ego::passmatch( char *pass )
{
   return strcmp( password, pass ) == 0;
}

void Ego::write()
{
   while( output() )
   {
      Message *msg = outBuffer.front();
      outBuffer.pop();
      char buffer[ 256 ];
      int length = strlen( msg->getData() );
      if( length <= 254 )
      {
         buffer[0] = (char)length;
         buffer[1] = msg->getType();
         strncpy( buffer + 2, msg->getData(), 254 );
         std::write( desc, buffer, length + 2 );
         cerr << "message sent: " << username << "\n";
         delete msg;
      }
   }
}
void Ego::write( Message *msg )
{
   outBuffer.push( msg );
}
bool Ego::read()
{
   char buffer[10240];
   int nread=0;
   while(1) {
      nread=std::read(desc,buffer,10240);
      cout << "Ego::read(): " << nread << "\n";
      if(nread==10240) {
         cerr << "input buffer overflow: dropping user\n";
         write( new Message( Message::Server, "Bye" ) );
         return FALSE;
         }
      if( nread > 0 )
      {
         outdata.open( "input", O_APPEND |O_WRONLY);
         outdata << buffer;
         outdata.close();
         if(!inputbufferlen)
         {
            inputbuffer = (char*)malloc( nread );
            for( int index = 0; index < nread; index++ )
               inputbuffer[ inputbufferlen + index ] = buffer[ index ];
            inputbufferlen = nread;
         }
         else
         {
            inputbuffer = (char*)realloc( inputbuffer, inputbufferlen + nread );
            for( int index = 0; index < nread; index++ )
               inputbuffer[ inputbufferlen + index ] = buffer[ index ];
            inputbufferlen += nread;
         }
         parse();
         return TRUE;
      }
      else if( nread == 0 )
      {
         left( this );
         setstate(WAITTOCLOSE);
         cerr << "EOF on Descriptor read\n";
         return FALSE;
      }
      else
      {
         cerr << "Ego::read() invalid input: DISCARDING\n";
         write( new Message( Message::Server, "ERROR:INVALID" ) );
         return FALSE;
      }
   }
   cerr << "Read: unknown error\n";
   return FALSE;
}

void Ego::parse()
{
   bool done = false;
   char dat[256];
   char *buffer = inputbuffer;
   int total = inputbufferlen;
   while( !done )
   {
      int length = (int)buffer[0];
      Message::Type type = (Message::Type)buffer[1];
      if( total >= length + 2 )
      {
         strncpy( dat, buffer + 2, length );
         dat[ length ]= '\0';
         inBuffer.push( new Message( type, dat ) );
         cerr << "new message queued: " << dat << "\n";
         buffer += length + 2;
         total -= length + 2;
         if( total <= 0 )
            done = true;
      }
      else
         done = true;
   }
   if( total > 0 )
   {
      char *newbuf = new char[ total ];
      int index = 0;
      while( index < total )
      {
         newbuf[ index ] = buffer[ index ];
         index++;
      }
      inputbufferlen = total;
      free( inputbuffer );
      inputbuffer = newbuf;
   }
   else
   {
      free( inputbuffer );
      inputbufferlen = 0;
   }
}

void Ego::inroom( Message *msg )
{
   for( list<Ego*>::iterator itr = Elist.begin(); itr != Elist.end(); itr++ )
   {
      if( strcmp( username, (*itr)->username ) != 0 && state == (*itr)->state )
      {
         (*itr)->write( new Message( (*msg) ) );
      }
      else if( strcmp( username, (*itr)->username ) == 0 && state == (*itr)->state )
      {
         (*itr)->write( new Message( (*msg) ) );
      }
   }
}
void Ego::listinroom()
{
   write( new Message( Message::Server, "UserList" ) );
   for( list<Ego*>::iterator itr = Elist.begin(); itr != Elist.end(); itr++ )
   {
      if( state == (*itr)->state )
      {
         write( new Message( Message::Server, (*itr)->getuser() ) );
      }
   }
}
void Ego::announce( Ego *who )
{
   for( list<Ego*>::iterator itr = Elist.begin(); itr != Elist.end(); itr++ )
   {
      if( strcmp( username, (*itr)->username ) != 0 && state == (*itr)->state )
      {
         char buffer[200];
         sprintf( buffer,">> %s has joined the chat", who->getuser() );
         (*itr)->write( new Message( Message::Text, buffer ) );
         (*itr)->listinroom();
      }
   }
}
void Ego::left( Ego *who )
{
   for( list<Ego*>::iterator itr = Elist.begin(); itr != Elist.end(); itr++ )
   {
      if( strcmp( username, (*itr)->username ) != 0 && state == (*itr)->state )
      {
         char buffer[200];
         sprintf( buffer,"<< %s has left the chat", who->getuser() );
         (*itr)->write( new Message( Message::Text, buffer ) );
         (*itr)->listinroom();
      }
   }
}

