/*
 * statusandquestion: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id: menumessages.c 0.2 2004/07/13 19:48:34 hflor Exp $
 */

#include "statusandquestion.h"
#include "i18n.h"
#include "vdrtools.h"
#include "messages.h"
#include "menumessages.h"
#include <vdr/osd.h>
#include <vdr/interface.h>
#if VDRVERSNUM >= 10307
  #include <vdr/font.h>
#endif

// --- cMenuEditDictionary --------------------------------------------------------

cMenuEditMessage::cMenuEditMessage(cMessage *Message, int MessageNumber, int MessageCount)
:cOsdMenu(tr("Disp$display message"), 22, 5, 6)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuEditMessage::cMenuEditMessage message=%s ID=%d Number=%d Count=%d", plugin_name, Message ? Message->Text() : "(null)", Message ? Message->ID() : -1, MessageNumber, MessageCount);
#endif
  message = Message;
#if VDRVERSNUM >= 10307
  textwrapper = NULL;
#else
  menutextitem = NULL;
#endif
  prevexists = MessageNumber > 1;
  nextexists = MessageNumber < MessageCount;
  messagenumber = MessageNumber;
  messagecount = MessageCount;
#if VDRVERSNUM >= 10307
  Set(DisplayMenu()->EditableWidth());
#else
  Set();
#endif
  SetHelpKeys();
}

cMenuEditMessage::~cMenuEditMessage()
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuEditMessage::~cMenuEditMessage message=%s ID=%d", plugin_name, message ? message->Text() : "(null)", message ? message->ID() : -1);
#endif
#if VDRVERSNUM >= 10307
  if (textwrapper)
    DELETENULL(textwrapper);
#endif
}

void cMenuEditMessage::SetHelpKeys(void)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuEditMessage::SetHelpKeys", plugin_name);
#endif
  SetHelp(prevexists ? "<<" : NULL, tr("Help$all Delete"), tr("Delete"), nextexists ? ">>" : NULL);
}

void cMenuEditMessage::Set(int Width)
{

#if VDRVERSNUM >= 10307
  cOsdItem *item;
  #define DisplayLine(V) item = new cOsdItem(buffer); item->SetSelectable(V); Add(item); free(buffer)
#else
  #define DisplayLine(V) Add(new cOsdItem(buffer)); free(buffer)
#endif

#ifdef SAQ_Debug
  dsyslog("%s: cMenuEditMessage::Set Current=%d", plugin_name, Current());
#endif
  Clear();
  char *buffer = NULL;
  if (message)
  {
    struct tm tm_r;
    asprintf(&buffer, "%s\t%d/%d\t\tID=%d", tr("Disp$Message"), messagenumber, messagecount, message->ID());
    DisplayLine(false);
    asprintf(&buffer, "%s\t%s", tr("Disp$Messagetyp"), MessageTypName(message->MessageTyp()));
    DisplayLine(false);
    time_t rt = message->ReceiveTime();
    localtime_r(&rt, &tm_r);
    asprintf(&buffer, "%s\t%s\t%02d.%02d\t%02d:%02d:%02d", tr("Disp$time of receiving"), WeekDayName(tm_r.tm_wday), tm_r.tm_mday, tm_r.tm_mon + 1, tm_r.tm_hour, tm_r.tm_min, tm_r.tm_sec);
    DisplayLine(false);
    if (message->ResponseTime())
    {
      rt = message->ResponseTime();
      localtime_r(&rt, &tm_r);
      asprintf(&buffer, "%s\t%s\t%02d.%02d\t%02d:%02d:%02d", tr("Disp$time of resonse"), WeekDayName(tm_r.tm_wday), tm_r.tm_mday, tm_r.tm_mon + 1, tm_r.tm_hour, tm_r.tm_min, tm_r.tm_sec);
      DisplayLine(false);
      asprintf(&buffer, "%s\t%d (%s)", tr("Disp$Keycode (Key)"), message->Key(), KeyName(message->Key()));
    } else
      asprintf(&buffer, "%s", tr("Disp$response not available"));
      DisplayLine(false);

#if VDRVERSNUM >= 10307
    asprintf(&buffer, " ");
    DisplayLine(true);
    splitline = item;
    SetCurrent(splitline);
    textwrapper = new cTextWrapper(message->Text(), cFont::GetFont(fontOsd), Width);
    firstline = 0;
    numlines = DisplayMenu()->MaxItems() - Count();
    if (numlines > 49)
      numlines = 49;
    textlines = textwrapper->Lines();
    if (numlines > textlines)
      numlines = textlines;
    for (int i = 0; i < numlines; i++)
    {
      asprintf(&buffer, "%s", textwrapper->GetLine(i));
      DisplayLine(false);
      scrollitems[i] = item;
    }
    if (numlines < textwrapper->Lines())
    {
      asprintf(&buffer, "\t%s%d - %d / %d%s", firstline ? "< " : "", firstline + 1, firstline + numlines, textlines, firstline + numlines < textlines ? " >" : "");
      splitline->SetText(buffer);
      free(buffer);
    }
#else
    lastline = Setup.OSDheight - Count() - 5;
    menutextitem = new cMenuTextItem(message->Text(), 1, Count() + 3, Setup.OSDwidth - 2, lastline);
    Add(menutextitem);
    SetCurrent(menutextitem);
#endif
  } else
  {
    asprintf(&buffer, "%s", tr("Disp$no data available"));
    DisplayLine(true);
  }

#undef DisplayLine
}

eOSState cMenuEditMessage::ProcessKey(eKeys Key)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuEditMessage::ProcessKey Key=%s", plugin_name, KeyName(Key));
#endif

  eOSState state = osUnknown;

#if VDRVERSNUM >= 10307
  int m_firstline = firstline;
  switch (NORMALKEY(Key))
  {
    case kUp:    firstline--;
                 break;
    case kDown:  firstline++;
                 break;
    case kLeft:  firstline -= (numlines - 1);
                 break;
    case kRight: firstline += (numlines - 1);
                 break;
    default:     state = cOsdMenu::ProcessKey(Key);
                 break;
  }
  if (firstline < 0)
    firstline = 0;
  if (firstline + numlines > textlines)
    firstline = textlines - numlines;
  if (m_firstline != firstline)
  {
    for (int i = 0; i < numlines; i++)
      scrollitems[i]->SetText(textwrapper->GetLine(i + firstline));
    if (numlines < textwrapper->Lines())
    {
      char *buffer = NULL;
      asprintf(&buffer, "\t%s%d - %d / %d%s", firstline ? "< " : "", firstline + 1, firstline + numlines, textlines, firstline + numlines < textlines ? " >" : "");
      splitline->SetText(buffer);
      free(buffer);
    }
    Display();
    state = osContinue;
  }
#else
  state = cOsdMenu::ProcessKey(Key);
  if (state == osContinue)
  {
    Interface->ClearEol(1, lastline);
    menutextitem->Display();
  }
#endif
#ifdef SAQ_Debug
  dsyslog("%s: cMenuEditMessage::ProcessKey OSState=%s", plugin_name, OSStateName(state));
#endif
  if (state == osUnknown)
    switch (NORMALKEY(Key))
    {
      case kOk:     state = osBack;
                    break;
      case kRed:    if (prevexists)
                      state = osUser1;
                    break;
      case kGreen:  state = osUser2;
                    break;
      case kYellow: state = osUser3;
                    break;
      case kBlue:   if (nextexists)
                      state = osUser4;
                    break;
      default:      break;
    }

#ifdef SAQ_Debug
  dsyslog("%s: cMenuEditMessage::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
#endif
  return state;
}

// --- cMenuMessageItem --------------------------------------------------------

cMenuMessageItem::cMenuMessageItem(cMessage *Message)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessageItem::cMenuMessageItem message=%s ID=%d", plugin_name, Message ? Message->Text() : "(null)", Message ? Message->ID() : -1);
#endif
  message = Message;
  Set();
}

bool cMenuMessageItem::operator< (const cListObject &ListObject)
{
  return sortdirection.u ? message->ReceiveTime() < ((cMenuMessageItem *)&ListObject)->message->ReceiveTime() : message->ReceiveTime() > ((cMenuMessageItem *)&ListObject)->message->ReceiveTime();
}

void cMenuMessageItem::Set(void)
{
  char *buffer = NULL;
  struct tm tm_r;
  time_t rt = message->ReceiveTime();
  localtime_r(&rt, &tm_r);
  asprintf(&buffer, "%c\t%02d:%02d\t%s\t%s", 
           Messages.SearchMessage(message->MessageData()) ? 'M' : Responses.SearchMessage(message->MessageData()) ? 'R' : ' ',
           tm_r.tm_hour, tm_r.tm_min,
           MessageTypNameShort(message->MessageTyp()),
           message->Textorg());
  SetText(buffer, false);
#ifdef SAQ_Debug
  dsyslog("%s: cMenuDictionaryItem::Set SetText=%s", plugin_name, buffer);
#endif
}

// --- cMenuMessages -----------------------------------------------------------

cMenuMessages::cMenuMessages(void)
:cOsdMenu(tr("Disp$Messages"), 2, 6, 3)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::cMenuMessages", plugin_name);
#endif

  lockmessages = false;
  lockmresponses = false;
  lockmhistory = false;

  if ((lockmessages = Messages.SetLock(true, true)))
    if ((lockmresponses = Responses.SetLock(true, true)))
      if ((lockmhistory = History.SetLock(true, true)))
      {
        controlstate = ControlState_DisplayMessages;
        cMessage *message = History.First();
        while (message) {
          Add(new cMenuMessageItem(message));
          message = History.Next(message);
        }
        Sort();
        if (Count())
          SetCurrent(Get(0));
        AddDelete();
        SetHelpKeys();
      }
      else
        ERROR(tr("Error$queuelock failed (512)"));
    else
      ERROR(tr("Error$queuelock failed (511)"));
  else
    ERROR(tr("Error$queuelock failed (510)"));
}

cMenuMessages::~cMenuMessages()
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::~cMenuMessages", plugin_name);
#endif
  if (lockmessages)
    Messages.SetLock(false);
  if (lockmresponses)
    Responses.SetLock(false);
  if (lockmhistory)
    History.SetLock(false);
  controlstate = ControlState_Normal;
}

void cMenuMessages::SetHelpKeys(void)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::SetHelpKeys", plugin_name);
#endif
  if (Count())
    if (CurrentMessage())
      SetHelp(tr("Help$Display"), tr("Help$all Delete"), tr("Delete"), NULL);
    else
      SetHelp(NULL, tr("Help$all Delete"), NULL, NULL);  
  else
    SetHelp(NULL, NULL, NULL, NULL);
}

void cMenuMessages::AddDelete(void)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::AddDelete Count=%d Current=%d", plugin_name, Count(), Current());
#endif
  deleteTop = false;
  deleteBottom = false;
  if (Count()) {
    if (delete_b_e.u & 0x1)
    {
      deleteTop = true;
      Ins(new cOsdItem(tr("Disp$Delete all messages ..."), osUser2));
    }
    if ((delete_b_e.u & 0x2) && (!deleteTop || Count() >= num_entrys.u)) {
      Add(new cOsdItem(tr("Disp$Delete all messages ..."), osUser2));
      deleteBottom = true;
    }
  }
}

void cMenuMessages::DelDelete(void)
{
#ifdef ATE_Debug
  dsyslog("%s: cMenuMessages::DelDelete deleteTop=%s deleteBottom=%s", plugin_name, deleteTop ? "true" : "false", deleteBottom ? "true" : "false");
#endif
  if (deleteTop)
    Del(0);
  if (deleteBottom)
    Del(Count() - 1);
  deleteTop = deleteBottom = false;
}

eOSState cMenuMessages::Disp(void)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::Disp", plugin_name);
#endif
  if (HasSubMenu() || !CurrentMessage())
    return osContinue;
  return AddSubMenu(new cMenuEditMessage(CurrentMessage(), Current() + (deleteTop ? 0 : 1), Count() - (deleteTop ? 1 : 0) - (deleteBottom ? 1 : 0)));
}

eOSState cMenuMessages::Delete(void)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::Delete", plugin_name);
#endif
  cMessage *message = CurrentMessage();
  if (message)
  {
    cMessage *smessage = Messages.SearchMessage(message->MessageData());
    if (smessage)
      Messages.Del(smessage);
    smessage = Responses.SearchMessage(message->MessageData());
    if (smessage)
      Responses.Del(smessage);
    History.Del(message);
    cOsdMenu::Del(Current());
    if (deleteTop && deleteBottom && (Count() == num_entrys.u + 1)) {
      Del(Count() - 1);
      deleteBottom = false;
    }
    if (!History.Count())
      DelDelete();
    Display();
  }
  return osContinue;
}

cMessage *cMenuMessages::CurrentMessage(void)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::CurrentMessage", plugin_name);
#endif
  if (Count())
  {
    if ((Current() > 0 || !deleteTop) && (Current() < Count() - 1 || !deleteBottom))
    {
      cMenuMessageItem *item = (cMenuMessageItem *)Get(Current());
      return item ? item->Message() : NULL;
    } else
      return NULL;
  } else
    return NULL;
}

eOSState cMenuMessages::ProcessKey(eKeys Key)
{
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::ProcessKey Key=%s", plugin_name, KeyName(Key));
#endif

  eOSState state = cOsdMenu::ProcessKey(Key);
#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::ProcessKey OSState=%s", plugin_name, OSStateName(state));
#endif

  int n;
  if (state == osUnknown)
    switch (NORMALKEY(Key))
    {
      case k0...k9: n = (Key == k0) ? 10 : (NORMALKEY(Key) - k0);
                    if (n > Count())
                      break;
                    SetCurrent(Get(--n));
                    // no break!
      case kOk:
      case kRed:    state = Disp();   break;
      case kGreen:  state = osUser2;  break; // delete all
      case kYellow: state = Delete(); break;
      default: break;
    }
  switch (state)
  {
    case osUser1: if (Current() > deleteTop ? 1 : 0)
                  {
                    state = cOsdMenu::ProcessKey(kBack);
                    SetCurrent(Prev(Get(Current())));
                    Disp();
                  }
                  break;
    case osUser2: state = cOsdMenu::ProcessKey(kBack);
                  Display();
                  if (Interface->Confirm(tr("Disp$Delete all messages?")))
                  {
                    DelDelete();
                    Messages.Clear();
                    Responses.Clear();
                    History.Clear();
                    Display();
                    state = osBack;
                  } else
                    state = osContinue;
                  break;
    case osUser3: state = cOsdMenu::ProcessKey(kBack);
                  state = Delete();
                  break;
    case osUser4: if (Current() < Count() - deleteBottom ? 2 : 1)
                  {
                    state = cOsdMenu::ProcessKey(kBack);
                    SetCurrent(Next(Get(Current())));
                    Disp();
                  }
                  break;
    default:      break;
  }

  if (!HasSubMenu() && Key != kNone)
    SetHelpKeys();

#ifdef SAQ_Debug
  dsyslog("%s: cMenuMessages::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
#endif
  return state;
}
