
#include <string>
#include <list>

#include <iostream>

#include "asterisk.h"
#include "ast_menu.h"
#include "ast_player.h"

using namespace std;

class astMessageItem : public cOsdItem
{
 private:
  astVoiceMessage m_msg;
  int m_display_mode;

 public:
  astMessageItem( astVoiceMessage msg, int display_mode = astVoicebox::GM_NONE )
    : m_msg( msg ), m_display_mode( display_mode )
    { 
      Set();
    }

  void Set(void);

  astVoiceMessage GetMessage() { return m_msg; }

  ~astMessageItem()
    { };
};

void astMessageItem::Set()
{
  char *buffer;

  string date   = m_msg.GetDate();
  string time   = m_msg.GetTime();
  string caller = m_msg.GetCallerId();
  string length = m_msg.GetDuration();
  string exten  = m_msg.GetExtension();

  if( m_display_mode == astVoicebox::GM_CALLER )
    {
      asprintf( &buffer, "%s\t%s\t%s\t%s", length.c_str(), time.c_str(), "", exten.c_str() );
    }
  else if( m_display_mode == astVoicebox::GM_DATE )
    {
      asprintf( &buffer, "%s\t%s\t%s\t%s", length.c_str(), caller.c_str(), "", exten.c_str() );
    }
  else
    {
      asprintf( &buffer, "%s\t%s\t%s\t%s", length.c_str(), caller.c_str(), date.c_str(), exten.c_str() );
    }
  
  SetText( buffer, false );
  // ? //   free( buffer );
}

class astFolderItem : public cOsdItem
{
 private:
  string m_foldername;

 public:
  astFolderItem( string foldername )
    : m_foldername( foldername )
    { 
      Set();
    }

  void Set(void)
    {
      SetText( tr( m_foldername.c_str() ), true );
    }

  string GetFolderName() { return m_foldername; }
};

astFolderMenu::astFolderMenu( astVoicebox &vb )
  : cOsdMenu( tr("Folder list") ), m_vbox( vb )
{ 
  DisplayFolderList();
}

void astFolderMenu::DisplayFolderList( )
{
  // set the title, add voicebox and folder names
  string title = tr( "Folder list of voicebox " );
  title += m_vbox.GetName();
  SetTitle( title.c_str() );

  // display folders
  list<string> folders = m_vbox.GetFolders();
  for( list<string>::iterator iter = folders.begin();
       iter != folders.end(); iter ++ )
    {
      // initialize folder items with folder names
      Add( new astFolderItem( *iter ) );
    }
	 
  Display();  
}
 
eOSState astFolderMenu::ProcessKey(eKeys key)
{
  eOSState state = cOsdMenu::ProcessKey(key);

  if (state == osUnknown) 
    {
      switch (key) 
	{
	case kOk:   
	  {
	    // retrieve real folder name, not (translated) display name
	    astFolderItem *fldr_item = (astFolderItem *) Get( Current() );

	    // Set current folder and return
	    m_vbox.SetCurrentFolder( fldr_item->GetFolderName() );
	    state = osBack;
	  } break;
	default:
	  {
	    state = osUnknown;
	  }
	}
    }
  
  return state;  
}

astMoveMenu::astMoveMenu( astVoicebox &vb, astMessageItem *msg )
  : cOsdMenu( tr("Folder list") ), m_vbox( vb ), m_message( msg )
{ 
  DisplayFolderList();
}

void astMoveMenu::DisplayFolderList( )
{
  // set the title, add voicebox and folder names
  string title = tr( "Folder list of voicebox " );
  title += m_vbox.GetName();
  SetTitle( title.c_str() );

  // display folders
  list<string> folders = m_vbox.GetFolders();
  for( list<string>::iterator iter = folders.begin();
       iter != folders.end(); iter ++ )
    {
      // initialize folder items with folder names
      Add( new astFolderItem( *iter ) );
    }
	 
  Display();  
}
 
eOSState astMoveMenu::ProcessKey(eKeys key)
{
  eOSState state = cOsdMenu::ProcessKey(key);

  if (state == osUnknown) 
    {
      switch (key) 
	{
	case kOk:   
	  {
	    // retrieve real folder name, not (translated) display name
	    astFolderItem *fldr_item = (astFolderItem *) Get( Current() );

	    // Set current folder and return
	    m_message->GetMessage().MoveTo( fldr_item->GetFolderName() );
	    state = osBack;
	  } break;
	default:
	  {
	    state = osUnknown;
	  }
	}
    }
  
  return state;  
}


astVoiceboxMenu::astVoiceboxMenu( astVoicebox vb )
  : cOsdMenu( tr("Message list"), 4, 20, 10, 6 ),
     m_vbox( vb )
{
  DisplayMessageList();
}

void astVoiceboxMenu::DisplayMessageList()
{
  Clear();

  // set the title, add voicebox and folder names
  string title = tr( "Message list " );
  title += m_vbox.GetName() + "/" + m_vbox.GetCurrentFolder();

  SetTitle( title.c_str() );

  map< string, cOsdItem* > separators;

  // display messages
  list<astVoiceMessage> vmlist = m_vbox.GetMessages();
  for( list<astVoiceMessage>::iterator iter = vmlist.begin();
       iter != vmlist.end(); iter ++ )
    {
      // test for key
      cOsdItem *sep = NULL;
      string key;
      
      if( m_display_mode == astVoicebox::GM_CALLER )
	{
	  key = iter->GetCallerId();
	}
      else if( m_display_mode == astVoicebox::GM_DATE )
	{
	  key = iter->GetDate();
	}
      
      if( m_display_mode != astVoicebox::GM_NONE )
	{
	  if( separators.find( key ) != separators.end() )
	    {
	      sep = separators[ key ];
	    }
	  else
	    {
	      char *buffer;
	      asprintf( &buffer, "---\t%s ---", key.c_str() );
	      sep = new cOsdItem( buffer );
	      sep->SetSelectable( false );
	      Add( sep ); // adds at the end
	    }
	}
      // add the message item after the separator found
      Add( new astMessageItem( *iter, m_display_mode ), false, sep ); 
    }
	 
  // Set menu
  if( m_vbox.GetCurrentFolder() != "Trash" )
    {
      SetHelp( tr("Delete"), tr("Move"), tr("Display"), tr("Select folder") );
    }
  else
    {
      SetHelp( tr("Purge"), tr("Move"), tr("Display"), tr("Select folder") );
    }
  Display();
}

eOSState astVoiceboxMenu::ProcessKey(eKeys key)
{
  bool fHasSubmenu = HasSubMenu();
  eOSState state = cOsdMenu::ProcessKey(key);
  
  if( fHasSubmenu && !HasSubMenu() )
    { // Submenu disappeared during call to cOsdMenu::ProcessKey
      DisplayMessageList();
    }

  if (state == osUnknown) 
    {
      switch (key) 
	{
	case kOk:   
	  {
	    astMessageItem *msg = (astMessageItem *)Get( Current() );
	    string sndfile = msg->GetMessage().GetSoundfile( "wav" );

	    cSndPlayerControl * control = new cSndPlayerControl( sndfile.c_str() );
	    cControl::Launch(control);
	  } break;
	case kRed:
	  {
	    if( m_vbox.GetName() != "Trash" )
	      {
		astMessageItem *msg = (astMessageItem *)Get( Current() );
		msg->GetMessage().MoveTo( "Trash" );
	      }
	    else
	      {
		// delete all entries in folder Trash
		m_vbox.PurgeMessages();
	      }
	  } break;
	case kGreen: 
	  { // move to different folder
	    astMessageItem *msg = (astMessageItem *)Get( Current() );
	    return AddSubMenu( new astMoveMenu( m_vbox, msg ) );
	  } break;
	case kYellow:
	  { // toggle display mode
	    switch( m_display_mode )
	      {
	      case astVoicebox::GM_NONE:
		{
		  m_display_mode = astVoicebox::GM_CALLER;
		} break;
	      case astVoicebox::GM_CALLER:
		{
		  m_display_mode = astVoicebox::GM_DATE;
		} break;
	      case astVoicebox::GM_DATE:
	      default:
		{
		  m_display_mode = astVoicebox::GM_NONE;
		} break;
	      }
	    DisplayMessageList();
	  } break;
	case kBlue:
	  {
	    return AddSubMenu( new astFolderMenu( m_vbox ) );
	  } break;
	default:
	  {
	    state = osUnknown;
	  }
	}
    }
  
  return state;  
}

// item representing  a single voicebox
class astVoiceboxItem : public cOsdItem
{
 private:
  astVoicebox m_voicebox;
  
 public:
  astVoiceboxItem( astVoicebox vb )
    : m_voicebox( vb )
    { 
      Set();
    }

  void Set();

  astVoicebox GetVoicebox() { return m_voicebox; }

  ~astVoiceboxItem()
    { };
};

void astVoiceboxItem::Set()
{
  char *buffer;

  string name = m_voicebox.GetName();
  int num_msgs = m_voicebox.GetCount();

  asprintf( &buffer, "%s\t%d", name.c_str(), num_msgs );
  SetText( buffer, false);
  //   free( buffer );
}

// Main menu
astMainMenu::astMainMenu( astVoiceboxList vbl )
  : cOsdMenu( tr("Voicebox list") ),
     m_vbox_list( vbl )
{
  DisplayVoiceboxList();
}

void astMainMenu::DisplayVoiceboxList( )
{
  // set the title
  SetTitle( "Voicebox list" );

  // display messages
  list<astVoicebox> vblist = m_vbox_list.GetVoiceboxes();
  for( list<astVoicebox>::iterator iter = vblist.begin();
       iter != vblist.end(); iter ++ )
  {
    Add( new astVoiceboxItem( *iter ) );
  }
	 
  // Set menu
  Display();  
}

eOSState astMainMenu::ProcessKey(eKeys key)
{
  eOSState state = cOsdMenu::ProcessKey(key);

  if (state == osUnknown) 
    {
      switch (key) 
	{
	case kOk:   
	  {
	    astVoiceboxItem *vbitem = (astVoiceboxItem *)Get( Current() );
	    if( vbitem )
	      {
		return AddSubMenu( new astVoiceboxMenu( vbitem->GetVoicebox() ) );
	      }
	  } break;
	default:
	  {
	    return osUnknown;
	  }
	}
    }
  else
    {
      if( state==osBack )
	{
	  cPluginAsterisk::Unmount();
	}
    }

  return state;  
}
