/**
 *  GraphTFT plugin for the Video Disk Recorder 
 * 
 *  graphtft.c - A plugin for the Video Disk Recorder
 *
 *  (c) 2004-2007 Lars Tegeler, Sascha Volkenandt, 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: graphtft.c,v 1.15 2007/12/03 19:58:20 root Exp $
 *
 **/

#include <theme.h>
#include <memcpy.h>
#include <getopt.h>

#include <service.h>
#include <graphtft.h>
#include <span.h>

//***************************************************************************
// cGraphTFTMenu
//***************************************************************************
//***************************************************************************
// Object
//***************************************************************************

cGraphTFTMenu::cGraphTFTMenu(const char* title, cPluginGraphTFT* aPlugin)
{
   int i = 0;
   plugin = aPlugin;
   defMode = 0;

   char** normalModes = theTheme->getNormalSections();

   while (normalModes[i])
   {
      if (normalModes[i] == GraphTFTSetup.normalMode)
      {
         defMode = i;
         break;
      }

      i++;
   }

   Clear();

   cOsdMenu::Add(new cOsdItem(tr("Reload themes")));
   cOsdMenu::Add(new cMenuEditBoolItem(tr("Refresh Display"), &plugin->getDisplay()->displayActive));
   cOsdMenu::Add(new cMenuEditStraItem(tr("Normal Display"), 
                                       &defMode, 
                                       theTheme->getNormalSectionsCount(),
                                       normalModes));
   cOsdMenu::Add(new cOsdItem(tr("Snapshot")));

#ifdef HAVE_SOFTMPEG
   cOsdMenu::Add(new cOsdItem(tr("Picture beside Picture")));
#endif

   Display();
}

cGraphTFTMenu::~cGraphTFTMenu()
{
}

//***************************************************************************
// Process Key
//***************************************************************************

eOSState cGraphTFTMenu::ProcessKey(eKeys key)
{
   eOSState state = cOsdMenu::ProcessKey(key);

	// RefreshCurrent();

   if (state == osUnknown)
   {
       switch (key)
       {
          case kOk:
          {
             isyslog("selected (%d); defMode is (%d)", Current(), defMode);

             switch (Current())
             {
                case 0:
                   plugin->loadThemes();
                   break;

                case 1:
                   plugin->getDisplay()->displayActive = !plugin->getDisplay()->displayActive;
                   break;

                case 2:
                   GraphTFTSetup.normalMode = theTheme->getNormalSections()[defMode];
                   plugin->SetupStore("normalMode", GraphTFTSetup.normalMode.c_str());
                   break;

                case 3:
                   plugin->getDisplay()->snapshotPending = yes;
                   break;

#ifdef HAVE_SOFTMPEG
                case 4:
                   plugin->getDisplay()->Pbp();  // Start PbP
                   break;
#endif
             }

             return osEnd;
          }

          default:
             break;
       }
    }

    return state;
}

//***************************************************************************
// cPluginGraphTFT
//***************************************************************************
//***************************************************************************
// Object
//***************************************************************************

cPluginGraphTFT::cPluginGraphTFT()
{
   display = 0;
   _dev = 0;
   port = 2039;
}

cPluginGraphTFT::~cPluginGraphTFT()
{
   if (display)
      delete display;

   delete[] _dev;
}

//***************************************************************************
// Command Line Help
//***************************************************************************

const char *cPluginGraphTFT::CommandLineHelp()
{
   return "   -d DEV,  --device=DEV   sets the output-device\n"

#ifdef HAVE_IMLIB
      "                           /dev/fb0 or vdr/1 \n"
#endif
#if HAVE_DFB
      "                           directFB \n"
#endif
      "                           (default: autodetect)\n";
}

//***************************************************************************
// Process Args
//***************************************************************************

bool cPluginGraphTFT::ProcessArgs(int argc, char* argv[])
{
   int c;

   static struct option long_options[] = 
      {
         { "device", required_argument, 0, 'd' },
         { 0 }
      };

   // check the arguments

   while ((c = getopt_long(argc, argv, "d:", long_options, 0)) != -1) 
   {
      switch (c)
      {
         case 'd':                  // device 
            _dev = strdup(optarg);
            break;

         case 'p':                  // port
            port = atoi(optarg);
            break;

         default: isyslog("Graphtft: Ignoring unknown argument '%s'", optarg);
      }
   }

   return true;
}

//***************************************************************************
// Initialize
//***************************************************************************

bool cPluginGraphTFT::Initialize()
{
   return true;
}

//***************************************************************************
// Start
//***************************************************************************

bool cPluginGraphTFT::Start()
{
   // Start any background activities the plugin shall perform.

   isyslog("Device is '%s'", _dev ? _dev : "not configured, probing");

#ifdef HAVE_FAST_MEMCPY
   probe_fast_memcpy(0);
#else
   fast_memcpy = memcpy;
#endif

#ifdef HAVE_IMLIB

   if (!_dev)
   {
      for (int i = 0; i < cDevice::NumDevices(); i++) 
      {
         cDevice *d = cDevice::GetDevice(i);

         if (d &&(!d->IsPrimaryDevice()) && d->HasDecoder()) 
         {
            fprintf(stderr, "vdr: graphtft - try device: vdr/%d !\n", i);
            asprintf(&_dev, "vdr/%d", i);
            break;
         }
      }
   }

#endif

#ifdef HAVE_DFB

   if (!_dev)
   {
      fprintf(stderr, "vdr: graphtft - try directFB device!\n");
      asprintf(&_dev, "directFB");
   }       

#endif

#ifdef HAVE_IMLIB

   if (!_dev)
   {
      fprintf(stderr, "vdr: graphtft - try framebuffer device!\n");
      asprintf(&_dev,"/dev/fb0");
   }

#endif

   // try to get the config dir

   if (!ConfigDirectory())
      return false;

   // init 

   GraphTFTSetup.PluginConfPath = strdup(ConfigDirectory());

#if APIVERSNUM < 10507
   RegisterI18n(Phrases);
#endif

   display = new cGraphTFTDisplay();

   logDevice = GraphTFTSetup.LogDevice;
   logLevel = GraphTFTSetup.Level;

   // load the thems

   if (loadThemes() != 0)
      return false;

   return display->Init(_dev, ConfigDirectory(), port);
}

//***************************************************************************
// Load Themes
//***************************************************************************

int cPluginGraphTFT::loadThemes()
{
   char* buffer;
   FILE* p;

   cMutexLock lock(display->getMutex());

   // look for the themes in the config directory

   asprintf(&buffer, "find %s/graphTFT/themes -follow -type f -name '*.theme' | sort", 
            ConfigDirectory());

   p = popen(buffer, "r");

   free(buffer);

   // first forget loaded themes

   themes.Clear();

   isyslog("Loading themes");

   if (p)
   {
      char* s;
      cReadLine ReadLine;

      while ((s = ReadLine.Read(p)))
      {
         // Try to load the themes

         theTheme = new cGraphTFTTheme();
         
         if (theTheme->load(s) != 0)
         {
            delete theTheme;
            theTheme = 0;

            continue;
         }

         theTheme->check(THEMEVERSION);
         themes.Add(theTheme);
      }
   }

   pclose(p);

   // Have we found themes?

   if (!themes.Count())
   {
      isyslog("Error: graphTFT - no themes found, aborting!");
      return fail;
   }

   else
   {
      theTheme = themes.getTheme(GraphTFTSetup.Theme);

      if (!theTheme)
         theTheme = themes.Get(0);
   }

   isyslog("Loaded %d themes", themes.Count());

   display->setupChanged();
   display->themesReloaded();

   if (theTheme)
      isyslog("Activated theme '%s'", theTheme->getName().c_str());
   else
      isyslog("Cant activate theme ;)");

   return success;
}

//***************************************************************************
// Main Menu Action
//***************************************************************************

cOsdObject* cPluginGraphTFT::MainMenuAction()
{

#ifdef HAVE_SOFTMPEG
   if (getDisplay()->PbpIsRunning())
      return new cGraphTFTOsdObject(getDisplay());
#endif

   return new cGraphTFTMenu(MainMenuEntry(), this);
}

//***************************************************************************
// Setup Menu
//***************************************************************************

cMenuSetupPage* cPluginGraphTFT::SetupMenu()
{
  return new cMenuSetupGraphTFT(display);
}

//***************************************************************************
// Setup Parse
//***************************************************************************

bool cPluginGraphTFT::SetupParse(const char* Name, const char* Value)
{
  return GraphTFTSetup.SetupParse(Name, Value);
}

//***************************************************************************
// Service
//***************************************************************************

bool cPluginGraphTFT::Service(const char* id, void* data)
{
   if (strcmp(id, SPAN_CLIENT_CHECK_ID) == 0)
   {
		if (GraphTFTSetup.enableSpectrumAnalyzer && data)
			*((cSpanService::Span_Client_Check_1_0*)data)->isActive = true;

		return true;
   }

   else if (strcmp(id, GRAPHTFT_TOUCH_EVENT_ID) == 0)
   {
      cGraphTftComService::GraphTftTouchEvent* event;
      event = (cGraphTftComService::GraphTftTouchEvent*)data;

      display->mouseEvent(event->x, event->y, event->button, event->flag);

      return true;
   }

   else if (strcmp(id, GRAPHTFT_CALIBRATION_ID) == 0)
   {
      display->setCalibrate(((cGraphTftComService::GraphTftCalibration*)data)->activate);

      return true;
   }

   return false;
}

//***************************************************************************
// SVDRP Help Pages
//***************************************************************************

const char** cPluginGraphTFT::SVDRPHelpPages()
{
   static const char* HelpPages[] = 
   {
      "ACTIVE \n"
      "    Activate/Deactivate display refresh {ON|OFF}\n",
      "VIEWMODE \n"
      "    Set the normal view to the specified section\n",
      "REFRESH \n"
      "    force display refresh\n",
      0
   };

   return HelpPages;
}

//***************************************************************************
// SVDRP Command
//***************************************************************************

cString cPluginGraphTFT::SVDRPCommand(const char* Command, 
                                      const char* Option, 
                                      int& ReplyCode)
{
   if (!strcasecmp(Command, "ACTIVE")) 
   {
      if (Option && strcasecmp(Option, "ON") == 0) 
      {
         display->displayActive = yes;
         ReplyCode = 550;
         return "graphTFT display activated";
      }
      else if (Option && strcasecmp(Option, "OFF") == 0) 
      {
         display->displayActive = no;
         ReplyCode = 550;
         return "graphTFT display deactivated!";
      }
      else
      {
         ReplyCode = 901;
         return "Error: Unexpected option";
      }
   }

   else if (!strcasecmp(Command, "REFRESH"))
   {
      display->broadcast(yes);
      ReplyCode = 550;
      return "display refreshed";
   }

   else if (!strcasecmp(Command, "VIEWMODE") || !strcasecmp(Command, "NORMALVIEW"))
   {
      if (Str::isEmpty(Option))
      {
         ReplyCode = 901;
         return "Error: Missing option";
      }

      if (!theTheme->isNormalMode(Option))
      {
         ReplyCode = 901;
         return "Error: Unexpected option";
      }

      GraphTFTSetup.normalMode = Option;
      SetupStore("normalMode", Option);
      display->broadcast(yes);

      ReplyCode = 550;
      return "Normal view changed";
   }

   return 0;
}

//***************************************************************************

VDRPLUGINCREATOR(cPluginGraphTFT);
