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

#include <ctype.h>
#include <stdlib.h>
#include "advchctrli18n.h"
#include "advchctrlcommon.h"
#include "advchctrlconfig.h"
#include "advchctrlsetup.h"
#include "advchctrlchannel.h"
#include "advchctrlosd.h"


#define CHANNELINPUT_TIMEOUT      1000

#define OSDHEIGHT                 advchctrlConfig.osdheight   // in pixels
#define OSDWIDTH                  advchctrlConfig.osdwidth    // in pixels
#define OSDROWHEIGHT              m_Font->Height()        // in pixels
#define OSDSTATUSHEIGHT           (OSDROWHEIGHT * 6)      // in pixels (6 rows)
#define OSDSPACING                5
#define OSDCORNERING              10

#define OSDSTATUSWIN_Y(offset)    (advchctrlConfig.osdposition ? offset : (OSDHEIGHT - OSDSTATUSHEIGHT + offset))
#define OSDSTATUSWIN_X(col)       ((col == 7) ? 475 : (col == 6) ? 410 : (col == 5) ? 275 : (col == 4) ? 220 : (col == 3) ? 125 : (col == 2) ? 70 : 15)
#define OSDSTATUSWIN_XSYMBOL(c,w) (c * ((OSDWIDTH - (5 * w)) / 6) + ((c - 1) * w))
#define OSDBARX2(offset, val, max)((int)(((double)(val) / (max)) * (OSDWIDTH - (offset)))+(offset))

// --- cAdvChCtrlOsd -------------------------------------------------------------


cAdvChCtrlOsd::cAdvChCtrlOsd(void)
:cOsdObject(true), cThread("advchctrl osd")
{
  DEBUGOSD("%s()\n", __PRETTY_FUNCTION__);
  m_Osd = NULL;
  m_Active = false;
  m_Number = 0;
   m_Mutex = new cMutex();
  if (Setup.UseSmallFont == 0) {
     // Dirty hack to force the small fonts...
     Setup.UseSmallFont = 1;
     m_Font = cFont::GetFont(fontSml);
     Setup.UseSmallFont = 0;
     }
  else
     m_Font = cFont::GetFont(fontSml);
}

cAdvChCtrlOsd::~cAdvChCtrlOsd(void)
{
  DEBUGOSD("%s()\n", __PRETTY_FUNCTION__);
  if (m_Active) {
     m_Active = false;
     Cancel(3);
     }
  //if (m_Receiver)
  //     delete m_Receiver;
  if (m_Osd)
     delete m_Osd;
}

void cAdvChCtrlOsd::DrawStatusWindow(void)
{
  cMutexLock lock(m_Mutex);
  char buf1[128];
  char buf2[128];
//int signal = 140;
  double barlength[2];
  int 	TextLength[2];
  int offset = 0;
  int TxtCol;

  cChannel *channel = Channels.GetByNumber(cDevice::PrimaryDevice()->CurrentChannel());
  int ChVolume = AdvChCtrlChannelsList.GetVolume(Channels.GetByNumber(cDevice::PrimaryDevice()->CurrentChannel())->GetChannelID());
  if (ChVolume < 0) ChVolume = advchctrlConfig.defaultvolume;
    if (m_Osd) {
	m_Osd->DrawRectangle(0, OSDSTATUSWIN_Y(0), OSDWIDTH, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT), advchctrlTheme[advchctrlConfig.theme].clrBackground);
	snprintf(buf1, sizeof(buf1), "%d%s %s", m_Number ? m_Number : channel->Number(), m_Number ? "-" : "", channel->ShortName(true));
	m_Osd->DrawRectangle(0, OSDSTATUSWIN_Y(offset), OSDWIDTH, OSDSTATUSWIN_Y(offset+OSDROWHEIGHT-1), advchctrlTheme[advchctrlConfig.theme].clrTitleBackground);
	m_Osd->DrawText(OSDSTATUSWIN_X(1), OSDSTATUSWIN_Y(offset), buf1, advchctrlTheme[advchctrlConfig.theme].clrTitleText, advchctrlTheme[advchctrlConfig.theme].clrTitleBackground, m_Font);
//	if (advchctrlConfig.theme == eThemeSTTNG)
//	{
//    	    m_Osd->DrawEllipse(0, OSDSTATUSWIN_Y(0), OSDCORNERING, OSDSTATUSWIN_Y(OSDCORNERING), clrTransparent,  -2);
//	    m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), OSDSTATUSWIN_Y(0), OSDWIDTH, OSDSTATUSWIN_Y(OSDCORNERING), clrTransparent, -1);
//	    m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), OSDSTATUSWIN_Y(0), OSDWIDTH, OSDSTATUSWIN_Y(OSDCORNERING), advchctrlTheme[advchctrlConfig.theme].clrTitleBackground, 1);
//	    m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), OSDSTATUSWIN_Y(0)+ OSDCORNERING+1, OSDWIDTH, OSDSTATUSWIN_Y((2*OSDCORNERING)), advchctrlTheme[advchctrlConfig.theme].clrTitleBackground, 4);
//	    m_Osd->DrawRectangle((OSDWIDTH-OSDCORNERING - 15), OSDSTATUSWIN_Y(0),(OSDWIDTH-OSDCORNERING-12), OSDSTATUSWIN_Y(offset+OSDROWHEIGHT-1), advchctrlTheme[advchctrlConfig.theme].clrTitleBackground);
//        }
        offset += OSDROWHEIGHT + 15;
        snprintf(buf1, sizeof(buf1), "%s", tr("Default volume"));
	snprintf(buf2, sizeof(buf2), "%s", tr("Channel volume"));
	TextLength[0] = m_Font->Width(buf1);
	TextLength[1] = m_Font->Width(buf2);
//	TxtCol = (advchctrlConfig.theme == eThemeSTTNG ? advchctrlTheme[advchctrlConfig.theme].clrTitleText: advchctrlTheme[advchctrlConfig.theme].clrInactiveText);
	TxtCol = advchctrlTheme[advchctrlConfig.theme].clrInactiveText;
	m_Osd->DrawRectangle(0, OSDSTATUSWIN_Y(offset),OSDSTATUSWIN_X(1)+max(TextLength[0],TextLength[1]) ,OSDSTATUSWIN_Y(offset)+(2*OSDROWHEIGHT), advchctrlTheme[advchctrlConfig.theme].clrMenuBackground); 
	m_Osd->DrawText(OSDSTATUSWIN_X(1), OSDSTATUSWIN_Y(offset), buf1, TxtCol, advchctrlTheme[advchctrlConfig.theme].clrMenuBackground, m_Font);
	m_Osd->DrawText(OSDSTATUSWIN_X(1), OSDSTATUSWIN_Y(offset)+OSDROWHEIGHT, buf2, TxtCol, advchctrlTheme[advchctrlConfig.theme].clrMenuBackground, m_Font);
	
	barlength[0] = OSDBARX2(2*OSDSTATUSWIN_X(1) + max(TextLength[0],TextLength[1]), (advchctrlConfig.defaultvolume), 255);
	// DEBUGOSD("signal:%d  offset:%d  barx2:%f Y(%d):%d", signal, OSDSTATUSWIN_X(1) + m_Font->Width(buf), barlength[0], offset, OSDSTATUSWIN_Y(offset));
	m_Osd->DrawRectangle(2*OSDSTATUSWIN_X(1) +  max(TextLength[0],TextLength[1]), OSDSTATUSWIN_Y(offset)+3,  (int)barlength[0], OSDSTATUSWIN_Y(offset)+OSDROWHEIGHT-3, advchctrlTheme[advchctrlConfig.theme].clrGreen);
	offset += OSDROWHEIGHT;
	barlength[1] = OSDBARX2(2*OSDSTATUSWIN_X(1) + max(TextLength[0],TextLength[1]), ChVolume, 255);
	//barlength = OSDBARX2(300, 85, 255);
//        m_Osd->DrawRectangle(OSDSTATUSWIN_X(1) +  m_Font->Width(buf), OSDSTATUSWIN_Y(offset+3),(int) barlength , OSDSTATUSWIN_Y(offset+OSDROWHEIGHT-3), advchctrlTheme[advchctrlConfig.theme].clrRed);
        m_Osd->DrawRectangle(2*OSDSTATUSWIN_X(1) + max(TextLength[0],TextLength[1]), OSDSTATUSWIN_Y(offset)+3,(int) barlength[1] , OSDSTATUSWIN_Y(offset)+OSDROWHEIGHT-3, advchctrlTheme[advchctrlConfig.theme].clrRed);
	//DEBUGOSD("signal:%d  offset:%d  barx2:%f  ChVolume:%d", signal, OSDSTATUSWIN_X(1) + max(TextLength[0],TextLength[1]), barlength[1], ChVolume);
     offset += OSDROWHEIGHT;

	m_Osd->DrawRectangle(0, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT)-OSDROWHEIGHT, OSDWIDTH, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT), advchctrlTheme[advchctrlConfig.theme].clrMenuBackground);
//	m_Osd->DrawRectangle(OSDSTATUSWIN_X(0), OSDSTATUSWIN_Y(OSDSTATUSHEIGHT)-OSDROWHEIGHT, OSDSTATUSWIN_X(0), OSDSTATUSWIN_Y(OSDSTATUSHEIGHT), advchctrlTheme[advchctrlConfig.theme].clrRed);
	m_Osd->DrawRectangle(OSDSTATUSWIN_X(0) + OSDWIDTH/4, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT)-OSDROWHEIGHT, OSDSTATUSWIN_X(0) + (2 * OSDWIDTH/4), OSDSTATUSWIN_Y(OSDSTATUSHEIGHT), advchctrlTheme[advchctrlConfig.theme].clrGreen);
	
        snprintf(buf1, sizeof(buf1), "%s", tr("Reset"));
	TextLength[0] = m_Font->Width(buf1);
	m_Osd->DrawText(OSDSTATUSWIN_X(0) + int(1.5 *OSDWIDTH/4)-TextLength[0]/2, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT)-OSDROWHEIGHT, buf1, advchctrlTheme[advchctrlConfig.theme].clrTitleText, advchctrlTheme[advchctrlConfig.theme].clrGreen, m_Font);
//	m_Osd->DrawRectangle(OSDSTATUSWIN_X(4), OSDSTATUSWIN_Y(OSDSTATUSHEIGHT)-OSDROWHEIGHT, OSDSTATUSWIN_X(5), OSDSTATUSWIN_Y(OSDSTATUSHEIGHT), advchctrlTheme[advchctrlConfig.theme].clrBlue);
	
	m_Osd->DrawEllipse(0, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT-OSDCORNERING), OSDCORNERING, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT), clrTransparent, -3);
     m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), OSDSTATUSWIN_Y(OSDSTATUSHEIGHT-OSDCORNERING), OSDWIDTH, OSDSTATUSWIN_Y(OSDSTATUSHEIGHT), clrTransparent, -4);
     m_Osd->Flush();
     }
}


void cAdvChCtrlOsd::Action(void)
{
    DEBUGOSD("%s()\n", __PRETTY_FUNCTION__);
    cTimeMs t;
    m_Active = true;
    while (m_Active) {
	t.Set(0);
	DrawStatusWindow();
	cCondWait::SleepMs(100 * advchctrlConfig.updateinterval - t.Elapsed());
    }
}

void cAdvChCtrlOsd::Show(void)
{
    DEBUGOSD("%s()\n", __PRETTY_FUNCTION__);

    m_Osd = cOsdProvider::NewOsd(((Setup.OSDWidth - OSDWIDTH) / 2) + Setup.OSDLeft + advchctrlConfig.osdoffset, ((Setup.OSDHeight - OSDHEIGHT) / 2) + Setup.OSDTop);
    if (m_Osd) {
	tArea Areas1[] = { { 0, 0, OSDWIDTH, OSDHEIGHT, 4 } };
	if (m_Osd->CanHandleAreas(Areas1, sizeof(Areas1) / sizeof(tArea)) == oeOk) 
	{
	    m_Osd->SetAreas(Areas1, sizeof(Areas1) / sizeof(tArea));
	} else 
	{
    	    tArea Areas2[] = { { 0, OSDSTATUSWIN_Y(0),          (OSDWIDTH-1), OSDSTATUSWIN_Y(OSDSTATUSHEIGHT-1), 4 } };//,
//                           { 0, OSDINFOWIN_Y(0),            (OSDWIDTH-1), OSDINFOWIN_Y(OSDROWHEIGHT-1),      4 },
//                           { 0, OSDINFOWIN_Y(OSDROWHEIGHT), (OSDWIDTH-1), OSDINFOWIN_Y(OSDINFOHEIGHT-1),     2 } };
    	    m_Osd->SetAreas(Areas2, sizeof(Areas2) / sizeof(tArea));
        }
        m_Osd->Flush();
        Start();
     }
}

void cAdvChCtrlOsd::ChannelSwitch(const cDevice * device, int channelNumber)
{
    DEBUGOSD("%s(%d,%d)\n", __PRETTY_FUNCTION__, device->DeviceNumber(), channelNumber);

    if (!device->IsPrimaryDevice() || !channelNumber || cDevice::PrimaryDevice()->CurrentChannel() != channelNumber)
	return;
}


eOSState  cAdvChCtrlOsd::ProcessKey(eKeys Key)
{ 
  eOSState state = cOsdObject::ProcessKey(Key);
  if (state == osUnknown) {
     switch (Key) {
       case k0:
            if ((m_Number == 0) && (m_OldNumber != 0)) {
               m_Number = m_OldNumber;
               m_OldNumber = cDevice::CurrentChannel();
               Channels.SwitchTo(m_Number);
               m_Number = 0;
               return osContinue;
               }
       case k1 ... k9:
            if (m_Number >= 0) {
               m_Number = m_Number * 10 + Key - k0;
               if (m_Number > 0) {
                  DrawStatusWindow();
                  cChannel *ch = Channels.GetByNumber(m_Number);
                  m_InputTime.Set(0);
                  // Lets see if there can be any useful further input:
                  int n = ch ? m_Number * 10 : 0;
                  while (ch && (ch = Channels.Next(ch)) != NULL) {
                        if (!ch->GroupSep()) {
                           if (n <= ch->Number() && ch->Number() <= n + 9) {
                              n = 0;
                              break;
                              }
                           if (ch->Number() > n)
                              n *= 10;
                           }
                        }
                  if (n > 0) {
                     // This channel is the only one that fits the input, so let's take it right away:
                     m_OldNumber = cDevice::CurrentChannel();
                     Channels.SwitchTo(m_Number);
                     m_Number = 0;
                     }
                  }
               }
            break;
       case kBack:
            return osEnd;
       case kGreen:
            {
		if (!(cDevice::PrimaryDevice()->IsMute()))
		    cDevice::PrimaryDevice()->SetVolume(advchctrlConfig.defaultvolume, 1);

            }
            break;
       case kYellow:
            break;
       case kRight:
       case kLeft:
            break;
       case kUp|k_Repeat:
       case kUp:
       case kDown|k_Repeat:
       case kDown:
            m_OldNumber = cDevice::CurrentChannel();
            cDevice::SwitchChannel(NORMALKEY(Key) == kUp ? 1 : -1);
            m_Number = 0;
            break;
       case kNone:
            if (m_Number && (m_InputTime.Elapsed() > CHANNELINPUT_TIMEOUT)) {
               if (Channels.GetByNumber(m_Number)) {
                  m_OldNumber = cDevice::CurrentChannel();
                  Channels.SwitchTo(m_Number);
                  m_Number = 0;
                  }
               else {
                  m_InputTime.Set(0);
                  m_Number = 0;
                  }
               }
            break;
       case kOk:
            // toggle between display modes
            //if (++m_DisplayMode == eFemonModeAC3 && !Channels.GetByNumber(cDevice::CurrentChannel())->Dpid(0)) m_DisplayMode++;
            //if (m_DisplayMode >= eFemonModeMaxNumber) m_DisplayMode = 0;
            //DrawInfoWindow();
            break;
       default:
            break;
       }
     state = osContinue;
  }
  return state;
}
