/**
 *  GraphTFT plugin for the Video Disk Recorder 
 * 
 *  display.h - A plugin for the Video Disk Recorder
 *
 *  (c) 2004 Lars Tegeler, Sascha Volkenandt
 *  (c) 2006-2008 Jörg Wendel
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id: display.h,v 1.11 2007/12/03 19:58:20 root Exp $
 *
 **/

#ifndef __GTFT_DISPLAY_H
#define __GTFT_DISPLAY_H

//***************************************************************************
// Includes
//***************************************************************************

#include <map>
#include <string>
#include <vector>

#include <vdr/thread.h>
#include <vdr/status.h>
#include <vdr/tools.h>
#include <vdr/skins.h>

#include <common.h>
#include <comthread.h>
#include <touchthread.h>
#include <renderer.h>
#include <theme.h>
#include <transfer.h>

using std::map;
using std::string;
using std::vector;

//***************************************************************************
// Class cGraphTFTService
//***************************************************************************

class cGraphTFTService : public cThemeService
{
   public:

      enum ChannelType
      {
         ctRadio = 0,
         ctTv
      };

      enum { MaxTabs = 6 };
      
      enum CalibrationStart
      {
         csUnknown = na,
         csUpperLeft,
         csUpperRight,
         csLowerLeft,
         csLowerRight,
         csDone,
         csTest
      };

      enum DisplayMode 
      {
         ModeUnknown         = 0x00,

         ModeMask            = 0xF0,
         DisplayMask         = 0x0F,

         ModeNormal          = 0x10,
         ModeReplay          = 0x20,
         ModeMenu            = 0x30,

         NormalView          = 0x11,

         ReplayNormal        = 0x21,
         ReplayMP3           = 0x22,
         ReplayDVD           = 0x23,

         MenuDefault         = 0x31,
         MenuMain            = 0x32,
         MenuSchedule        = 0x33,
         MenuChannels        = 0x34,
         MenuTimers          = 0x35,
         MenuRecordings      = 0x36,
         MenuSetup           = 0x37,
         MenuCommands        = 0x38,
         MenuWhatsOnElse     = 0x39,
         MenuWhatsOnNow      = 0x3a,
         MenuWhatsOnNext     = 0x3b,
         MenuSetupPage       = 0x3c,

         ModeCalibration     = 0x41,
         ModeCalibrationTest = 0x42
      };

      static int isModeNormal(DisplayMode mode)       { return (mode & ModeMask) == ModeNormal; }
      static int isModeReplay(DisplayMode mode)       { return (mode & ModeMask) == ModeReplay; }
      static int isModeMenu(DisplayMode mode)         { return (mode & ModeMask) == ModeMenu; }
};

//***************************************************************************
// Class GraphTFT Display
//***************************************************************************

class cGraphTFTDisplay : public cStatus, cThread, public cGraphTFTService
{
   public:

      // object

      cGraphTFTDisplay(const char* aSyntaxVersion);
      ~cGraphTFTDisplay();

      // interface

      int Init(const char* dev, const char* cfgDir, int port);
      void setupChanged();
      void setCalibrate(int active, int state = csUnknown);
      void switchCalibrate(int state = csUnknown);
      int calibrateTouch(int x, int y);
      int setMode(DisplayMode mode, const char* menuName = 0, int force = false);
      int isMode(DisplayMode mode) { return mode == _mode; }
      void setCoverPath(const char* path) { _coverPath = Str::notNull(path); }
      void musicAddPlaylistItem(const char* item, int index = na);
      void setMusicPlayerState(cTftCS::MusicServicePlayerInfo* state);
      void setMusicPlayerHelpButtons(cTftCS::MusicServiceHelpButtons* buttons);
      cTouchThread* getTouchThread() { return touchThread; }

      // thread stuff

      bool Start()        { return cThread::Start(); }
      void Stop();
      bool Active() const { return _active; }
      cMutex* getMutex()  { return &_mutex; }

      void themesReloaded() { lastSection = 0; currentSection = 0; }

      // due to comThread destructor is called
      // by vdr, trick to inherited by cRemote

      void clearComThread()   { comThread = 0; } 
      void clearTouchThread() { touchThread = 0; } 

      // event
      
      void mouseEvent(int x, int y, int button, int flag = ComThread::efNone, int data = 0);
      cDisplayItem* getItemAt(int x, int y);
      int processAction(cDisplayItem* p, string action, int step = 1);

      // PbP stuff

      void Pbp();
      void PbpRestart();
      void PbpSwitch(bool Back);
      void PbpUpDown(bool Up);
      bool PbpIsRunning();
      void PbpStart();
      void PbpStop();
      void PbpInit();

      // display stuff

      void broadcast(int force = no);
      int display(string sectionName);
      void refresh();
      void clear();
      int updateGroup(int group);

      // Tabs

      const char* GetTabbedText(const char* s, int Tab);

      // some structures and types

      struct RecordingInfo 
      {
         string name;
         const cDevice* device;
      };

      typedef vector <RecordingInfo> RecordingInfos;
   
      struct ReplayInfo 
      {
         DisplayMode lastMode;
         string name;
         string fileName;
         cControl* control;
      };

      struct Calibration
      {
         string instruction;
         string info;
         int state;
         int cursorX;
         int cursorY;
         int lastX;
         int lastY;

         cTouchThread::CalibrationSetting settings;
      };

      struct MenuItem 
      {
         string text;
         string tabs[MaxTabs];
         int tabCount;
         int nextX;
         Ts::MenuItemType type;
         const cEvent* event;
         const cChannel* channel;
         const cRecording* recording;
      };
   
      struct MenuInfo 
      {
         DisplayMode lastMode;
         int currentRow;
         int currentRowLast;
         int visibleRows;
         int topRow;
         int lineHeight;
         int lineHeightSelected;
         string title;
         string current;
         string buttons[4];
         string text;
         // int textStartLine;
         int drawingRow;             // current drawing index
         vector<MenuItem> items;
         int charInTabs[MaxTabs+1];
      };

      struct MusicPlayerInfo
      {
         string filename;
         string artist;
         string album;
         string genre;
         string comment;
         string year;
         double frequence;
         int bitrate;
         string smode;
         bool loop;
         bool shuffle;
         bool shutdown;
         bool recording;
         int rating;
         int index;      // current index in tracklist
         int count;      // items in tracklist
         bool lyrics;
         bool copy;
         bool timer;
         string status;  // player status
         string currentTrack;
         vector<string> tracks; // tracklist (only the unplayed part!)

         // help buttons

         string red;
         string green;
         string yellow;
         string blue;

         // internals

         unsigned int iter;

         const char* nextTrack() 
         { 
            if (iter > tracks.size())
               return "";

            return tracks[iter++].c_str();
         }
      };

      // display contents

      cThemeSection* currentSection;
      cThemeSection* lastSection;
      ChannelType channelType;
      DisplayMode _mode;
      string _sectionName;

      int _eventsReady;
      bool _mute;
      int _volume;

      int _showRecording;

      int _channel;
      const cChannel* _presentChannel;
      const cEvent* _presentEvent;
      const cEvent* _followingEvent;
      string _channelText;
      const cEvent* _event;
      string _coverPath;

      string _recording;
      ReplayInfo _replay;

      string _message;
      RecordingInfos _recordings;   // the running recordings
      MenuInfo _menu;
      MusicPlayerInfo _music;       // special for Music Plugin
      Calibration calibration;
      int mouseX;
      int mouseY;
      int mouseKey;
      int touchMenu;
      uint64_t touchMenuHideAt;
      uint64_t touchMenuHideTime;

      // 

      int displayActive;
      int snapshotPending;

   protected:

      // thread

      virtual void Action();

      // helper functions

      void takeSnapshot();
      bool StoppedTimer(const char *Name);
      void UpdateProgramme();
      const cChannel* channelByName(const char* name);

      // status interface

      virtual void ChannelSwitch(const cDevice* Device, int ChannelNumber);
      virtual void OsdSetEvent(const cEvent* event);
      virtual void OsdSetRecording(const cRecording* recording);
      virtual void OsdChannel(const char* Text);
      virtual void OsdProgramme(time_t PresentTime, const char* PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle);
      virtual void SetVolume(int Volume, bool Absolute);
      virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On);
      virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On);
      virtual void OsdStatusMessage(const char *Message);
      virtual void OsdTitle(const char* Title);
      virtual void OsdItem(const char* Text, int Index);
      virtual void OsdEventItem(const cEvent* Event, const char* Text, int Index, int Count);
      virtual void OsdCurrentItem(const char *Text);
      virtual void OsdClear();
      virtual void OsdHelpKeys(const char* Red, const char* Green, const char* Yellow, const char* Blue);
      virtual void OsdTextItem(const char* Text, bool Scroll);
      virtual void OsdMenuDisplay(const char* kind);
      virtual void OsdMenuDestroy();

   private:

      // renderer

      Renderer* _render;
      int isDummyRender;
      ComThread* comThread;
      cTouchThread* touchThread;

      // thread control

      bool _active;
      cMutex _mutex;
      cCondVar _doUpdate;

      //

      int forceNextDraw;
      uint64_t nextCyclicForce;   
      int forceWriteThrough;

      // pbp stuff

      bool _pbpActive;
      cDevice* _dev;
      const cChannel* _chan;
      cGraphTFTTransfer* _transfer;
      const char* syntaxVersion;
      int versionReported;
      int startedAt;
};

//***************************************************************************
#endif // __GTFT_DISPLAY_H
