/*
 * menuitems.c: Implementation of the menu helper classes
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */
#include <vdr/tools.h>
#include "config.h"
#include "genrereader.h"
#include "subgenrereader.h"
#include "mediareader.h"
#include "mediatypereader.h"
#include "castreader.h"
#include "cmtreader.h"
#include "menuitems.h"
#include "tools.h"

// -- IntStack ----------------------------------------------------------------
IntStack::IntStack(int size)
: sc(0)	
{_
  stack = (int *)malloc(int(((size*sizeof(int))+64)/64)*64);	
}

IntStack::~IntStack()
{_
  if(stack) free(stack);	
  SLDEBUG("# destructor of IntStack");
}

void    IntStack::Push(int v)
{_
  stack[++sc] = v;	
}

int     IntStack::Peek()
{_
  return stack[sc];	
}

int     IntStack::Pop()
{_
  if(sc > 0) 
	  return stack[sc--];	
  return 0;
}

// -- cMenuData ---------------------------------------------------------------
cMenuData::cMenuData(cMenuData::XmsParts top)
: xmsParts(20)	
, genre(0)
, subgenre(0)	
, sGenre(0)
, sSubgenre(0)	
{_
  xmsParts.Push(top);	
  sCategory = strdup(XmsSetup.DefaultType);	
  memset(scratch, 0, sizeof(scratch));
}

cMenuData::~cMenuData()
{_
  if(sCategory) free(sCategory);
  if(sGenre) free(sGenre);
  if(sSubgenre) free(sSubgenre);  
  SLDEBUG("# destructor of cMenuData");
}

cMenuData::XmsParts cMenuData::Active() 
{_
  return (cMenuData::XmsParts)xmsParts.Peek();	
}

cMenuData::XmsParts cMenuData::Up()
{_
  return (cMenuData::XmsParts)xmsParts.Pop();
}  

void cMenuData::SetActive(cMenuData::XmsParts what)
{_
  xmsParts.Push(what);	
}

void cMenuData::SetStrGenre(char *s)
{_
  if(sGenre) free(sGenre);
  if(s) sGenre = strdup(s);  
}

void cMenuData::SetStrSubgenre(char *s)
{_
  if(sSubgenre) free(sSubgenre);
  if(s) sSubgenre = strdup(s);  
}

void cMenuData::SetStrCategory(char *s)
{_
  if(sCategory) free(sCategory);
  if(s) sCategory = strdup(s);  
}

void cMenuData::SetStrTitle(char *s)
{_
  if(sTitle) free(sTitle);
  if(s) sTitle = strdup(s);
}  

#define  CASEDUMP(s,k)  case k: SLDEBUG(#k##"\t"##s,k); break

void cMenuData::DumpKey(eKeys Key)
{
  if(Key != kNone) {_
	  if(ISRAWKEY(Key)) SLDEBUG("key is raw");
	  if(ISMODELESSKEY(Key)) SLDEBUG("key is modeless");
	  SLDEBUG("Basic-Key: %d 0x%X", BASICKEY(Key), BASICKEY(Key));
	  SLDEBUG("KbdKey: %d 0x%X", KBDKEY(Key), KBDKEY(Key));
	  SLDEBUG("KeyKbd: %d 0x%X", KEYKBD(Key), KEYKBD(Key));
//	  switch(Key) {
//		  CASEDUMP("eKey - code: %d", kUp);
//		  CASEDUMP("eKey - code: %d", kDown);
//		  CASEDUMP("eKey - code: %d", kMenu);
//		  CASEDUMP("eKey - code: %d", kOk);
//		  CASEDUMP("eKey - code: %d", kBack);
//		  CASEDUMP("eKey - code: %d", kLeft);
//		  CASEDUMP("eKey - code: %d", kRight);
//		  CASEDUMP("eKey - code: %d", kRed);
//		  CASEDUMP("eKey - code: %d", kGreen);
//		  CASEDUMP("eKey - code: %d", kYellow);
//		  CASEDUMP("eKey - code: %d", kBlue);
//		  CASEDUMP("eKey - code: %d", k0);
//		  CASEDUMP("eKey - code: %d", k1);
//		  CASEDUMP("eKey - code: %d", k2);
//		  CASEDUMP("eKey - code: %d", k3);
//		  CASEDUMP("eKey - code: %d", k4);
//		  CASEDUMP("eKey - code: %d", k5);
//		  CASEDUMP("eKey - code: %d", k6);
//		  CASEDUMP("eKey - code: %d", k7);
//		  CASEDUMP("eKey - code: %d", k8);
//		  CASEDUMP("eKey - code: %d", k9);
//		  CASEDUMP("eKey - code: %d", kPlay);
//		  CASEDUMP("eKey - code: %d", kPause);
//		  CASEDUMP("eKey - code: %d", kStop);
//		  CASEDUMP("eKey - code: %d", kRecord);
//		  CASEDUMP("eKey - code: %d", kFastFwd);
//		  CASEDUMP("eKey - code: %d", kFastRew);
//		  CASEDUMP("eKey - code: %d", kPower);
//		  CASEDUMP("eKey - code: %d", kChanUp);
//		  CASEDUMP("eKey - code: %d", kChanDn);
//		  CASEDUMP("eKey - code: %d", kVolUp);
//		  CASEDUMP("eKey - code: %d", kVolDn);
//		  CASEDUMP("eKey - code: %d", kMute);
//		  CASEDUMP("eKey - code: %d", kAudio);
//		  CASEDUMP("eKey - code: %d", kSchedule);
//		  CASEDUMP("eKey - code: %d", kChannels);
//		  CASEDUMP("eKey - code: %d", kTimers);
//		  CASEDUMP("eKey - code: %d", kRecordings);
//		  CASEDUMP("eKey - code: %d", kSetup);
//		  CASEDUMP("eKey - code: %d", kCommands);
//		  CASEDUMP("eKey - code: %d", kUser1);
//		  CASEDUMP("eKey - code: %d", kUser2);
//		  CASEDUMP("eKey - code: %d", kUser3);
//		  CASEDUMP("eKey - code: %d", kUser4);
//		  CASEDUMP("eKey - code: %d", kUser5);
//		  CASEDUMP("eKey - code: %d", kUser6);
//		  CASEDUMP("eKey - code: %d", kUser7);
//		  CASEDUMP("eKey - code: %d", kUser8);
//		  CASEDUMP("eKey - code: %d", kUser9);
//		  CASEDUMP("eKey - code: %d", kKbd);
//		  CASEDUMP("eKey - code: %d", k_Plugin);
//		  CASEDUMP("eKey - code: %d", k_Setup);
//		  default:;
//		  }
	  }
}

// -- cOsdGenreList -----------------------------------------------------------
cOsdGenreList::cOsdGenreList(cMenuData & md) 
: cOsdMenu("", 45)
, menu(md)
{_
  char * tmp;
  asprintf(&tmp, tr("select genre for mediatype: %s"), menu.StrCategory());
  SetTitle(tmp);
  menu.SetActive(cMenuData::xmsGenre);
  cGenreReader reader = cGenreReader(menu.StrCategory());
  cMenuGenreItem * pI = 0;

  while((pI = reader.Read()) != NULL) {
     SLDEBUG("try to add entry %s", pI->Name());	
     Add(pI);
     }
  SetHelp();
}

cOsdGenreList::~cOsdGenreList()
{_
	SLDEBUG("# destructor of cOsdGenreList");
	menu.Up();
}

eOSState cOsdGenreList::ProcessKey(eKeys Key)
{
  eOSState state = cOsdMenu::ProcessKey(Key);
  if(Key != kNone) {_
	  if(menu.Active() == cMenuData::xmsGenre) {
	     menu.DumpKey(Key);
		  if(state == osUnknown) {
			  switch(Key) {
				  case kRed: AddSubMenu(new cOsdCategoryList(menu)); break;
				  case kGreen: AddSubMenu(new cOsdSearch(menu)); break;
				  case kOk:
				  case kYellow: {
					  cMenuGenreItem * pI = (cMenuGenreItem *)Get(Current());				  

					  if(pI) {
						  menu.SetGenre(pI->Id());
						  menu.SetStrGenre(pI->Name());
						  AddSubMenu(new cOsdSubGenreList(menu));
						  }
					  } break;				 
				  case kBlue: {
					  cMenuGenreItem * pI = (cMenuGenreItem *)Get(Current());				  

					  if(pI) {
						  menu.SetGenre(pI->Id());
						  menu.SetStrGenre(pI->Name());
						  AddSubMenu(new cOsdMediaList(menu, pI->Id()));
						  }
					  } break;
				  default:;
				  }
			  }
		  else if(state == osBack || state == osContinue) {
			  if(Key == kYellow) {
				  AddSubMenu(new cOsdMediaList(menu, "title", menu.scratch));
				  }
			  else if(Key == kGreen) {
				  AddSubMenu(new cOsdMediaList(menu, "cast", menu.scratch));
				  }
			  }
		  }
     }
  return state;
}

void cOsdGenreList::SetHelp()
{_
                  	// red,              green,        yellow,                blue
  cOsdMenu::SetHelp(tr("media-type"), tr("search"), tr("select subgenre"), tr("list media"));
}

// -- cOsdSubGenreList --------------------------------------------------------
cOsdSubGenreList::cOsdSubGenreList(cMenuData &rd) 
: cOsdMenu("", 45)
, menu(rd)	
{_
  menu.SetActive(cMenuData::xmsSubGenre);	
  char * tmp;

  asprintf(&tmp, tr("SubGenreSelect: %s"), menu.StrGenre());  
  SetTitle(tmp);
  cSubGenreReader reader = cSubGenreReader(menu.Genre());
  cMenuSubGenreItem * pI = 0;
  while((pI = reader.Read()) != NULL) {
     SLDEBUG("cOsdSubGenreList::cOsdSubGenreList(): try to add entry %s", pI->Name());	
     Add(pI);
     }
  SetHelp();
}

cOsdSubGenreList::~cOsdSubGenreList()
{_
	SLDEBUG("# destructor of cOsdSubGenreList");
	menu.Up();
}

eOSState cOsdSubGenreList::ProcessKey(eKeys Key)
{
  eOSState state = cOsdMenu::ProcessKey(Key);
  if(Key != kNone) {_
	  menu.DumpKey(Key);
	  if(menu.Active() == cMenuData::xmsSubGenre) {
	     menu.DumpKey(Key);
		  if(state == osUnknown) {
			  switch(Key) {
				  case kRed: AddSubMenu(new cOsdCategoryList(menu)); break;
				  case kGreen: AddSubMenu(new cOsdSearch(menu)); break;
				  case kOk:				
				  case kBlue: {
					  cMenuSubGenreItem * pI = (cMenuSubGenreItem *)Get(Current());				  

					  if(pI) {
						  menu.SetSubgenre(pI->Id());
						  menu.SetStrSubgenre(pI->Name());
						  AddSubMenu(new cOsdMediaList(menu, menu.Genre(), menu.Subgenre()));
						  }
					  } break;
				  default:;
				  }
			  }
		  else if(state == osContinue) {
			  if(Key == kYellow) {
				  AddSubMenu(new cOsdMediaList(menu, "title", menu.scratch));
				  }
			  else if(Key == kGreen) {
				  AddSubMenu(new cOsdMediaList(menu, "cast", menu.scratch));
				  }
			  }
		  }
     }
  return state;
}

void cOsdSubGenreList::SetHelp() 
{_                   // red,              green,  yellow,     blue
  cOsdMenu::SetHelp(tr("media-type"), tr("search"), NULL, tr("list media"));
}

// -- cOsdCategoryList --------------------------------------------------------
cOsdCategoryList::cOsdCategoryList(cMenuData & md)
: cOsdMenu(tr("media-type"), 45)	
, menu(md)
{_
  menu.SetActive(cMenuData::xmsCategory);	
  cMediaTypeReader reader = cMediaTypeReader();
  cMenuMediaTypeItem * pI = 0;

  while((pI = reader.Read()) != NULL) {
     SLDEBUG("try to add entry %s", pI->Name());	
     Add(pI);
     }
}

cOsdCategoryList::~cOsdCategoryList()
{_
	SLDEBUG("# destructor of cOsdCategoryList");
	menu.Up();
}

eOSState cOsdCategoryList::ProcessKey(eKeys Key)
{
  eOSState state = cOsdMenu::ProcessKey(Key);
  if(Key != kNone) {_
	  menu.DumpKey(Key);
	  if(Key == kOk) {
		  SLINFO(" - OK");
		  cMenuMediaTypeItem * pI = (cMenuMediaTypeItem *)Get(Current());

		  if(pI) {
			  SLDEBUG("set category to <%s>", pI->Name());
			  menu.SetStrCategory(pI->Name());
			  }
		  else {
			  SLWARN("could not get Mediatype item!");
			  }
		  }
     }
  return state;
}

void cOsdCategoryList::SetHelp() 
{_                   // red,              green,  yellow,     blue
  cOsdMenu::SetHelp(NULL, NULL, NULL, NULL);
}

// -- cOsdMediaList -----------------------------------------------------------
cOsdMediaList::cOsdMediaList(cMenuData & md, int genre)
: cOsdMenu("", 4,4,6)
, menu(md)
{_
  char * tmp;
  asprintf(&tmp, "%s", menu.StrGenre());  
  SetTitle(tmp);
  menu.SetActive(cMenuData::xmsMediaList);	
  cMediaReader reader = cMediaReader(genre);
  cMenuMediaItem * pI = 0;

  while((pI = reader.Read()) != NULL) {
     SLDEBUG("try to add entry %s", pI->Title());	
	  Add(pI);
     }  
  SetHelp();
}

cOsdMediaList::cOsdMediaList(cMenuData &md, int genre, int subgenre)
: cOsdMenu("", 4,4,6)
, menu(md)
{_
  char * tmp;
  asprintf(&tmp, "%s / %s", menu.StrGenre(), menu.StrSubgenre());  
  SetTitle(tmp);
  menu.SetActive(cMenuData::xmsMediaList);	
  cMediaReader reader = cMediaReader(genre, subgenre);
  cMenuMediaItem * pI = 0;

  while((pI = reader.Read()) != NULL) {
     SLDEBUG("try to add entry %s", pI->Title());	
	  Add(pI);
     }  
  SetHelp();
}

cOsdMediaList::cOsdMediaList(cMenuData &md, char * what, char * pat)
: cOsdMenu("", 4,4,6)
, menu(md)
{_
  char * tmp;
  asprintf(&tmp, "%s: %s", tr(what), pat);
  SetTitle(tmp);
  menu.SetActive(cMenuData::xmsMediaList);	
  cMediaReader reader = cMediaReader(what, pat);
  cMenuMediaItem * pI = 0;

  while((pI = reader.Read()) != NULL) {
     SLDEBUG("try to add entry %s", pI->Title());	
	  Add(pI);
     }  
  SetHelp();
}

cOsdMediaList::~cOsdMediaList()
{_
	SLDEBUG("# destructor of cOsdMediaList");
	menu.Up();
}

eOSState cOsdMediaList::ProcessKey(eKeys Key)
{
  eOSState state = cOsdMenu::ProcessKey(Key);
  if(Key != kNone) {_
	  menu.DumpKey(Key);
	  if(menu.Active() == cMenuData::xmsMediaList && state == osUnknown) {
	     menu.DumpKey(Key);
		  switch(Key) {
			  case kRed: 
				  SLWARN("play media - NOT implemented yet"); 
				  break;
			  case kGreen: {
				  cMenuMediaItem *pI = (cMenuMediaItem*)Get(Current());

				  if(pI) {
					  menu.SetStrTitle(pI->Title());
					  AddSubMenu(new cOsdCastList(menu, pI->Id()));
					  }
				  } break;
			  case kOk:
			  case kYellow: {
				  cMenuMediaItem * pI = (cMenuMediaItem *)Get(Current());				  

				  if(pI) {
					  menu.SetStrTitle(pI->Title());
					  AddSubMenu(new cOsdComment(menu, pI->Id()));
				     }
				  } break;
			  default:;
		     }
	     }
     }
  return state;
}

void cOsdMediaList::SetHelp() 
{_                  // red,        green,       yellow,    blue
  cOsdMenu::SetHelp(tr("play"), tr("cast"), tr("comment"), NULL);
}

// -- cOsdComment -------------------------------------------------------------
cOsdComment::cOsdComment(cMenuData &md, int i) 
: cMenuText("", "")	
, menu(md)
{_
  char * tmp;
  asprintf(&tmp, tr("comment of: %s"), menu.StrTitle());
  SetTitle(tmp);  
  menu.SetActive(cMenuData::xmsComment);	
  cCommentReader reader = cCommentReader(i);
  cMenuCommentItem *pI = 0;
  if((pI = reader.Read()) != NULL) {
	  SetText(pI->Comment());
     }
}

cOsdComment::~cOsdComment()
{_
	SLDEBUG("# destructor of cOsdComment");
	menu.Up();
}

// -- cOsdCast ----------------------------------------------------------------
cOsdCastList::cOsdCastList(cMenuData & md, int i) 
: cOsdMenu("", 25) 	
, menu(md)
{_
  char * tmp;
  asprintf(&tmp, tr("cast of %s"), menu.StrTitle());
  SetTitle(tmp);  
  menu.SetActive(cMenuData::xmsCast);	
  cCastReader reader = cCastReader(i);
  cMenuCastItem * pI = 0;

  while((pI = reader.Read()) != NULL) {
     SLDEBUG("try to add entry %s", pI->Name());	
	  pI->SetSelectable(false);
	  Add(pI);
     }  
  SetHelp();
}

cOsdCastList::~cOsdCastList()
{_
	SLDEBUG("# destructor of cOsdCastList");
	menu.Up();
}

void cOsdCastList::SetHelp() 
{_               // red, green, yellow, blue
  cOsdMenu::SetHelp(NULL, NULL, NULL, NULL);
}

// -- cOsdSearch --------------------------------------------------------------
cOsdSearch::cOsdSearch(cMenuData & md)
: cOsdMenu(tr("search"), 25)
, menu(md)
{_
	menu.SetActive(cMenuData::xmsSearch);
	Add(new cMenuEditStrItem(tr("enter search pattern")
									, menu.scratch
									, sizeof(menu.scratch)
									, " abcdefghijklmnopqrstuvwxyz0123456789_."));
	SetHelp();
}

cOsdSearch::~cOsdSearch()
{_
	SLDEBUG("# destructor of cOsdSearch");
	menu.Up();
}

eOSState cOsdSearch::ProcessKey(eKeys Key)
{
  eOSState state = cOsdMenu::ProcessKey(Key);
  if(Key != kNone) {_
	  menu.DumpKey(Key);
	  if(menu.Active() == cMenuData::xmsSearch) {
		  switch(Key) {
			  case kYellow:
				  state = osBack;
				  break;
			  case kGreen:
				  state = osBack;
				  break;
			  case kOk:
				  SetHelp();
				  break;
			  default:;
		     }
        }
     }
  return state;
}

void cOsdSearch::SetHelp() 
{_
                 // red,      green,             yellow,         blue
  cOsdMenu::SetHelp(NULL, tr("search cast"), tr("search title"), NULL);
}

