/****************************************************************************
** Client - class
**
**   Created : Fri Jun 6 12:09:08 2008
**        by : Varol Okan using kate editor
** Copyright : (c) Varol Okan
**   License : GPL v 2.0
**
**
****************************************************************************/

#ifndef RENDER_CLIENT_H
#define RENDER_CLIENT_H

#include <qthread.h>
#include <qsocket.h>
#include <qpixmap.h>
#include <qdatetime.h>
#include <qvaluelist.h>
#include <qwaitcondition.h>

class QFile;

#define EVENT_RENDER_EXIT      11111
#define EVENT_RENDER_PROGRESS  11112
#define EVENT_RENDER_EXCEPTION 11113

// The block size we shuffle over the socket at once.
#define BLOCK_LEN 1024
// Throttling transfere over socket for better debugging (delay in usec)
#define THROTTLE 0

class CXmlSlideshow;
class SourceFileEntry;
class ButtonTransition;

namespace Render
{

class Client : public QObject, public QThread
{
  Q_OBJECT

  template<class type> class Message  {
  public:
    Message ( ) { };
    static QByteArray create ( type value )
    {
      char cBuffer[ sizeof ( type ) ];
      (type &)cBuffer = value;
      return QByteArray ( cBuffer, sizeof ( type ) );
    }
  };

public:
  Client ( SourceFileEntry  * );
  Client ( ButtonTransition * );
  virtual  ~Client ( );

  virtual void run ( );
  void lock   ( );
  void unlock ( );
  void initMe ( );
  void startMe( );

  float progress         ( );
  bool  waitingInQueue   ( );
  void  killServerThread ( );
  void  setWaiting  ( bool );
  SourceFileEntry  *sourceFileEntry  ( );
  ButtonTransition *buttonTransition ( );

protected:
  virtual void timerEvent ( QTimerEvent   * );
  void runSlideshow       ( CXmlSlideshow * );
  bool sendFile ( QString );
  void enableTimer ( bool );
  void runEntry         ( );
  void runTrans         ( );
  void startServer      ( );
  void restartServer    ( );
  void receivedPing     ( );
  void sendNextPacket   ( );
  void receivedFileAck  ( );
  void displayProgress  ( );
  void receivedProgress ( );
  Q_UINT64 fileFromSocket        ( );
  void receivedServerDone        ( );
  void receivedServerState       ( );
  void receivedVersionAndHost    ( );
  bool sendVersionAndHostRequest ( );
  static void reRequest ( Client * );

private slots:
  virtual void closeConnection ( );
  virtual void socketReadyRead ( );
  virtual void socketConnected ( );
  virtual void socketClosed    ( );
  virtual void slotReconnect   ( );
  virtual void slotRecovered   ( );
  virtual void socketError ( int );
  virtual void socketConnectionClosed ( );
  virtual void slotConnectAndStart    ( );
  virtual void socketConnectAndStart  ( );

private:
  // Something for the server connection
  QFile            *m_pFile;
  QSocket          *m_pSocket;
  SourceFileEntry  *m_pSourceFileEntry;
  ButtonTransition *m_pButtonTransition;
  QWaitCondition    m_waiter;
  QMutex            m_mutex;
  float             m_fProgress;
  Q_ULONG           m_iMessageLen;     // to keep track of the incoming slideshow video file
  Q_UINT16          m_iMessageID;      // The current MessageID being processed
  bool              m_bRemoteServer;   // The server is on a different computer
  bool              m_bSendImageFiles; // The server needs the image files ( def. true )
  bool              m_bWaitInQueue;    // If the server has currently more then the set threads running
  bool              m_bSentAllInfo;    // has the function run() completed ?
  int               m_iKeepaliveTimer; // Checks if the server has a heartbeat
  QDateTime         m_lastPing;        // Last received ping
  int               m_iRetryCounter;   // The numer of times to try to re-establish the connection
};

// Singleton class Manager
class Manager
{
public:
  class ServerInfo
  {
  public:
    ServerInfo ( unsigned long, unsigned int, unsigned int );
   ~ServerInfo ( );

    unsigned long  getIP ( );
    unsigned int getPort ( );
    Client    *addClient ( SourceFileEntry  * );
    bool    removeClient ( SourceFileEntry  * );
    Client    *addClient ( ButtonTransition * );
    bool    removeClient ( ButtonTransition * );
    bool startNextClient ( );
    bool  startingServer ( );
    int      clientCount ( );
    void     startServer ( );
    bool      inRecovery ( ); // connection was lost and now trying to re-eastablish
    void     setRecovery ( bool );
    void     setStarting ( bool );
    bool       hasClient ( Client * );

  private:
    unsigned long        m_iServerIP;    // 32 bit notation instead of in_addr_t
    unsigned int         m_iServerPort;  // Defaults to Render::SERVER_PORT
    unsigned int         m_iConcurrentThreads;
    bool                 m_bRecoveryMode;
    bool                 m_bStartingServer; // After issuing the bash command through system() we should prevent other threads

    QValueList<Client *> m_listOfClients;
  };

public:
   Manager ( );
  ~Manager ( );
  static bool registerEntry   ( SourceFileEntry  * );
  static bool unregisterEntry ( SourceFileEntry  * );

  static bool registerTrans   ( ButtonTransition * );
  static bool unregisterTrans ( ButtonTransition * );

  ServerInfo  *getServerInfo  ( unsigned long      );
  ServerInfo  *getServerInfo  ( Render::Client   * );
  QStringList &getFilterNames ( );

  void lock   ( );
  void unlock ( );

  static Manager *m_pSelf; // Pointer to the sole instance of itself
  QMutex m_mutex;
  QValueList<ServerInfo *> m_listOfServer;
  QStringList              m_listFilterNames;
};

}; // End of namespace Render

#endif // RENDER_CLIENT_H
