#include "cserver.h"

using namespace std;

cserver::cserver(unsigned short port)
{
   /* start server */
   sockaddr_in server_info;
   server_info.sin_family=AF_INET;
   server_info.sin_port=htons(port);
   server_info.sin_addr.s_addr=INADDR_ANY;
   bind(s,(sockaddr*) &server_info,sizeof(server_info));
   listen(s,SOMAXCONN);
   /* start server */
}

cserver::~cserver()
{
   /* iterator to iterate through connections */
   list <cconnection>::iterator i;
   /* iterator to iterate through connections */

   /* close sockets */
   for (i=connections.begin();i!=connections.end();i++) i->destroy();
   /* close sockets */
}

void cserver::write_packet(int n,char* packet)
{
   /* iterator to iterate through connections */
   list <cconnection>::iterator i;
   /* iterator to iterate through connections */

   /* header */
   char header[2]={strlen(packet),0};
   /* header */

   /* append header + packet to sendbuffer(s) */
   if (n==1)
      for (i=connections.begin();i!=connections.end();i++)
      {
         i->get_sb()->append(header);
         i->get_sb()->append(packet);
      }
   else
   {
      i=connections.begin();
      while (i->get_id()!=n) i++;
      i->get_sb()->append(header);
      i->get_sb()->append(packet);
   }
   /* append header + packet to sendbuffer(s) */
}

void cserver::update()
{
   /* iterator to iterate through connections */
   list <cconnection>::iterator i;
   /* iterator to iterate through connections */

   /* clear FD_SET */
   FD_ZERO(&read_sockets);
   FD_ZERO(&write_sockets);
   /* clear FD_SET */

   /* for connection requests */
   FD_SET(s,&read_sockets);
   /* for connection requests */

   /* highest file descriptor */
   int hfd=s;
   /* highest file descriptor */

   /* add sockets to FD_SET and check for highest file descriptor */
   for (i=connections.begin();i!=connections.end();i++)
   {
      FD_SET(i->get_s(),&read_sockets);
      FD_SET(i->get_s(),&write_sockets);
      if (i->get_s()>hfd) hfd=i->get_s();
   }
   /* add sockets to FD_SET and check for highest file descriptor */

   if (select(hfd+1,&read_sockets,&write_sockets,0,&delay)>0)
   {
      /* read data and remove disconnected connections */
      i=connections.begin();
      while (i!=connections.end())
      if (FD_ISSET(i->get_s(),&read_sockets))
      {
         char buffer[1025];
         int bytes=recv(i->get_s(),buffer,1024,0);
         if (bytes>0)
         {
            buffer[bytes]=0;
            i->get_rb()->append(buffer);
            i++;
         }
         else
         {
            /* send old id to server and remove connection */
            char packet[2]={i->get_id(),0};
            i->destroy();
            i=connections.erase(i);
            sb.append(packet);
            /* send old id to server and remove connection */
         }
      }
      else i++;
      /* read data and remove disconnected connections */

      /* send data and remove it from the sendbuffer */
      for (i=connections.begin();i!=connections.end();i++)
      if (FD_ISSET(i->get_s(),&write_sockets))
      {
         int bytes=send(i->get_s(),i->get_sb()->data(),i->get_sb()->size(),0);
         i->get_sb()->erase(0,bytes);
      }
      /* send data and remove it from the sendbuffer */

      /* accept/reject new connection */
      if (FD_ISSET(s,&read_sockets))
      {
         if (connections.size()<MAX_CONNECTIONS)
         {
            /* search for unused id */
            int n=2;
            i=connections.begin();
            while (i!=connections.end()) if (i->get_id()!=n) i++;
                                         else
                                         {
                                            n++;
                                            i=connections.begin();
                                         }
            /* search for unused id */

            /* create new connection and send new id to server */
            connections.push_front(cconnection());
            connections.begin()->create(accept(s,0,0),n);
            char packet[2]={n,0};
            sb.append(packet);
            /* create new connection and send new id to server */
         }
         else
         {
            SOCKET reject=accept(s,0,0);
            closesocket(reject);
         }
      }
      /* accept/reject new connection */
   }
}

int cserver::read_packet(char* packet)
{
   /* id */
   int n=0;
   /* id */

   /* connected/disconnected clients */
   if (sb.size()>0)
   {
      packet[0]=0;
      n=sb[0];
      sb.erase(0,1);
   }
   /* connected/disconnected clients */

   /* packets */
   else
   {
      /* iterator to iterate through connections */
      list <cconnection>::iterator i=connections.begin();
      /* iterator to iterate through connections */

      /* copy packet and remove it from the receivebuffer*/
      while (i!=connections.end())
      {
         if (i->get_rb()->size()>1)
         {
            int length=(*i->get_rb())[0];
            if (i->get_rb()->size()>length)
            {
               n=i->get_id();
               i->get_rb()->copy(packet,length,1);
               packet[length]=0;
               i->get_rb()->erase(0,length+1);
               i=connections.end();
            }
            else i++;
         }
         else i++;
      }
      /* copy packet and remove it from the receivebuffer*/
   }
   /* packets */

   /* return id */
   return n;
   /* return id */
}
