/*
 * Least Cost Routing plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */

#include <ctype.h>
#include "lcr.h"
#include "lcrosd.h"

#define CHANNELINPUT_TIMEOUT      Setup.ZapTimeout * 1000 // in millisecs
#define OSDHEIGHT                 lcrConfig.osdheight     // in pixels
#define OSDWIDTH                  600                     // in pixels
#define OSDROWHEIGHT              m_Font->Height()        // in pixels
#define OSDLCRHEIGHT              (OSDROWHEIGHT * 10)     // in pixels (10 rows)
#define OSDSPACING                5
#define OSDCORNERING              10
#define OSDWIN_Y(offset)          offset
#define OSDWIN_X(col)             ((col == 7) ? 475 : (col == 6) ? 460 : (col == 5) ? 275 : (col == 4) ? 280 : (col == 3) ? 150 : (col == 2) ? 70 : 16)
#define INITIAL_OFFSET            OSDROWHEIGHT + 5
#define LOGO_FRAME_WIDTH          4
#define DISPLAYABLE_ENTRIES       7

#include "symbols/logo2.xpm"
cBitmap cLcrOsd::bmLogo(logo_xpm);

cLcrOsd::cLcrOsd(void) : cOsdObject(true), cThread("lcr osd")
{
  Dprintf("%s()\n", __PRETTY_FUNCTION__);
  m_Osd = NULL;
  m_Active = false;
  m_Number = 0;
  m_OldNumber = 0;
  memset(rates, 0, LOADABLE_DATA_ENTRIES * 50 * 100);
  firstRun = true;
  displayWindowNr = -1;
  snprintf( fileName, sizeof(fileName), XQUOTE(RATES_FILE_NAME), displayWindowNr );

  inc = 4;
  logoOffset = 3;
  m_InputTime.Set(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);
  }
  
  cLcrOsd::resetServiceData();

  selectedData = lcrConfig.preferredEntry;
  entriesNr = 0;
}

cLcrOsd::~cLcrOsd(void)
{
  Dprintf("%s()\n", __PRETTY_FUNCTION__);
  if (m_Active)
  {
    m_Active = false;
    Cancel(3);
  }
  if (m_Osd)
  {
    delete m_Osd;
  }
  
  cLcrOsd::resetServiceData();
}

void cLcrOsd::DrawWindow(void)
{   
  Dprintf("%s()\n", __PRETTY_FUNCTION__);
  
  cMutexLock lock(m_Mutex);
  int offset = 0;
  // (lcrConfig.theme == 0) = classic
  int fontColor = (lcrConfig.theme != 0) ? lcrTheme[lcrConfig.theme].clrInactiveText : lcrTheme[lcrConfig.theme].clrTitleBackground;

  cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());

  if (m_Osd)
  {
    m_Osd->DrawRectangle(0, OSDWIN_Y(offset), OSDWIDTH, OSDWIN_Y(offset+OSDROWHEIGHT-1), lcrTheme[lcrConfig.theme].clrTitleBackground);
    snprintf(buf, sizeof(buf), "%s", tr(MAINMENUENTRY));
    m_Osd->DrawText(OSDWIN_X(1), OSDWIN_Y(offset), buf, lcrTheme[lcrConfig.theme].clrTitleText, lcrTheme[lcrConfig.theme].clrTitleBackground, m_Font);
    m_Osd->DrawEllipse(0, OSDWIN_Y(0), OSDCORNERING, OSDWIN_Y(OSDCORNERING), clrTransparent, -2);
    m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), OSDWIN_Y(0), OSDWIDTH, OSDWIN_Y(OSDCORNERING), clrTransparent, -1);

    offset = INITIAL_OFFSET; // looks nicer
    
    if ( !firstRun )
    {
        // Rectangle around the logo
        if ( lcrConfig.logoFrame )
        {
          int frameWidth = LOGO_FRAME_WIDTH;
          m_Osd->DrawRectangle(OSDWIN_X(0)-frameWidth, OSDWIN_Y(0) + offset + logoOffset - frameWidth, OSDWIN_X(0) + bmLogo.Width()+frameWidth, OSDWIN_Y(0)+ offset + logoOffset + bmLogo.Height()+frameWidth, lcrTheme[lcrConfig.theme].clrTitleBackground);
        }
        // Draw the logo
        m_Osd->DrawBitmap( OSDWIN_X(0), OSDWIN_Y(0) + offset + logoOffset, bmLogo );     
    }

    // just display a message that data is being loaded
    if (rates[displayWindowNr+1][0][0] == 0)
    {
      offset += OSDROWHEIGHT*3;
      snprintf(buf, sizeof(buf), "%s ...", tr("Loading tariff data"));
      m_Osd->DrawText(OSDWIN_X(4), OSDWIN_Y(offset), buf, lcrTheme[lcrConfig.theme].clrInactiveText, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
      offset += OSDROWHEIGHT*2;
      snprintf(buf, sizeof(buf), "%s:", tr("Source"));
      m_Osd->DrawText(OSDWIN_X(0), OSDWIN_Y(offset), buf, lcrTheme[lcrConfig.theme].clrInactiveText, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
      offset += OSDROWHEIGHT;
      snprintf(buf, sizeof(buf), "%s", SOURCE);
      m_Osd->DrawText(OSDWIN_X(0), OSDWIN_Y(offset), buf, lcrTheme[lcrConfig.theme].clrInactiveText, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
      m_Osd->Flush();

//      esyslog( "%s: Cannot open rates-file yet: %s\n", PLUGIN_NAME_I18N, fileName );
      return;
    }
    
    // clear the text "Loading tariff data" from OSD
    offset += OSDROWHEIGHT*3;
    snprintf(buf, sizeof(buf), "%s ...", tr("Loading tariff data"));
    m_Osd->DrawText(OSDWIN_X(4), OSDWIN_Y(offset), buf, lcrTheme[lcrConfig.theme].clrBackground, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
    
    
    offset = INITIAL_OFFSET; // looks nicer
    
    cReadLine rl = cReadLine();
    entriesNr = 0;
    // get rates-data line by line
    for ( int i=0; i<DISPLAYABLE_ENTRIES; i++ )
    {
      if ( rates[displayWindowNr+1][i*3][0] == 0 ) // EOF reached prematurely
      {
      	break;
      }
    
      if ( lcrConfig.highlightEntry == 1 )
      {
          if ( i == selectedData )
          {
            fontColor = (lcrConfig.theme == 0) ? lcrTheme[lcrConfig.theme].clrTitleBackground : lcrTheme[lcrConfig.theme].clrInactiveText;
          }
          else
          {
            fontColor = (lcrConfig.theme != 0) ? lcrTheme[lcrConfig.theme].clrTitleBackground : lcrTheme[lcrConfig.theme].clrInactiveText;
          }
      }
      
      if ( displayWindowNr == -1 ) // the start-screen
      {
          destinationData[i] = cString::sprintf( "%s", rates[displayWindowNr+1][i*4] );
          snprintf(buf, sizeof(buf), "%s: %s", (const char *)destinationData[i], rates[displayWindowNr+1][i*4+1]);

          destinationData[i] = cString::sprintf( "%s", buf );
          m_Osd->DrawText(OSDWIN_X(3), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
          snprintf(buf, sizeof(buf), "%s: %s", tr("Price"), rates[displayWindowNr+1][i*4+2]);          
          priceData[i] = cString::sprintf( "%s", buf );
          m_Osd->DrawText(OSDWIN_X(4), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
          snprintf(buf, sizeof(buf), "%s: %s", tr("Pulse"), rates[displayWindowNr+1][i*4+3]);
          pulseData[i] = cString::sprintf( "%s", buf );
          m_Osd->DrawText(OSDWIN_X(6), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);     
          offset += OSDROWHEIGHT;
          
          entriesNr++;
      }
      else // detailed view for one destination
      {
          destinationData[i] = cString::sprintf( "%s", rates[displayWindowNr+1][i*3] );
          snprintf(buf, sizeof(buf), "%s: %s", tr("Prefix"), rates[displayWindowNr+1][i*3]);
          destinationData[i] = cString::sprintf( "%s", buf );
          m_Osd->DrawText(OSDWIN_X(3), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
          snprintf(buf, sizeof(buf), "%s: %s/Min.", tr("Price"), rates[displayWindowNr+1][i*3+1]);
          priceData[i] = cString::sprintf( "%s", buf );
          m_Osd->DrawText(OSDWIN_X(4), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
          snprintf(buf, sizeof(buf), "%s: %s", tr("Pulse"), rates[displayWindowNr+1][i*3+2]);          
          pulseData[i] = cString::sprintf( "%s", buf );
          m_Osd->DrawText(OSDWIN_X(6), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);     
          offset += OSDROWHEIGHT;
          
          entriesNr++;
      }
    }
    
    if ( displayWindowNr != -1 ) // display the destination's name (highlighted)
    {
        fontColor = (lcrConfig.theme == 0) ? lcrTheme[lcrConfig.theme].clrTitleBackground : lcrTheme[lcrConfig.theme].clrInactiveText;
        offset += OSDROWHEIGHT;
        if (displayWindowNr >= 10)
	  snprintf(buf, sizeof(buf), "%s: %s", tr("Top-5 for"), tr(destinationNames[displayWindowNr-10]));
	else
	  snprintf(buf, sizeof(buf), "%s: %s", tr("Top-5 for"), tr(destinationNames[lcrConfig.destination[displayWindowNr]]));
        m_Osd->DrawText(OSDWIN_X(4), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
    }
    
    if ( lcrConfig.highlightEntry == 1 )
    {
        // reset the font color
        fontColor = (lcrConfig.theme == 0) ? lcrTheme[lcrConfig.theme].clrTitleBackground : lcrTheme[lcrConfig.theme].clrInactiveText;    
    }
    
	// step back to be able to draw the text below the logo 
	offset = 5*OSDROWHEIGHT + INITIAL_OFFSET;
    if ( !firstRun )
    {
        m_Osd->DrawRectangle(0, OSDWIN_Y(OSDLCRHEIGHT-OSDROWHEIGHT-inc), OSDWIDTH, OSDWIN_Y(OSDLCRHEIGHT-inc), lcrTheme[lcrConfig.theme].clrTitleBackground);
        snprintf(buf, sizeof(buf), "%s:", tr("Source"));
        m_Osd->DrawText(OSDWIN_X(0), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
        offset += OSDROWHEIGHT;
        snprintf(buf, sizeof(buf), "%s", SOURCE);
        m_Osd->DrawText(OSDWIN_X(0), OSDWIN_Y(offset), buf, fontColor, lcrTheme[lcrConfig.theme].clrBackground, m_Font);
        snprintf(buf, sizeof(buf), "%d%s %s", m_Number ? m_Number : channel->Number(), m_Number ? "-" : "", channel->ShortName(true));
        m_Osd->DrawText(OSDWIN_X(1), OSDWIN_Y(OSDLCRHEIGHT-OSDROWHEIGHT-inc), buf, lcrTheme[lcrConfig.theme].clrInactiveText, lcrTheme[lcrConfig.theme].clrTitleBackground, m_Font);
        m_Osd->DrawEllipse(0, OSDWIN_Y(OSDLCRHEIGHT-OSDCORNERING-inc), OSDCORNERING, OSDWIN_Y(OSDLCRHEIGHT-inc), clrTransparent, -3);
        m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), OSDWIN_Y(OSDLCRHEIGHT-OSDCORNERING-inc), OSDWIDTH, OSDWIN_Y(OSDLCRHEIGHT-inc), clrTransparent, -4);
    }        
    m_Osd->Flush();
    
    // announce current line as currently running for lcdproc and others
    // with the service-function the output is a bit nicer (shorter), since the time is dropped and thus
    // the space for the time can be used more sensible.
    if ( lcrConfig.otherDisplays == 1 )
    {
        time_t timeNow = time(NULL);
        struct tm *timeCurrent = localtime(&timeNow);
        snprintf(buf, sizeof(buf), "%s | %s", (const char*)priceData[selectedData], (const char*)pulseData[selectedData]);
        cStatus::MsgOsdProgramme(mktime(timeCurrent), destinationData[selectedData], buf, 0, NULL, NULL);
    }
  }
}

void cLcrOsd::Action(void)
{
  Dprintf("%s()\n", __PRETTY_FUNCTION__);
  cTimeMs t;
  m_Active = false;
   
  {
    m_Active = true;
    cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
    while (m_Active)
    {
      t.Set(0);
      int offset = 0;
      char buf[128];

      int j = 0;
      int i;

      for ( i=OSDROWHEIGHT; i<OSDWIN_Y(OSDLCRHEIGHT-OSDROWHEIGHT); i += inc )
      {
        if ( !lcrConfig.zoomIn || !firstRun ) // set to final values to display the same as
                                 // if zoom-in had finished
        {
          i = OSDWIN_Y(OSDLCRHEIGHT-OSDROWHEIGHT-inc);
          j = (OSDWIDTH-OSDWIN_Y(0))/2;       	  
        }

        m_Osd->DrawRectangle(0, OSDWIN_Y(OSDROWHEIGHT), OSDWIDTH, OSDWIN_Y(OSDLCRHEIGHT-OSDROWHEIGHT), clrTransparent);
        m_Osd->DrawRectangle( (OSDWIDTH-OSDWIN_Y(0))/2-j, OSDWIN_Y(OSDROWHEIGHT), (OSDWIDTH-OSDWIN_Y(0))/2+j, i, lcrTheme[lcrConfig.theme].clrBackground);
        
        m_Osd->DrawRectangle(0, OSDWIN_Y(offset), OSDWIDTH, OSDWIN_Y(offset+OSDROWHEIGHT-1), lcrTheme[lcrConfig.theme].clrTitleBackground);
        m_Osd->DrawText(OSDWIN_X(1), OSDWIN_Y(offset), tr(MAINMENUENTRY), lcrTheme[lcrConfig.theme].clrTitleText, lcrTheme[lcrConfig.theme].clrTitleBackground, m_Font);
        m_Osd->DrawEllipse(0, OSDWIN_Y(0), OSDCORNERING, OSDWIN_Y(OSDCORNERING), clrTransparent, -2);
        m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), OSDWIN_Y(0), OSDWIDTH, OSDWIN_Y(OSDCORNERING), clrTransparent, -1);                   
                       
       	m_Osd->DrawRectangle(0, i, OSDWIDTH, i + OSDROWHEIGHT, lcrTheme[lcrConfig.theme].clrTitleBackground);
        snprintf(buf, sizeof(buf), "%d%s %s", m_Number ? m_Number : channel->Number(), m_Number ? "-" : "", channel->ShortName(true));
        m_Osd->DrawText(OSDWIN_X(1), i, buf, lcrTheme[lcrConfig.theme].clrInactiveText, lcrTheme[lcrConfig.theme].clrTitleBackground, m_Font);
        m_Osd->DrawEllipse(0, i+OSDROWHEIGHT-OSDCORNERING, OSDCORNERING, i + OSDROWHEIGHT, clrTransparent, -3);
        m_Osd->DrawEllipse((OSDWIDTH-OSDCORNERING), i+OSDROWHEIGHT-OSDCORNERING, OSDWIDTH, i + OSDROWHEIGHT, clrTransparent, -4);
        m_Osd->Flush();
        
        if ( !lcrConfig.zoomIn )
        {
          break;
        }
        else
        {
          if ( !firstRun )
            break;
          // with a PIII 1,2GHz this works fine
          cCondWait::SleepMs(50 * lcrConfig.updateinterval - t.Elapsed());
          if ( j < OSDWIDTH-OSDROWHEIGHT )
          {
            j += 7;
          }
          else
          {
            j = OSDWIDTH;
          }
        }
      }
      m_Active = false;
      firstRun = false;
    }
  }
  DrawWindow();
}

void cLcrOsd::Show(void)
{
  Dprintf("%s()\n", __PRETTY_FUNCTION__);

  m_Osd = cOsdProvider::NewOsd(((Setup.OSDWidth - OSDWIDTH) / 2) + Setup.OSDLeft + lcrConfig.osdoffsetX, ((Setup.OSDHeight - OSDHEIGHT) / 2) + Setup.OSDTop + lcrConfig.osdoffsetY);  
  /**
   * Conditions for areas (depending color depth):
   * 8 bit: no restrictions
   * 4 bit: width % 2 == 0
   * 2 bit: width % 4 == 0
   * 1 bit: width % 8 == 0
   */
  if (m_Osd)
  {
	  eOsdError result;
  	// for 4MB-cards
    tArea Areas1[] = { { 0, 0, OSDWIDTH, OSDHEIGHT, 4 } }; //4
    result = m_Osd->CanHandleAreas(Areas1, sizeof(Areas1) / sizeof(tArea));
    if ( result == oeOk)
    {
      m_Osd->SetAreas(Areas1, sizeof(Areas1) / sizeof(tArea));
    }
    else
    { // for 2MB-cards
      tArea Areas2[] = { { 0, OSDWIN_Y(0), (OSDWIDTH-1), OSDWIN_Y(OSDLCRHEIGHT-1), 4 } };
      result = m_Osd->CanHandleAreas(Areas2, sizeof(Areas2) / sizeof(tArea));
      if ( result == oeOk)
      {
        m_Osd->SetAreas(Areas2, sizeof(Areas2) / sizeof(tArea));
      }
      else // for DXR3s ??? (the minimum - which surprisingly looks the same as on my 2MB card, although
	       // the color depth is less - 2bit instead of 4bit)
      {      
        tArea Areas3[] = { { 0, OSDWIN_Y(0), (OSDWIDTH-1), OSDWIN_Y(OSDLCRHEIGHT-1), 2 } }; //could not believe that it's that simple
        result = m_Osd->CanHandleAreas(Areas3, sizeof(Areas3) / sizeof(tArea));
        if ( result != oeOk)
        {
            esyslog("%s: OSD open failed! Can't handle areas (%d)\n", PLUGIN_NAME_I18N, result);
        }
        else
        {
            m_Osd->SetAreas(Areas3, sizeof(Areas3) / sizeof(tArea));
        }
      }
    }
    m_Osd->DrawRectangle(0, OSDWIN_Y(0), OSDWIDTH, OSDWIN_Y(OSDLCRHEIGHT), clrTransparent);
    m_Osd->Flush();

    /** First start the thread (pseudo-thread just to manage the zoom-in effect) */
    Start();
    
    /** Concurrently get the required data */
    cLcrOsd::getData();
  }
}

inline void cLcrOsd::resetServiceData()
{
    int i;
    for ( i=0; i<DISPLAYABLE_ENTRIES; i++ )
    {
        destinationData[i] = "---";
        priceData[i] = "---";
        pulseData[i] = "---";
    }
}

inline void cLcrOsd::getData()
{
    cLcrOsd::resetServiceData();
    
    if ( rates[displayWindowNr+1][0][0] == 0 )        
    {
        /** Then (in background, because the thread is running simultaneously) grab
         *  the data from the web. */
        if ( displayWindowNr == -1 )
            snprintf(buf, sizeof(buf), "%s", retrievalScript );                  
        else if (displayWindowNr >= 10 ) 
            snprintf(buf, sizeof(buf), "%s \"%s\"", retrievalScript, destinationUrlNames[displayWindowNr-10] );
        else
            snprintf(buf, sizeof(buf), "%s \"%s\"", retrievalScript, destinationUrlNames[lcrConfig.destination[displayWindowNr]] );                
    
        FILE *content = popen(buf, "r");
        cReadLine rl = cReadLine();
        int lineCount = 0;
        char *line = NULL;
        do {
          line = rl.Read(content);
          if (line) strcpy(rates[displayWindowNr+1][lineCount], line);
           lineCount++;
        } while (line != NULL);
    }
}

eOSState cLcrOsd::ProcessKey(eKeys Key)
{
  eOSState state = cOsdObject::ProcessKey(Key);
  if (state == osUnknown)
  {
    switch (Key) {

      case k0 ... k9:
            if ( displayWindowNr == Key - k0 ) // the same as already is being displayed
                break;
            Start();
            displayWindowNr = Key - k0;
            if (lcrConfig.destination[displayWindowNr] < 7)
              displayWindowNr += 9;
            selectedData = 0;
            cLcrOsd::getData();
            DrawWindow();
            break;
// TODO: if I have the leisure to make dis-/enabling of this in setup, I might want to reuse this code
/*      case k0:
           if ((m_Number == 0) && (m_OldNumber != 0)) {
             m_Number = m_OldNumber;
             m_OldNumber = cDevice::CurrentChannel();
             Channels.SwitchTo(m_Number);
             m_Number = 0;
             DrawWindow();
             return osContinue;
           }
      case k1 ... k9:
          if (m_Number >= 0)
          {
            m_Number = m_Number * 10 + Key - k0;
            if (m_Number > 0)
            {
              DrawWindow();
              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;
              }
            }
          }
          DrawWindow();
          break;
*/
      case kBack:
           if ( displayWindowNr >= 0 )
           {
                if ( displayWindowNr >= 10 )
                    selectedData = displayWindowNr - 10;
                Start();
                displayWindowNr = -1;
                cLcrOsd::getData();
           } 
           else
                return osEnd;
      case kNone:
           if (m_Number && ((int)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;
             }               
           }
           if ( !m_Active && m_Number == 0 && m_OldNumber != cDevice::CurrentChannel() )
           {
             DrawWindow();
           }
           break;
      case kOk:
    	   if ( lcrConfig.highlightEntry == 1 && displayWindowNr == -1)
           {
                Start();
                displayWindowNr = selectedData+10;
                selectedData = 0;
                cLcrOsd::getData();
                DrawWindow();
	       }
	       else
	       {
                return osEnd;
           }
           break;
      case kUp|k_Repeat:
      case kUp:
           if (entriesNr > 0) {
               selectedData = (selectedData == 0) ? entriesNr-1 : (selectedData-1)%(entriesNr);
               DrawWindow();
           }
           break;
      case kDown|k_Repeat:
      case kDown:
          if (entriesNr > 0) {
               selectedData = (selectedData == entriesNr-1) ? 0 : (selectedData+1)%(entriesNr);
               DrawWindow();
          }
           break;
      default:
           break;
      }
    state = osContinue;
  }
  return state;
}

void cLcrOsd::getServiceData( LcrService_v1_0 *data )
{
    if ( data != NULL && (const char*)(destinationData[selectedData]) != NULL && selectedData < entriesNr )
    {
        data->destination = cString::sprintf( "%s", (const char*)destinationData[selectedData] );
        data->price = cString::sprintf( "%s", (const char*)priceData[selectedData] );
        data->pulse = cString::sprintf( "%s", (const char*)pulseData[selectedData] );
//        isyslog("%s: Service: %s = %s\n", PLUGIN_NAME_I18N, (const char*)destinationData[selectedData], (const char*)data->destination);
    }
}

