
#include <vdr/interface.h>
#include <vdr/menuitems.h>
#include <vdr/i18n.h>
#include <vdr/config.h>
#include "menu-vbox.h"
#include "sndplayer.h"
#include <typeinfo>

const char * szVBOXAuFilename = "/tmp/vbox-vdr.au";
class cVBOXSndPlayerControl: public cSndPlayerControl
{
public:
	cVBOXSndPlayerControl(const char *fn)
		:cSndPlayerControl(fn) 
	{}

};




// ---------------------------------------------------------------------------
// --- cVBOXBaseItem -------------------------------------------------------------
class cVBOXBaseItem : public cOsdItem {
protected:
 cVBOXClient *m_pVBOX;
 char *m_szText;
public:
 cVBOXBaseItem (cVBOXClient *pVBOX,const char *szText,eOSState State = osUnknown)
	 :cOsdItem(State)
 {
	m_pVBOX=pVBOX;
	m_szText = strdup(szText);
 }

 virtual eOSState ProcessKey(eKeys Key);
 virtual eOSState OnOk(){return osUnknown;}
 virtual ~cVBOXBaseItem();
};


eOSState cVBOXBaseItem::ProcessKey(eKeys Key)
{
	if(Key == kOk)
	{
		eOSState state = OnOk();
		return state;
	}
	return osUnknown;
}
cVBOXBaseItem::~cVBOXBaseItem()
{
	if(m_szText)
		free(m_szText);
}

// ---------------------------------------------------------------------------
// --- cCtrlItem -------------------------------------------------------------
class cCtrlItem : public cVBOXBaseItem {
protected:
	cVBOXClient::eCtrl m_CtrlId;
    
    int m_OldStatus;
public:
 cCtrlItem (cVBOXClient *pVBOX,const char *szText,cVBOXClient::eCtrl ctrlid);
 virtual eOSState OnOk();
 virtual void Set(void);
};

cCtrlItem::cCtrlItem (cVBOXClient *pVBOX,const char *szText,cVBOXClient::eCtrl ctrlid)
:cVBOXBaseItem(pVBOX,szText)
{

	m_CtrlId = ctrlid;
	m_OldStatus = 0;
	Set();

}

void cCtrlItem::Set(void)
{
	char *buffer = NULL; 
	int iStatus = 0;
	m_pVBOX->GetServerStatusCtrl(m_CtrlId,&iStatus);
	asprintf(&buffer,("%s\t: %s"),m_szText,(iStatus == 1 ? tr("On"):tr("Off")));

	SetText(buffer,false);
}
eOSState cCtrlItem::OnOk()
{
	int iStatus = 0;
	m_pVBOX->GetServerStatusCtrl(m_CtrlId,&iStatus);
	if(iStatus == 0)
	{
		m_pVBOX->GetServerCreateCtrl(m_CtrlId);
	}
	else
	{
		m_pVBOX->GetServerRemoveCtrl(m_CtrlId);
	}
   
	Set();
	return osContinue;
}

// ---------------------------------------------------------------------------
// --- cShowListItem -------------------------------------------------------------
class cShowListItem : public cVBOXBaseItem {
protected:

public:
	cShowListItem (cVBOXClient *pVBOX, const char * szText)
		:cVBOXBaseItem(pVBOX,szText,osUser1)
	  {Set();}
	virtual void Set(void);
	 virtual eOSState OnOk(){return osUser1;}
	
	
};




void cShowListItem::Set(void)
{
 
	 char *buffer=NULL;
	time_t tempTimeLatest=0;
	int tempCount = 0;
	m_pVBOX->GetServerNewMsgCount(&tempCount,&tempTimeLatest);
	if(tempCount > 0)
	{
		asprintf(&buffer, "%s\t: %d %s",m_szText,tempCount,tr("new call(s)"));
	}
	else
	{
		asprintf(&buffer,"%s\t: %s",m_szText,tr("no new calls"));

	}
	SetText(buffer,false);
	
 
}



/*
// ---------------------------------------------------------------------------
// --- cCtrlStatusListItem -------------------------------------------------------------
class cCtrlStatusListItem : public cCtrlItem {
protected:

public:
	cCtrlStatusListItem (cVBOXClient *pVBOX)
		:cCtrlItem(pVBOX)
	  {}

};
*/

// ---------------------------------------------------------------------------
// --- cMenuCtrlVBOX -------------------------------------------------------------
cMenuCtrlVBOX::cMenuCtrlVBOX(cVBOXUser *pVBOXUser)
:cOsdMenu(tr("VBOX Mainmenu"),35)
{
  m_pVBOXUser = pVBOXUser;

  StatusMessage(tr("Connecting to vbox ..."));

  if(m_pVBOXUser->GetVBOX()->Connect() == cVBOXClient::vboxSuccess)
  {
	CreateEntrys();
  }
  else
  {
    ErrorMessage("Error to connect to vbox!");
  }
}
cMenuCtrlVBOX::~cMenuCtrlVBOX(void)
{
	m_pVBOXUser->GetVBOX()->Disconnect();
}
void cMenuCtrlVBOX::CreateEntrys()
{
	Clear();
	char * title = NULL;
	asprintf(&title,tr("VBOX Mainmenu for %s"),m_pVBOXUser->Name());
	SetTitle(title);
	free(title);
	SetHasHotkeys();
	Add(new cShowListItem(m_pVBOXUser->GetVBOX(),hk(tr("Enter List of Calls"))),false);
	Add(new cCtrlItem(m_pVBOXUser->GetVBOX(),hk(tr("VBOX stop")),cVBOXClient::ctrlStop),false);
	Add(new cCtrlItem(m_pVBOXUser->GetVBOX(),hk(tr("VBOX answers ALL calls")),cVBOXClient::ctrlAnswerAll),false);
	Add(new cCtrlItem(m_pVBOXUser->GetVBOX(),hk(tr("VBOX answers CURRENT call")),cVBOXClient::ctrlAnswerNow),false);
	Add(new cCtrlItem(m_pVBOXUser->GetVBOX(),hk(tr("VBOX rejects CURRENT call")),cVBOXClient::ctrlReject),false);
	Add(new cCtrlItem(m_pVBOXUser->GetVBOX(),hk(tr("VBOX suspends CURRENT call")),cVBOXClient::ctrlSuspend),false);
	
	SetHelp(tr("Answer"),tr("Answer all"),tr("Reject"),tr("Suspend"));
	Display();
}

eOSState cMenuCtrlVBOX::ProcessKey(eKeys Key)
{
  
  eOSState state=cOsdMenu::ProcessKey(Key);

  if(state == osUser1)
  {
	state=osContinue;
	return AddSubMenu(new cMenuListVBOX(m_pVBOXUser->GetVBOX()));

  }
  else if (state == osUnknown) {
     switch (Key) 
	 {
     case kRed:
     	state = ((cCtrlItem*)Get(3))->OnOk();
		Display();
		break;
     case kGreen:
     	state =  ((cCtrlItem*)Get(2))->OnOk();
		Display();
		break;
     case kYellow:
     	state =  ((cCtrlItem*)Get(4))->OnOk();
		Display();
		break;
     case kBlue:
     	state =  ((cCtrlItem*)Get(5))->OnOk();
		Display();
		break;
     			
     case kNone:
		 m_pVBOXUser->GetVBOX()->KeepAlive(); 
		 
		 
		 break;
     default:return osUnknown;
     }
  }
  
 
  return state;
}
// ---------------------------------------------------------------------------
// --- cMsgItem -------------------------------------------------------------
class cMsgItem : public cOsdItem {
private:
 int m_MsgNr;
 enum CallerDisplay {DISPLAY_NAME,DISPLAY_NUMBER};
 enum CallerDisplay m_eDisplay;
 cVBOXClient *m_pVBOX;
 char * m_szCallerName;
public:
 cMsgItem (cVBOXClient *pVBOX,int nr);
 void SetMyText(void);
 int GetNumber(void) { return m_MsgNr; }
 void ToggleNew(void);
 void ToggleDelete(void);
 void ToggleNameNumber(void);
 ~cMsgItem(void);
};

cMsgItem::cMsgItem (cVBOXClient *pVBOX,int nr)
{
  m_eDisplay = DISPLAY_NAME;
	m_MsgNr = nr;
	m_pVBOX = pVBOX;
  m_szCallerName = NULL;
	SetMyText();
}

void cMsgItem::SetMyText(void)
{
 
	 char *buffer=NULL;
	 bool bDeleted=false;
	 m_pVBOX->GetMsgIsDeleted(m_MsgNr,&bDeleted);
	 bool bNew = false;
	 m_pVBOX->GetMsgIsNew(m_MsgNr,&bNew );
	 struct tm tmTime;
	 static char date[50];
	 m_pVBOX->GetMsgTime(m_MsgNr,&tmTime );
	 strftime(date, sizeof(date), "%d.%m %R", &tmTime);

	 char* playtime = NULL;
	 m_pVBOX->GetMsgPlaytime(m_MsgNr,&playtime );
	 if(playtime == NULL)
		 playtime = strdup("#ERR#");
	 if(m_szCallerName == NULL)
      m_pVBOX->GetMsgCallerName(m_MsgNr,&m_szCallerName);
	 char* callerid = NULL;
	 m_pVBOX->GetMsgCallerId(m_MsgNr,&callerid );
   const char *caller = NULL;
   if(m_eDisplay == DISPLAY_NAME)
   {
    if(m_szCallerName == NULL)
    {
      if(callerid)
      {
        if(resolvenumber_script)
        {
          cCommand cmd;
          cmd.Parse(resolvenumber_script);
          m_szCallerName = strdup(cmd.Execute(callerid));
          caller = m_szCallerName;
        }
        else
          caller = callerid;
      }
      if(caller == NULL)
        caller = tr("unknown number");
    }
    else
      caller = m_szCallerName;
   }
   else if (m_eDisplay == DISPLAY_NUMBER )
   {
     if(callerid)
      caller = callerid;
     else
      caller = tr("unknown number");
   }
	 if(caller == NULL)
    caller = "#error#s";
   asprintf(&buffer,"%s\t%s\t%s\t%s",(bDeleted?"D":(bNew?"U":" ")),date,playtime,caller);
//printf("%s\n",buffer);
//printf("bDeleted=%d\n",(int)bDeleted);
//printf("bNew=%d\n",(int)bNew);
	  SetText(buffer,false);
 
	  free(playtime);
	  free(callerid);
}

void cMsgItem::ToggleDelete(void)
{
	m_pVBOX->ToggleDeletedFlag(m_MsgNr);	
	SetMyText();
}

void cMsgItem::ToggleNew(void)
{
	m_pVBOX->ToggleNewFlag(m_MsgNr);	
	SetMyText();
}
void cMsgItem::ToggleNameNumber(void)
{
  m_eDisplay = (m_eDisplay == DISPLAY_NAME) ? DISPLAY_NUMBER:DISPLAY_NAME;
  SetMyText();
}
cMsgItem::~cMsgItem (void)
{
  free(m_szCallerName);
}


cMenuListVBOX::cMenuListVBOX(cVBOXClient *pVBOX)
:cOsdMenu(tr("VBOX List of calls"),4,13,8,20)
{
  m_pVBOX = pVBOX;
  m_bIsPlaying = false;
  m_bDisconnectOnDestroy = false;
  if( m_pVBOX->IsConnected() == false)
  {
    StatusMessage(tr("Connecting to vbox ..."));
    if(m_pVBOX->Connect() != cVBOXClient::vboxSuccess)
    {
     ErrorMessage(tr("Error to connect to vbox!"));
     return;
    }
    m_bDisconnectOnDestroy = true;
  }
  RefreshMsgList(false);// do not DeleteMarkedMessages

}

void cMenuListVBOX::DisplayMsgList(void)
{
	char * title = NULL;
	asprintf(&title,"%s (%d/%d)",tr("VBOX List of calls"),m_pVBOX->GetMsgNewCount(),m_pVBOX->GetMsgTotalCount());
	SetTitle(title);
	free(title);
//	char * header = NULL;
//	asprintf(&header,"S\t%s\t%s\t%s \t%s",tr("Time"),tr("Length"),tr("Name"),tr("CallerId"));
//	Add(new cMenuTextItem(header, 1, 2, Setup.OSDwidth - 2, MAXOSDITEMS, clrBlack, clrBackground));

	for(int nr=0;nr <  m_pVBOX->GetMsgTotalCount(); nr++)
	{
		Add(new cMsgItem(m_pVBOX,nr),false);
	}
	SetHelpTexts();
	Display();
}

void cMenuListVBOX::RefreshMsgList(bool bDeleteMarkedMessages)
{
	if(bDeleteMarkedMessages)
		DeleteMarkedMessages(false);
	cOsdMenu::Clear();
    StatusMessage(tr("Retrieving list of calls ..."));
	if(m_pVBOX->TransferMsgList() == cVBOXClient::vboxSuccess)
	{
		DisplayMsgList();
	}
	else
	{
        ErrorMessage(tr("Retrieving list of calls failed!"));
	}	
}
void cMenuListVBOX::SetHelpTexts()
{
	if(m_bIsPlaying)
		SetHelp(tr("Stop"),tr("Unread"),tr("Refresh"),tr("Del/Undel"));
	else
		SetHelp(tr("Play"),tr("Unread"),tr("Refresh"),tr("Del/Undel"));
	Display();
}
cMenuListVBOX::~cMenuListVBOX(void)
{
	
	DeleteMarkedMessages(false);
  if(m_bDisconnectOnDestroy)
    m_pVBOX->Disconnect();
}

void cMenuListVBOX::DeleteMarkedMessages(bool bReloadList)
{

	if(m_pVBOX->GetMsgDeletedCount())
	{
		bool bOk = true;
		if(g_VBOXSetup.m_bConfirmDeletion)
		{
			bOk = Interface->Confirm(tr("Really delete all marked messages?"));
		}
		if(bOk)
		{
			m_pVBOX->DeleteMarkedMessages(bReloadList);//TODO print error
		}
	}

}
cVBOXSndPlayerControl* cMenuListVBOX::GetVBOXSndPlayerControl()
{
	cControl *control=cControl::Control();
	if(control && typeid(*control)==typeid(cVBOXSndPlayerControl)) 
	{    // is there a running cVBOXSndPlayerControl
		return static_cast<cVBOXSndPlayerControl*>(control);
	}
	return NULL;
}
eOSState cMenuListVBOX::ProcessKey(eKeys Key)
{
  
  eOSState state=cOsdMenu::ProcessKey(Key);

  if (state == osUnknown)
  {
    cMsgItem *mi = (cMsgItem *)Get(Current());
    if(!mi)
      return osContinue;

   switch (Key)
	 {
     case kRed:
     case kOk:   
		 {
				cVBOXSndPlayerControl * control = GetVBOXSndPlayerControl();
				if(control)
				{
					control->Stop(); // stop it
					return osContinue;
				}
				if(m_pVBOX->CreateAuFileFromMsg(mi->GetNumber(),szVBOXAuFilename) != cVBOXClient::vboxSuccess)
				{
          ErrorMessage(tr("Retrieving calldata failed, cannot play!"));
				}
				else
				{
					bool bIsNew = false;
					m_pVBOX->GetMsgIsNew(mi->GetNumber(),&bIsNew);
					if(bIsNew)
					{
						mi->ToggleNew();
						RefreshCurrent();
					}
					DisplayCurrent(true);
					cControl::Launch(new cVBOXSndPlayerControl(szVBOXAuFilename));
					m_bIsPlaying = true;
					SetHelpTexts();
          StatusMessage( tr("Playing call ..."));
				}
				return osContinue;
            break;
		 }
     case kGreen:  
		{
			mi->ToggleNew();
			Display();
			return osContinue;
     }
     case kBlue:   
		 {
				mi->ToggleDelete();
				Display();
			  return osContinue;
     }
     case k0:
     {
        mi->ToggleNameNumber();
        Display();
     }
			return osContinue;

     case kYellow: 
		 RefreshMsgList(true); // true means :delete marked messages
		 return osContinue;
		 break;
     
     case kNone:
  		 m_pVBOX->KeepAlive();
	  	 if(m_bIsPlaying && GetVBOXSndPlayerControl()==NULL)
       {
          m_bIsPlaying = false;
          SetHelpTexts();
		   }
		 return state;
     default: return osUnknown;
     }
  }
 
  return state;
}

// --- cVBOXUserItem -------------------------------------------------------------
class cVBOXUserItem : public cOsdItem {
private:
 int m_MsgNr;
 cVBOXUser *m_pVBOXUser;
public:
 cVBOXUserItem (cVBOXUser *pVBOXUser);
 cVBOXUser * GetUser(void) { return m_pVBOXUser; }
 ~cVBOXUserItem(void);
};

cVBOXUserItem::cVBOXUserItem (cVBOXUser *pVBOXUser)
{
	m_pVBOXUser = pVBOXUser;
	char *buffer=NULL;
    asprintf(&buffer,"%s\t@%s",m_pVBOXUser->Name(),m_pVBOXUser->Server());
    SetText(buffer,false);

}

cVBOXUserItem::~cVBOXUserItem (void)
{
 
}


cMenuVBOXUser::cMenuVBOXUser(cVBOXUserlist *pVBOXUserlist)
:cOsdMenu(tr("Select a VBOX User"),14)
{
  
  DisplayUserList(pVBOXUserlist);
}


void cMenuVBOXUser::DisplayUserList(cVBOXUserlist *pVBOXUserlist)
{
	for (cVBOXUser *pVBOXUser = pVBOXUserlist->First(); pVBOXUser; pVBOXUser = pVBOXUserlist->Next(pVBOXUser))
	{
		Add(new cVBOXUserItem(pVBOXUser));
	}
	SetHelp(tr("Control"));
	Display();
}

eOSState cMenuVBOXUser::ProcessKey(eKeys Key)
{
  
  eOSState state=cOsdMenu::ProcessKey(Key);

  if (state == osUnknown) {
     switch (Key) 
	 {
     case kRed:   
		 {
              cVBOXUserItem *ui = (cVBOXUserItem *)Get(Current());
			  if(ui)
				return AddSubMenu(new cMenuCtrlVBOX(ui->GetUser()));


            break;

		 }

	case kOk:
		 {
              cVBOXUserItem *ui = (cVBOXUserItem *)Get(Current());
			  if(ui)
			  {
			  
				return AddSubMenu(new cMenuListVBOX(ui->GetUser()->GetVBOX()));
			  }

            break;

		 }
     default:return osUnknown;
     }
  }
  
 
  return state;
}

cMenuVBOXUser::~cMenuVBOXUser()
{

}