/*
 * menu.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */

#include <vdr/status.h>
#include <vdr/remote.h>
#include "i18n.h"
#include "menu.h"

// --- cManualMenu -------------------------------------------------------------

cManualMenu::cManualMenu(cManualFileInfo *Fi, const char *Xpath)
:cOsdMenu("")
{
  fi = Fi;
  xpath = NULL;
  SetXpath(Xpath);
  for (int i = 0; i < ManualFiles.Count(); i++)
  {
    if (!strcmp(ManualFiles.Get(i)->FileName(), fi->FileName()))
    {
      ManualFiles.Get(i)->decUsedBy();
      dsyslog("manual: constructor cManualMenu, count = %d", ManualFiles.Get(i)->getUsedBy());
    }
  }
  SetMenu();
}

cManualMenu::~cManualMenu(void)
{
  free(xpath);
  for (int i = 0; i < ManualFiles.Count(); i++)
  {
    if (!strcmp(ManualFiles.Get(i)->FileName(), fi->FileName()))
    {
      ManualFiles.Get(i)->incUsedBy();
      if (ManualFiles.Get(i)->getUsedBy() == 0)
      {
        dsyslog("manual: destructor cManualMenu, count = %d", ManualFiles.Get(i)->getUsedBy());
        ManualFiles.Del(ManualFiles.Get(i));
      }
    }
  }
}

void cManualMenu::SetXpath(const char *Xpath)
{
  free(xpath);
  xpath = strdup(Xpath);
}

void cManualMenu::SetMenu(void)
{
  char buffer[64];
  char *xpath_buffer = NULL;
  char *str = NULL;
  xmlXPathObjectPtr result;

  asprintf(&xpath_buffer,"%s/parent::*/name",xpath);
  result = fi->GetNodeset((xmlChar *)xpath_buffer);
  free(xpath_buffer);
  if (result)
  {
    str = fi->GetString(result->nodesetval->nodeTab[0]->xmlChildrenNode);
    snprintf(buffer, sizeof(buffer), "%s", str);
    free(str);
  }
  else
    snprintf(buffer, sizeof(buffer), "%s: %s",tr("Manual"), fi->FileName());
  SetTitle(buffer);
  SetHasHotkeys();
  asprintf(&xpath_buffer,"%s/chapter/name",xpath);
  result = fi->GetNodeset((xmlChar *)xpath_buffer);
  free(xpath_buffer);
  if (result)
  {
    for (int i = 0;i < result->nodesetval->nodeNr;i++)
    {
      str = fi->GetString(result->nodesetval->nodeTab[i]->xmlChildrenNode);
      Add(new cOsdItem(hk(str)));
      free(str);
    }
  }
  else
  {
    Skins.Message(mtError, tr("Error reading manual!"));
    cRemote::Put(kBack, true);
  }
}

eOSState cManualMenu::ProcessKey(eKeys Key)
{
  char *xpath_buffer = NULL;
  cOsdMenu *menu;
  eOSState state = cOsdMenu::ProcessKey(Key);

  if (state == osUnknown)
  {
    switch (Key)
    {
      case kOk:
        free(xpath_buffer);
        asprintf(&xpath_buffer,"%s/chapter[%d]",xpath,(Current() + 1));
        menu = SetManualOsd(fi, xpath_buffer);
        free(xpath_buffer);
        if(menu)
          return AddSubMenu(menu);
        state = osContinue;
        break;
      default:
        break;
    }
  }
  return state;
}

// --- cManualText -------------------------------------------------------------

cManualText::cManualText(cManualFileInfo *Fi, const char *Xpath)
:cOsdMenu("")
{
  fi = Fi;
  text = NULL;
  xpath = NULL;
  SetXpath(Xpath);
  for (int i = 0; i < ManualFiles.Count(); i++)
  {
    if (!strcmp(ManualFiles.Get(i)->FileName(), fi->FileName()))
    {
      ManualFiles.Get(i)->decUsedBy();
      dsyslog("manual: constructor cManualMenu, count = %d", ManualFiles.Get(i)->getUsedBy());
    }
  }
  SetText();
}

cManualText::~cManualText()
{
  free(text);
  free(xpath);
  for (int i = 0; i < ManualFiles.Count(); i++)
  {
    if (!strcmp(ManualFiles.Get(i)->FileName(), fi->FileName()))
    {
      ManualFiles.Get(i)->incUsedBy();
      if (ManualFiles.Get(i)->getUsedBy() == 0)
      {
        dsyslog("manual: destructor cManualMenu, count = %d", ManualFiles.Get(i)->getUsedBy());
        ManualFiles.Del(ManualFiles.Get(i));
      }
    }
  }
}

void cManualText::SetXpath(const char *Xpath)
{
  free(xpath);
  xpath = strdup(Xpath);
}

void cManualText::SetText(void)
{
  char buffer[64];
  char *xpath_buffer = NULL;
  char *str = NULL;
  xmlXPathObjectPtr result;

  asprintf(&xpath_buffer,"%s/parent::*/name",xpath);
  result = fi->GetNodeset((xmlChar *)xpath_buffer);
  free(xpath_buffer);
  if (result)
  {
    str = fi->GetString(result->nodesetval->nodeTab[0]->xmlChildrenNode);
    snprintf(buffer, sizeof(buffer), "%s", str);
    free(str);
  }
  else
    snprintf(buffer, sizeof(buffer), "%s: %s",tr("Manual"), fi->FileName());
  SetTitle(buffer);
  result = fi->GetNodeset((xmlChar *)xpath);
  free(text);
  text = fi->GetString(result->nodesetval->nodeTab[0]->xmlChildrenNode);
}

void cManualText::Display(void)
{
  cOsdMenu::Display();
  DisplayMenu()->SetText(text, true);
  cStatus::MsgOsdTextItem(text);
}

eOSState cManualText::ProcessKey(eKeys Key)
{
  switch (Key)
  {
    case kUp|k_Repeat:
    case kUp:
    case kDown|k_Repeat:
    case kDown:
    case kLeft|k_Repeat:
    case kLeft:
    case kRight|k_Repeat:
    case kRight:
                  DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
                  cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp);
                  return osContinue;
    default: break;
  }

  eOSState state = cOsdMenu::ProcessKey(Key);

  if (state == osUnknown)
  {
     switch (Key)
     {
       case kOk: return osBack;
       default:  state = osContinue;
     }
  }
  return state;
}

//---SetManualOsd---------------------------------------------------------------------

cOsdMenu *SetManualOsd(cManualFileInfo *Fi, const char *XPath)
{
  char *xpath_buffer = NULL;
  xmlXPathObjectPtr result;
  char * xpath = NULL;

  asprintf(&xpath_buffer,"%s/child::*",XPath);
  result = Fi->GetNodeset((xmlChar *)xpath_buffer);
  free(xpath_buffer);
  if(result)
  {
    for(int i = 0; i < result->nodesetval->nodeNr;i++)
    {
      if (!xmlStrcmp(result->nodesetval->nodeTab[i]->name, (const xmlChar *) "file"))
      {
        char * name = NULL;
        char * ref = NULL;
        asprintf(&xpath,"%s/file",XPath);
        asprintf(&xpath_buffer,"%s/name",xpath);
        result = Fi->GetNodeset((xmlChar *)xpath_buffer);
        free(xpath_buffer);
        if(result)
        {
          name = Fi->GetString(result->nodesetval->nodeTab[0]->xmlChildrenNode);
	  dsyslog("manual: name = %s", name);
          asprintf(&xpath_buffer,"%s/ref",xpath);
          result = Fi->GetNodeset((xmlChar *)xpath_buffer);
          free(xpath_buffer);
          if(result)
          {
            asprintf(&ref,"descendant::*[normalize-space(@ref)='%s']/parent::*",Fi->GetString(result->nodesetval->nodeTab[0]->xmlChildrenNode));
	    dsyslog("manual: ref = %s", ref);
          }
          else
          {
            esyslog("manual: No ref!");
            Skins.Message(mtError, tr("Error reading manual!"));
            return NULL;
          }
          for (int j = 0; j < ManualFiles.Count(); j++)
          {
            if (!strcmp(ManualFiles.Get(j)->FileName(), name))
            {
              if(ref)
                asprintf(&xpath_buffer,"%s/%s",ManualFiles.Get(j)->LangXPath(),ref);
              return SetManualOsd(ManualFiles.Get(j),xpath_buffer);
            }
          }      
          cManualFileInfo *newfi = new cManualFileInfo(name);
          if(newfi->Init())
          {
            ManualFiles.Add(newfi);
            if(ref)
              asprintf(&xpath_buffer,"%s/%s",newfi->LangXPath(),ref);
            return SetManualOsd(newfi,xpath_buffer);
          }
          else
          {
            Skins.Message(mtError, tr("Error reading manual!"));
            return NULL;
          }
        }
        else
        {
          esyslog("manual: No filename!");
          Skins.Message(mtError, tr("Error reading manual!"));
          return NULL;
        }
      }
      else if (!xmlStrcmp(result->nodesetval->nodeTab[i]->name, (const xmlChar *) "menu"))
      {
        asprintf(&xpath_buffer,"%s/menu",XPath);
        return new cManualMenu(Fi, xpath_buffer);
      }
      else if (!xmlStrcmp(result->nodesetval->nodeTab[i]->name, (const xmlChar *) "text"))
      {
        asprintf(&xpath_buffer,"%s/text",XPath);
        return new cManualText(Fi, xpath_buffer);
      }
    }
  }
  esyslog("manual: Set failed");
  Skins.Message(mtError, tr("Error reading manual!"));
  return NULL;
}
