/*
 * avolctl.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */

#include "avolctl.h"

int 		perc;
alsa		*alsamixer;
setupvalues	*setup;
mixerlist	*playback;

static const char *VERSION        = "0.3b";
static const char *DESCRIPTION    = "Alsa Volume Control";
static const char *MAINMENUENTRY  = "AVolCtl";

int hidemainmenu = false;

// -----------------------------------------------------------------------------
// handles the volume settings
// -----------------------------------------------------------------------------
class cMyStatusMonitor:public cStatus
{
 protected:
  virtual void SetVolume(int Volume, bool Absolute);
};

void cMyStatusMonitor::SetVolume(int Volume, bool Absolute)
{
 long vol;
 
 if(Absolute)
   perc=100*Volume/255;
 else
   perc=perc+100*Volume/255;

 playback->resetp();
 while(playback->isNext())
 {
  if(playback->getSetup()==1)
  {
   vol=perc-100+playback->getOffset();
   alsamixer->setVolume(playback->getName(),vol);
  }
  playback->goNext();
 }
}

// -----------------------------------------------------------------------------
// setup menu
// -----------------------------------------------------------------------------

class cMenuSelectControl:public cMenuSetupPage
{
 private:
 protected:
  virtual void Store(void);
 public:
  cMenuSelectControl(void);
};

cMenuSelectControl::cMenuSelectControl(void)
{
 Add(new cMenuEditBoolItem(tr("Hide main menu entry?"),&hidemainmenu));

 cOsdItem *item=new cOsdItem(tr("Select mixer items:"));
 item->SetSelectable(false);
 Add(item);

 playback->resetp();
 while(playback->isNext())
 {
  if(!playback->isVolume())Add(new editselect(playback->extName(),&playback->p->setup,1));
  else Add(new editselect(playback->extName(),&playback->p->setup,0));
  playback->goNext();
 }
}

void cMenuSelectControl::Store(void)
{
 SetupStore("hidemainmenu",hidemainmenu);
 
 playback->resetp();
 while(playback->isNext())
 {
  switch(playback->getSetup())
  {
   case 0:
    SetupStore(playback->getName());
    break;
   case 1:
    SetupStore(playback->getName(),100);
    playback->setOffset(100);
    alsamixer->setVolume(playback->getName(),perc);
    break;
   case 2:
    if(playback->isSwitch()&&!playback->isVolume())
    {
     SetupStore(playback->getName(),2000);
     playback->setOffset(0);
     alsamixer->setSwitch(playback->getName(),0);
     break;
    }
    if(playback->isVolume())
    {
     SetupStore(playback->getName(),1000);
     playback->setOffset(0);
     alsamixer->setVolume(playback->getName(),0);
    }
  }
  playback->goNext();
 }
}

// -----------------------------------------------------------------------------
// main menu
// -----------------------------------------------------------------------------
class cMenuMainAvolctl:public cMenuSetupPage
{
 protected:
  virtual eOSState ProcessKey(eKeys Key);
  virtual void Store(void);
 public:
  cMenuMainAvolctl(cPlugin *plugin = NULL);
};

cMenuMainAvolctl::cMenuMainAvolctl(cPlugin *plugin)
{
 SetPlugin(plugin);

 cOsdItem *item1=new cOsdItem(tr("Controlable items:"));
 item1->SetSelectable(false);
 Add(item1);

 playback->resetp();
 while(playback->isNext())
 {
  if(playback->getSetup()==2&&playback->isVolume())Add(new editoffset(playback->getName(),&playback->p->offset,true));
  else if(playback->getSetup()==2&&playback->isSwitch())Add(new editswitch(playback->getName(),&playback->p->offset));
  playback->goNext();
 }
 
 cOsdItem *item2=new cOsdItem("Offset (%):");
 item2->SetSelectable(false);
 Add(item2);
 
 playback->resetp();
 while(playback->isNext())
 {
  if(playback->getSetup()==1)Add(new editoffset(playback->getName(),&playback->p->offset,false));
  playback->goNext();
 }
}

void cMenuMainAvolctl::Store(void)
{ 
 playback->resetp();
 while(playback->isNext())
 {
  if(playback->getSetup()==1)SetupStore(playback->getName(),playback->getOffset());
  if(playback->getSetup()==2&&playback->isVolume())SetupStore(playback->getName(),playback->getOffset()+1000);
  else if(playback->getSetup()==2&&playback->isSwitch())SetupStore(playback->getName(),playback->getOffset()+2000);
  playback->goNext();
 }
}

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

 if (state == osUnknown)
 {
  switch (Key)
  {
   case kOk:
    Store();
    state = osBack;
    break;
   default:
    break;
  }
 }
 return state;
}

// -----------------------------------------------------------------------------
class cPluginAvolctl : public cPlugin {
private:
 cMyStatusMonitor	*statusMonitor;
 snd_mixer_t		*handle;
public:
  cPluginAvolctl(void);
  virtual ~cPluginAvolctl();
  virtual const char *Version(void) { return VERSION; }
  virtual const char *Description(void) { return DESCRIPTION; }
  virtual const char *CommandLineHelp(void);
  virtual bool ProcessArgs(int argc, char *argv[]);
  virtual bool Initialize(void);
  virtual bool Start(void);
  virtual void Stop(void);
  virtual void Housekeeping(void);
  virtual const char *MainMenuEntry(void) { return hidemainmenu ? NULL : tr(MAINMENUENTRY); }
  virtual cOsdObject *MainMenuAction(void);
  virtual cMenuSetupPage *SetupMenu(void);
  virtual bool SetupParse(const char *Name, const char *Value);
  };

cPluginAvolctl::cPluginAvolctl(void)
{
 statusMonitor=NULL;
 alsamixer=new alsa;
 setup=new setupvalues;
 playback=new mixerlist;
}

cPluginAvolctl::~cPluginAvolctl()
{
  // Clean up after yourself!
  delete statusMonitor;
  delete setup;
  delete playback;
  delete alsamixer;
}

const char *cPluginAvolctl::CommandLineHelp(void)
{
  return NULL;
}

bool cPluginAvolctl::ProcessArgs(int argc, char *argv[])
{
  return true;
}

bool cPluginAvolctl::Initialize(void)
{
 RegisterI18n(Phrases);
 return true;
}

bool cPluginAvolctl::Start(void)
{
 statusMonitor=new cMyStatusMonitor;
 
 playback=alsamixer->List();
 
 // --- apply setup values ---
 setup->resetp();
 while(setup->isNext())
 {
  playback->resetp();
  while(playback->isNext())
  {
   if(!strcmp(setup->getName(),playback->getName()))
   {
    if(atoi(setup->getValue())<1000)
    {
     playback->setSetup(1);
     playback->setOffset(atoi(setup->getValue()));
    }
    if(atoi(setup->getValue())>=1000&&atoi(setup->getValue())<2000)
    {
     playback->setSetup(2);
     playback->setOffset(atoi(setup->getValue())-1000);
     playback->setVolume(true);
     alsamixer->setVolume(playback->getName(),playback->getOffset());
    }
    if(atoi(setup->getValue())>=2000)
    {
     playback->setSetup(2);
     playback->setOffset(atoi(setup->getValue())-2000);
     playback->setSwitch(true);
     alsamixer->setSwitch(playback->getName(),playback->getOffset());
    }
   }
   playback->goNext();
  }
  setup->goNext();
 }
 
 return true;
}

void cPluginAvolctl::Stop(void)
{
}

void cPluginAvolctl::Housekeeping(void)
{
}

cOsdObject *cPluginAvolctl::MainMenuAction(void)
{
  return new cMenuMainAvolctl(this);
}

cMenuSetupPage *cPluginAvolctl::SetupMenu(void)
{
 return new cMenuSelectControl;
}

// -----------------------------------------------------------------------------
// we have to store the parsed values because 'SetupParse' is called before 'Start'
// -----------------------------------------------------------------------------
bool cPluginAvolctl::SetupParse(const char *Name, const char *Value)
{
 if(!strcmp("hidemainmenu",Name))hidemainmenu=atoi(Value);
 else
 {
  setup->setName(Name);
  setup->setValue(Value);
  setup->addElem();
 }
 
 return true;
}

VDRPLUGINCREATOR(cPluginAvolctl); // Don't touch this!
