/* squidClass.hpp */
#ifndef SQUIDCLASS_HPP
#define  SQUIDCLASS_HPP

//DEBUG: section 90

class squid_fde {
   int fh; /* real file handle or socket */
public:
    unsigned int type;
    u_short local_port;
    u_short remote_port;
    struct in_addr local_addr;
    unsigned char tos;
    char ipaddr[16];           /* dotted decimal address of peer */
    char desc[FD_DESC_SZ];
    struct {
       unsigned int open:1;
       unsigned int close_request:1;
       unsigned int write_daemon:1;
       unsigned int closing:1;
       unsigned int socket_eof:1;
       unsigned int nolinger:1;
       unsigned int nonblocking:1;
       unsigned int ipc:1;
       unsigned int called_connect:1;
       unsigned int nodelay:1;
       unsigned int close_on_exec:1;
       unsigned int read_pending:1;
    } flags;
/*use in comm_select */
    unsigned int bytes_read;
    unsigned int bytes_written;
    int uses;                  /* ie # req's over persistent conn */

    struct _fde_disk  disk;

    PF *read_handler;
    void *read_data;
    PF *write_handler;
    void *write_data;
    PF *timeout_handler;
    time_t timeout;
    void *timeout_data;
//    void *lifetime_data; /* Not Used ?? */
    _close_handler *close_handler;      /* linked list */
    DEFER *defer_check;                /* check if we should defer read */
    void *defer_data;
    CommWriteStateData *rwstate;       /* State data for comm_write */
#if USE_SSL
    SSL *ssl;
    int ssl_shutdown:1;
#endif

    squid_fde (void)
    {
         fh = -1;
         type = FD_NONE;
    }
    void Change(int _fh, int _type)
    {  fh = _fh;
       type = _type;
    }

    void ChangeSocket(int _fh, int ind, int *socketToIndex)
    {  const  int  NumSocketToIndex = 0x10000;

       if(socketToIndex   && type == FD_SOCKET)
       {   debug(91, 8)
            ("ChangeSocket: fh=%d (socketToIndex[]=%d) -> _fh=%d (socketToIndex[]=%d), ind=%i\n",
            fh,socketToIndex[fh], _fh, socketToIndex[_fh], ind);

           if(fh >= 0 && fh < NumSocketToIndex)
                                socketToIndex[fh] = -1;
           if(_fh >= 0 && _fh < NumSocketToIndex)
                                socketToIndex[_fh] = ind;
       }
       fh = _fh;
    }


    int GetSocket(void);
    int GetFileHandle(void);
    int write(char *buf, int len);
    int read(char *buf, int len);
    int close(void);
    int open(const char *desc);
    int  sFD_ISSET(fd_set *readfds);
    void sFD_CLR(fd_set *readfds);
    void sFD_SET(fd_set *readfds);
    int check(void);

};

struct PipeInfo
{  int index;
   int type;  /* 0x1- read 0x2-write 0x4 - exist, 0x7 - read-write */
};

struct ChildInfo
{   int pid;
    char *pProgname;
};

class squid_fdeArray
{
  public:
  int n;             /* number of used items in fd_table i.e. analog of Biggest_FD */
  int nAllocated;    /* allocated siseof fd_table        */
  int iCurrent;      /* current index                    */
  int Number_FD;     /* number of live *fd               */
  int MaxSocket;     /* Max  socket descriptor for select*/
  int MinSocket;     /* Min  socket descriptor for select*/
  squid_fde *fd_table;
  int *SocketToIndex;
                      /* массив для получения индекса по сокету */
                      /* размерность должна быть равна размерности fd_set.fd_array  */
  int NumSocketToIndex; /* размер массива SocketToIndex - для 32битных стеков */
  int NumPipes;                   /* число пайпов */
  struct PipeInfo listPipes[256]; /* список пайпов */
  int NumChilds;      /* число дочерних процессов  */
  struct ChildInfo listChilds[256]; /* список дочерних процессов */
  int NumReadReadyPipes;   /* кол-во пайпов read-ready */
//  int readReadyPipes[128]; /* список read-ready пайпов */
  int NumWriteReadyPipes;  /* кол-во пайпов Write-ready */
//  int writeReadyPipes[128];/* список Write-ready пайпов */

   squid_fdeArray(void)
   {   int i;
       nAllocated =  SQUID_MAXFD;
       fd_table = (squid_fde *)xcalloc(nAllocated+1, sizeof(squid_fde));

//       SocketToIndex = (int *) xcalloc(SQUID_MAXFD+1, sizeof(int));
       NumSocketToIndex = 0x10000;
       SocketToIndex = (int *) xcalloc(NumSocketToIndex+1, sizeof(int));
       for(i=0; i < NumSocketToIndex; i++) SocketToIndex[i] = -1;
//       NumSocketToIndex = SQUID_MAXFD;
       n = 0;
       iCurrent = 0;
       MaxSocket = -1;
       MinSocket = 0;
       Number_FD = 0;
       NumWriteReadyPipes = NumReadReadyPipes =   NumPipes = 0;
       NumChilds = 0;
   }

   squid_fde * squid_fdeArrayRealloc(int _MaxFD)
   {
      nAllocated = _MaxFD;
      if(nAllocated > 0x10000) nAllocated = 0x10000;
      if(fd_table)
      {
         fd_table = (squid_fde *)xrealloc((void *)fd_table, (nAllocated+1) * sizeof(squid_fde));
      } else {
         fd_table = (squid_fde *)xcalloc(nAllocated+1, sizeof(squid_fde));
      }
      return fd_table;
   }

   int NFree(void)
   {  return (nAllocated - Number_FD);
   }
   int Add(int fh, int type);
   int AddPipe(int index, int type);
   int DelPipe(int index);

   void sFD_SET  (int index, fd_set *readfds);
   int  sFD_ISSET(int index, fd_set *readfds, int id);
   void sFD_CLR  (int index, fd_set *readfds);
   int check(int index, int number);
   int checkSocket(int index, int number);

   int open(int &index,int fh, unsigned int type, const char *desc);
   int close(int index);
   int closeAll();

   int MarkWriteReadyPipe(int index);
   int MarkReadReadyPipe(int index);
   int QueryPipe(int index, int mask);
   int MarkClearReadyPipe(int index, int mask);

   int AddChild(int pid, char *pName)
   {  if(NumChilds < sizeof(listChilds)/sizeof(struct ChildInfo))
      {  listChilds[NumChilds].pid = pid;
         listChilds[NumChilds].pProgname = pName;
         NumChilds++;
      }
      return 0;
   }

};

#endif // SQUIDCLASS_HPP

//FD_READ_METHOD ->fd_table[fd].read_method
//FD_WRITE_METHOD->fd_table[fd].write_method
