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

#include "directorosd.h"
#include <time.h>
#include <vdr/menu.h>

cDirectorOsd::cDirectorOsd(cMenuDirectorData* data)
   : cOsdObject(true)
{	
   mData = data;
	
	//init colors

	bgColor = toColor(52, 80, 97, 200);
	bgClear = toColor(52, 80, 97, 0);
	//green = toColor(config.clr2Red, config.clr2Green, config.clr2Blue, config.trans);
	lightgrey = toColor(170, 170, 170, 255);
  
	font = cFont::GetFont(fontOsd);
	osd = NULL;
	channelname = NULL;
	asprintf(&channelname, " ");
	
	Channel = Channels.GetByNumber(cDevice::PrimaryDevice()->CurrentChannel());
	cChannel* initChannel = Channel;

#if VDRVERSNUM < 10333
	if (!Channel->GetLinkChannels())
		Channel = Channel->GetRefChannel();
#else
	if (!Channel->LinkChannels())
		Channel = (cChannel*)Channel->RefChannel();
#endif

	if (!Channel)
		Channel = initChannel;
		
	number = 1;
	current = 0;
	lastChannel = 0;	
	
	// try to find the right channel number

	if (Channel)
	{

#if VDRVERSNUM < 10333
		cLinkChannels* linkChannels = Channel->GetLinkChannels();
#else
		cLinkChannels* linkChannels = (cLinkChannels*)Channel->LinkChannels();
#endif

		if (linkChannels)
      {
			for (int i = 0; i < getNumLinks() + 1; i++)
				if (initChannel == getChannel(i))
					current = i;
      }
	}
	
	lastkeytime = time(NULL);
}

void cDirectorOsd::Show(void)
{
	drawOsd();
}
 
cDirectorOsd::~cDirectorOsd(void)
{
  delete osd;
  free(channelname);
}
 
eOSState cDirectorOsd::ProcessKey(eKeys Key)
{
	eOSState state = cOsdObject::ProcessKey(Key);

	if (state == osUser1)
	{
		SwitchtoChannel(0);
		state = osContinue;
	}  
   else if (state == osUnknown) 
   {
      switch (Key)
      { 
         case kYellow:
         {
            mData->mShowOldDirectorOsd = 0;
            cRemote::CallPlugin("arghdirector");
            return osEnd;
         }
         case kUp:
         case kUp|k_Repeat:
            CursorUp();
            break; 
         case kDown:
         case kDown|k_Repeat:
            CursorDown();
            break; 
         case kLeft:
         case kLeft|k_Repeat:
            CursorLeft();
            break; 
         case kRight:
         case kRight|k_Repeat:
            CursorRight();
            break;       
         case kOk:
            if(isOsdShowing)
					clearOsd();
				else
					drawOsd();
            break;   
         case k0 ... k9:

            int number;
            number = Key;
      	
            if (difftime(time(NULL), lastkeytime) < 2)
               number = 10 * current + Key;
            else if (number == 11) // catch a switch with 0
            {
               SwitchtoChannel(lastChannel);
               break;
            }

            if (mData->mPortalmode == 0)
					SwitchtoChannel(number - k0 - 1);
				else
					SwitchtoChannel(number - k0);        

            lastkeytime =  time(NULL);

            break;

         case kBack:
            return osEnd;
         default:
            return state;
      }

      state = osContinue;
   }

   return state;
}

void cDirectorOsd::Action(void){}

void cDirectorOsd::CursorUp()
{
	if (mData->mSwapKeys == 0)
		ChannelUp();
	else
		ChannelDown();
} 

void cDirectorOsd::CursorDown()
{
	if (mData->mSwapKeys == 0)
		ChannelDown();
	else
		ChannelUp();
}

void cDirectorOsd::CursorLeft()
{	
	SwitchtoChannel(0);
}

void cDirectorOsd::CursorRight()
{
	SwitchtoChannel(getNumLinks());
}

void cDirectorOsd::ChannelDown()
{	
	number = getNumLinks() + 1;

	if (current > number - 1)
		current = number - 1;	
	
	if (lastChannel == current)
		return;		

	lastChannel = current;	

	if (current > 0)
		current--;
	
	cChannel *newChannel =  getChannel(current);
	free(channelname);
	asprintf(&channelname, "%s", newChannel->Name());
	
	cDevice::PrimaryDevice()->SwitchChannel(newChannel, true);

	if (isOsdShowing)
		drawOsd();
	else if (mData->mDisplayChannelInfo == 1)
		Skins.Message(mtInfo, channelname);
}

void cDirectorOsd::ChannelUp()
{
	number = getNumLinks() + 1;
	
	if (current == number - 1)
		return;
	lastChannel = current;
	
	current++;

	if (current >= number - 1)
		current = number - 1;	
	if (lastChannel == current)
		return;
	
	cChannel *newChannel = getChannel(current);
	
	free(channelname);	
	asprintf(&channelname, "%s", newChannel->Name());
	
	cDevice::PrimaryDevice()->SwitchChannel(newChannel, true);

	if (isOsdShowing)
		drawOsd();
	else if (mData->mDisplayChannelInfo == 1)
		Skins.Message(mtInfo, channelname);
}

void cDirectorOsd::SwitchtoChannel(int channelnumber)
{
	number = getNumLinks() + 1;	
	if (channelnumber > number - 1)
		channelnumber = number - 1;	
	
	if (current == channelnumber)
		return;
	lastChannel = current;
	current = channelnumber;
	
	//fprintf(stderr, "lastChannel %d\n", lastChannel);
	//fprintf(stderr, "current %d\n", current);
	
	cChannel *newChannel = getChannel(current);
	
	free(channelname);
	asprintf(&channelname, "%s", newChannel->Name());
	
	cDevice::PrimaryDevice()->SwitchChannel(newChannel, true);

	if (isOsdShowing)
		drawOsd();
	else
		Skins.Message(mtInfo, channelname);
}

void cDirectorOsd::CursorOK(){}

cChannel* cDirectorOsd::getChannel(int channelnumber)
{	
	number = getNumLinks() + 1;

	if (channelnumber > number -1)
		channelnumber = number -1;
	if (channelnumber < 1)
		return Channel;
	else
	{
#if VDRVERSNUM < 10333
		cLinkChannels* linkChannels = Channel->GetLinkChannels();
#else
		cLinkChannels* linkChannels = (cLinkChannels*)Channel->LinkChannels();
#endif
		cLinkChannel* lca = linkChannels->First();

		for (int i = 1; i < channelnumber; i++)
			lca = linkChannels->Next(lca);

		return lca->Channel();
	}
}

int cDirectorOsd::getNumLinks()
{
#if VDRVERSNUM < 10333
	cLinkChannels* linkChannels = Channel->GetLinkChannels();
#else
	cLinkChannels* linkChannels = (cLinkChannels*)Channel->LinkChannels();
#endif
	if (linkChannels)
		return linkChannels->Count();
	else
		return 0;
}

tColor cDirectorOsd::toColor(int r, int g, int b, int t)
{
   int temp = t;
   temp <<= 8;
   temp += r;
   temp <<= 8;
   temp += g;
   temp <<= 8;
   temp += b;
   return (tColor) temp;
}

void cDirectorOsd::clearOsd(void)
{
	delete osd;
	osd = NULL;
	isOsdShowing = false;
}

void cDirectorOsd::drawOsd(void)
{	
	isOsdShowing = true;
	
	if (Channel)
	{
#if VDRVERSNUM < 10333
		cLinkChannels* linkChannels = Channel->GetLinkChannels();
#else
		cLinkChannels* linkChannels = (cLinkChannels*)Channel->LinkChannels();
#endif
		if (linkChannels)
			number = getNumLinks() + 1;
		else
			number = 1;
		
		char *buffer=0;
		asprintf(&buffer,"1 %s %d", Channel->Name(), number);
				
		int theHeigth = font->Height("A");
		int m_height = (number * theHeigth) + 10;
		
		// get the width

		int gr_width = font->Width(buffer);

		for (int i = 0; i < number; i++)
		{
			cChannel *newChannel =  getChannel(i);
			asprintf(&buffer,"%d %s", i + 1, newChannel->Name());
			int width = font->Width(buffer);
			if(width > gr_width)
				gr_width = width;
		}
		
		gr_width += 12;

		if (gr_width%2 == 0)
			gr_width++;
		
		asprintf(&buffer,"1 %s %d", Channel->Name(), number);
  
  		if (!osd)
  			osd = cOsdProvider::NewOsd(100, 50);
		if (osd) 
		{
			if(gr_width != last_gr_width)
			{
				delete osd;
				osd = cOsdProvider::NewOsd(100, 50);
			}
			
			last_gr_width = gr_width;
			
			int y = 5;
			tArea Area = { 0, 0, gr_width, m_height,  4 };
			osd->SetAreas(&Area, 1);
			osd->DrawRectangle(0, 0, gr_width, m_height, bgColor);
			
			for (int i = 0; i < number; i++)
			{				
				cChannel *newChannel =  getChannel(i);
				if (mData->mPortalmode == 0)
				{
					if(i < 9)
						asprintf(&buffer,"%d   %s", i + 1, newChannel->Name());
					else
						asprintf(&buffer,"%d %s", i + 1, newChannel->Name());
				}
				else
				{
					if (i == 0)
                  asprintf(&buffer,"     %s", newChannel->Name());
					else if (i < 10)
						asprintf(&buffer,"%d   %s", i, newChannel->Name());
					else
						asprintf(&buffer,"%d %s", i, newChannel->Name());
				}
				if (current == i)
					osd->DrawText(7, y, buffer, clrBlack, bgColor, font);
				else
					osd->DrawText(7, y, buffer, lightgrey, bgColor, font);
				y += theHeigth;
			}
			drawRect(0, 0, gr_width, m_height, clrWhite);
			osd->Flush();
		}
		
		free(buffer);
	}
}

void cDirectorOsd::drawRect(int x, int y, int width, int height, tColor colorvalue)
{
	if (osd)
	{
		osd->DrawRectangle(x, y, 1, height, colorvalue);//-
		osd->DrawRectangle(x, y, width, 1, colorvalue); //|
		osd->DrawRectangle(width - 1, y, width, height, colorvalue);
		osd->DrawRectangle(x, height - 1, width, height, colorvalue);
	}
}

