#include "menuitems.h"
#include "menu.h"
#include "diseqc.h"


// --- Width ----------------------------------------------------------------

int Width(char c)
{
  char s[2];
  s[0]=c;
  s[1]='\0';
  return Width(s);
}

int Width(const char *s)
{
  if (cSkinDisplay::Current()->EditableWidth()>100)
    return cFont::GetFont(fontOsd)->Width(s);
  else
    return s ? strlen(s) : 0;
}

// --- ThreeItems -----------------------------------------------------------

const char* ThreeItems(const char* first,const char* second, const char* third, int edw)
{
  char text[700];
  sprintf(text,"<- %s",first);
  int fw=Width(text);
  int mw=Width(second);
  for (int i=1; (i*Width(BLANK))<=((edw-mw)/2-fw);i++)
    sprintf(text,"%s%c",text,edw>100 ? BLANK : ' ');
  sprintf(text,"%s%s",text,second);
  fw=Width(third)+Width(" ->")+Width(text);
  for (int i=1; (i*Width(BLANK))<=(edw-fw);i++) 
    sprintf(text,"%s%c",text,edw>100 ? BLANK : ' '); 
  sprintf(text,"%s%s ->",text,third);
  return strdup(text);
}

// --- CenterText -----------------------------------------------------------

const char* CenterText(const char* txt, int edw)
{
  char text[700];
  int i;
  for (i=0; ((i+1)*Width(BLANK))<=(edw-Width(txt))/(2);i++)
    text[i]=edw>100 ? BLANK : ' ';
  text[i]='\0';
  sprintf(text,"%s%s",text,txt);
  return strdup(text);
}

cMenuEditEWItem::cMenuEditEWItem(const char *Name):cOsdItem(Name)
{
};

eOSState cMenuEditEWItem::ProcessKey(eKeys Key)
{
  Key = NORMALKEY(Key);
  switch (Key) {
    case kNone           : break;
    case kLeft|k_Repeat  :
    case kRight|k_Repeat : break;
    case kLeft|k_Release :
    case kRight|k_Release:
                           DiseqcCommand(Halt);
                           break;
    case kLeft           : DiseqcCommand(DriveEast);
                           Setup.UpdateChannels=0;
                           break;
    case kRight          : DiseqcCommand(DriveWest);
                           Setup.UpdateChannels=0;
                           break;
    case kOk             : DiseqcCommand(Halt);
                           break;
    default              :
                           return osUnknown;
               }
  return osContinue;
}

// --- cMenuEditStepsEWItem -------------------------------------------------

cMenuEditStepsEWItem::cMenuEditStepsEWItem()
{
  steps=1;
  edw=cSkinDisplay::Current()->EditableWidth();
  char t1[50];
  sprintf(t1,"%d %s",steps,tr("Steps"));
  SetText(ThreeItems(tr("To East"),t1,tr("To West"),edw));
}

eOSState cMenuEditStepsEWItem::ProcessKey(eKeys Key)
{
  Key = NORMALKEY(Key);
  switch (Key) {
    case kNone  : break;
    case k0...k9: if (fresh)
                  {
                    steps=0;
                    fresh=false;
                  }
                  steps= steps*10 + (Key-k0);
                  if (steps>128) steps=128;
                    char t1[50];
                  sprintf(t1,"%d %s",steps,tr("Steps"));
                  SetText(ThreeItems(tr("To East"),t1,tr("To West"),edw));
                  break;
    case kLeft  : fresh=true;
                  DiseqcCommand(DriveStepsEast,steps);
                  Setup.UpdateChannels=0;
                  break;
    case kRight : fresh=true;
                  DiseqcCommand(DriveStepsWest,steps);
                  Setup.UpdateChannels=0;
                  break;
    case kOk    : fresh=true;
                  break;
    default     : return osUnknown;
               }
  return osContinue;
}

// --- cMenuEditLimitsItem -----------------------------------------------------

cMenuEditLimitsItem::cMenuEditLimitsItem(const char *Name):cOsdItem(Name)
{
};

eOSState cMenuEditLimitsItem::ProcessKey(eKeys Key)
{
  Key = NORMALKEY(Key);
  switch (Key) {
    case kNone : break;
    case kLeft : DiseqcCommand(SetEastLimit);
                 break;
    case kRight: DiseqcCommand(SetWestLimit);
                 break;
    case kOk   : DiseqcCommand(LimitsOn);
                 break;
    default    :
                 return osUnknown;
               }
  return osContinue;
}

// --- cMenuEditFreqItem -------------------------------------------------------

cMenuEditFreqItem::cMenuEditFreqItem(const char *Name,int *Value,char *Value2, eOSState State)
{
  value = Value;
  value2= Value2;
  state=State;
  edw=cSkinDisplay::Current()->EditableWidth();
  name=strdup(Name);
  Set();
};

void cMenuEditFreqItem::Set()
{
  char text[700];
  sprintf(text,"%s:",name);
  char txt[50];
  sprintf(txt,"%d %c",*value,*value2);
  int w=Width(text);
  for (int i=1; (i*Width(BLANK))<=(edw-w-Width(txt));i++) sprintf(text,"%s%c",text,edw>100 ? BLANK : ' ');
  sprintf(text,"%s%s",text,txt);
  SetText(text);
}

eOSState cMenuEditFreqItem::ProcessKey(eKeys Key)
{
  Key = NORMALKEY(Key);
  switch (Key) {
    case kNone  : break;
    case k0...k9: if (fresh)
                  {
                    *value=0;
                    fresh=false;
                  }
                  if (*value<1300)
                  *value = *value*10 + (Key-k0);
                  Set();
                  break;
    case kLeft  : *value2='V';
                  fresh=true;
                  Set();
                  break;
    case kRight : *value2='H';
                  fresh=true;
                  Set();
                  break;
    case kOk    :
                  fresh=true;
                  return state;
                  break;
    default     :
                  return osUnknown;
               }
  return osContinue;
}

// --- cMenuEditSatItem ------------------------------------------------------

cMenuEditSatItem::cMenuEditSatItem(cRotorPos** SPos, int* p, bool& Assign)
{
  spos=SPos;
  pos=p;
  *pos=(*spos)->Pos();
  assign=&Assign;
  edw=cSkinDisplay::Current()->EditableWidth();
  Set();
}

void cMenuEditSatItem::Set()
{
  char text[700];
  sprintf(text,"%s: %d",tr("Position"),*pos);
  while (edw-Width((*spos)->Description())-Width(text)-Width(BLANK)>=0)
    sprintf(text,"%s%c",text,edw>100 ? BLANK : ' ');
  sprintf(text,"%s%s",text,(*spos)->Description());
  SetText(text);
}

eOSState cMenuEditSatItem::ProcessKey(eKeys Key)
{
  Key=NORMALKEY(Key);
  switch (Key) {
    case k0...k9: if (fresh)
                  {
                    *pos=0;
                    fresh=false;
                  }
                  *pos=*pos*10 + (Key-k0);
                  if (!*assign)
                    *spos=RotorPositions.GetfromPos(*pos);
                  Set();
                  break;
    case kLeft  : *assign=false;
                  if (RotorPositions.Prev(*spos)!=RotorPositions.First())
                    *spos=RotorPositions.Prev(*spos);
                  fresh=true;
                  if (!*assign)
                    *pos=(*spos)->GetPos();
                  Set();
                  break;
    case kRight : *assign=false;
                  if (RotorPositions.Next(*spos))
                    *spos=RotorPositions.Next(*spos);
                  fresh=true;
                  if (!*assign)
                    *pos=(*spos)->GetPos();
                  Set();
                  break;
    case kOk    : if (*assign)
                  {
                    // Now really Assign
                    *assign=false;
                    break;
                  }
                  Setup.UpdateChannels=0;
                  GotoX((*spos)->R_Code());
                  fresh=true;
                  break;
    case kBlue  : if (!*pos && !*assign)
                  { 
                    *assign=true;
                    break;
                  }
    default     : return osUnknown;
                  break;
               }
  return osContinue;
}

// --- cMenuEditSymbItem ----------------------------------------------------

cMenuEditSymbItem::cMenuEditSymbItem(const char *Name, int *Value, int Min, int Max, eOSState State):cMenuEditIntItem(Name,Value,Min,Max)
{
  edw=cSkinDisplay::Current()->EditableWidth();
  name=strdup(Name);
  state=State;
  Set();
}

void cMenuEditSymbItem::Set()
{
  char text[700];
  sprintf(text,"%s:",name);
  char txt[50];
  sprintf(txt,"%d",*value);
  int w=Width(text)+Width(txt);
  for (int i=1; (i*Width(BLANK))<=(edw-w);i++) sprintf(text,"%s%c",text,edw>100 ? BLANK : ' ');
  sprintf(text,"%s%s",text,txt);
  SetText(text);
}

eOSState cMenuEditSymbItem::ProcessKey(eKeys Key)
{
  return Key == kOk ? state : cMenuEditIntItem::ProcessKey(Key);
}

void cMenuEditIntpItem::Set(void)
{
  char buf[16];
  snprintf(buf, sizeof(buf), "%d.%d %s", *value/10, *value % 10, *value2 ? trueString : falseString);
  SetValue(buf);
}

// --- cMenuEditIntpItem ----------------------------------------------------

cMenuEditIntpItem::cMenuEditIntpItem(const char *Name, int *Value, int Min, int Max,int *Value2, const char *FalseString,const char *TrueString):cMenuEditIntItem(Name, Value, Min, Max)
{
  value = Value;
  value2= Value2;
  trueString = TrueString;
  falseString = FalseString;
  min = Min;
  max = Max;
  Set();
}

eOSState cMenuEditIntpItem::ProcessKey(eKeys Key)
{
  eOSState state = cMenuEditItem::ProcessKey(Key);
  if (state == osUnknown)
  {
    int newValue = *value;
    int newValue2= *value2;
    Key = NORMALKEY(Key);
    switch (Key) {
      case kNone  : break;
      case k0...k9:
                    if (fresh)
                    {
                      *value = 0;
                      fresh = false;
                    }
                    newValue = *value * 10 + (Key - k0);
                    break;
      case kLeft  :
                    newValue2 = 0;
                    fresh = true;
                    break;
      case kRight :
                    newValue2 = 1;
                    fresh = true;
                    break;
      default     :
                    if (*value < min) { *value = min; Set(); }
                    if (*value > max) { *value = max; Set(); }
                    return state;
                 }
    if ((!fresh || min <= newValue) && newValue <= max)
    {
      *value = newValue;
      *value2 = newValue2;
      Set();
    }
 state = osContinue;
  }
  return state;
}

// --- cMenuEditRotorConfItem ------------------------------------------------------

cMenuEditRotorConfItem::cMenuEditRotorConfItem(int *CP)
{
  sat = RotorPositions.Next(RotorPositions.First());
  cp=CP;
  *cp=1;
  Set();
}

void cMenuEditRotorConfItem::Set()
{
  char text[700];
  if (sat->Code()!=sat->R_Code() || !*cp)
    sprintf(text,"%s:\t%s",sat->Description(),sat->Code() ? *cSource::ToString(sat->Code()) : "no action");
  else
    sprintf(text,"%s:\t%d",sat->Description(),sat->Pos());
  SetText(text);
}

eOSState cMenuEditRotorConfItem::ProcessKey(eKeys Key)
{
  Key=NORMALKEY(Key);
  switch (Key) {
    case k0...k9: if (fresh || !*cp)
                  {
                    sat->SetPos(0);
                    fresh=false;
                  }
                  sat->SetPos(sat->Pos()*10 + (Key-k0));
                  sat->SetCode(sat->R_Code());
                  *cp=1;
                  Set();
                  break;
    case kLeft  : 
                  if (*cp || fresh)
                  {
                    fresh=true;
                    *cp=1;
                    if (RotorPositions.Prev(sat)!=RotorPositions.First())
                      sat=RotorPositions.Prev(sat);
                  }
                  else
                  {
                    if (!sat->Code()) break;
                    cSource *t = Sources.Get(sat->Code());
                    if (!t)
                      sat->SetCode(Sources.First()->Code());
                    else
                    {
                      t=Sources.Prev(t);
                      if (!t)
                        sat->SetCode(0);
                      if (t && (t->Code() & 0xC000) == 0x8000)
                        sat->SetCode(t->Code());
                    }
                  }
                  Set();
                  break;
    case kRight :  
                  if (*cp || fresh)
                  {
                    fresh=true;
                    *cp=1;
                    if (RotorPositions.Next(sat))
                      sat=RotorPositions.Next(sat);
                  }
                  else
                  {
                    cSource *t=sat->Code() ? Sources.Get(sat->Code()) : NULL;
                    if (!t)
                      sat->SetCode(Sources.First()->Code());
                    else 
                    {
                      t=Sources.Next(t);
                      if (t && (t->Code() & 0xC000) == 0x8000)
                        sat->SetCode(t->Code());
                    }
                  }
                  Set();
                  break;
    case kRed   : 
                  if (!*cp)
                    sat->SetCode(sat->R_Code());
                  *cp=!*cp;
                  fresh=*cp;
                  Set();
                  break;
    case kOk    : if (!*cp)
                  {
                    *cp=1;  
                    break;
                  }
    default     : return osUnknown;
                  break;
               }
  return osContinue;
}

