/*
 * $Id: pimOsdMenu.c,v 1.1.1.1 2005/02/17 05:45:53 sundin Exp $
 *
 * Tag: $Name:  $
 *
 * See the file COPYRIGHT for copyright information
 *
 * $Log: pimOsdMenu.c,v $
 * Revision 1.1.1.1  2005/02/17 05:45:53  sundin
 * initial import ver0.0.5
 *
 * Revision 1.2  2005/01/17 18:30:28  ksltuf
 * fix for gcc 3.4
 *
 * Revision 1.1.1.1  2005/01/17 18:06:31  ksltuf
 * PIM-Plugin 0.0.4
 *
 * Revision 1.5  2004/11/24 21:29:51  ksltuf
 * Changed order of include-Statements - VDR-includes come last
 * (problems with STL under gcc 2.95)
 *
 * Revision 1.4  2004/08/09 17:45:24  ksltuf
 * repeat events for cursor
 *
 * Revision 1.3  2004/07/05 19:26:41  ksltuf
 * removed unused variable weekFont
 *
 * Revision 1.2  2004/07/05 19:00:26  ksltuf
 * Added COPYRIGHT and cvs information
 *
 *
 */



#include "pimOsdMenu.h"
#include "pimSetup.h"
#include "calEvent.h"
#include "calEvents.h"
#include "calendar.h"
#include "calManager.h"
#include "i18n.h"

#include <vdr/config.h>
#include <vdr/osd.h>
#include <vdr/osdbase.h>


cPimOsdMenu::cPimOsdMenu()
{
  osd = NULL;
  list = NULL;

  cursorX = 0;
  cursorY = 0;

#if VDRVERSNUM >= 10307
  int maxWidth  = Setup.OSDWidth;
  int maxHeight = Setup.OSDHeight;
#else
  int maxWidth  = Setup.OSDwidth  * cOsd::CellWidth();
  int maxHeight = Setup.OSDheight * cOsd::LineHeight();
#endif

  // size of our OSD
  myW = min (352, maxWidth);
  myH = min (450, maxHeight);

  // start point (left upper corner) of our osd on the screen
  startX = (maxWidth  - myW) / 2 + globalSetup.osdOffsetX;
  startY = (maxHeight - myH) / 2 + globalSetup.osdOffsetY;

  // step size for calendar columns and rows
  stepX = myW / 7; // TODO: 8 if we want to draw week number
  stepY = myH / 9;

  // start point for drawing text (calendar entrys)
  offsetX = 10;
  offsetY = 10 + 2 * stepY;  // skip headers (3 lines)

  maxX = 6; // day per week 0 ... 6 , i.e. columns
  maxY = 5; // max. weeks per month  0 ... 5 , i.e. rows

}

cPimOsdMenu::~cPimOsdMenu()
{
  if (osd)  DELETENULL(osd);
  if (list) DELETENULL(list);
}


tMyColor cPimOsdMenu::getInversColor (tMyColor c, bool cursor)
{
  tMyColor n;
  switch (c)
  {
    case clrRed         : n = cursor ? clrBlack : clrWhite; break;
    case clrMagenta     : n = cursor ? clrBlack : clrWhite; break;
    case clrGreen       : n = cursor ? clrBlack : clrWhite; break;
    case clrYellow      : n = cursor ? clrBlack : clrWhite; break;
    case clrBlue        : n = cursor ? clrBlack : clrWhite; break;
    case clrWhite       : n = clrBlack; break;
    case clrBlack       : n = clrWhite; break;
    default             : n = clrWhite; break;
  }
  return n;
}


tMyColor cPimOsdMenu::getColorForDay (int day, int month,
	                              int year, int dayOfWeek, bool cursor)
{

  if ( isToday(day) )

    col = clrMagenta;

  else if ( cCalManager::getInstance()->hasEvent(day, month, year, dayOfWeek) )

    col= clrGreen;

  else

    col = cursor ? clrWhite:(dayOfWeek==6 || dayOfWeek==7) ? clrBlue : clrBlack;

  return col;
}


void cPimOsdMenu::showCursor(eKeys key)
{

  char buf[30];

  // old position
  int xPos = offsetX + cursorX*stepX;
  int yPos = offsetY + cursorY*stepY;

  // get old entry
  if (_cal[cursorY][cursorX] != 0)
     sprintf (buf, "%2d ", _cal[cursorY][cursorX]);
  else
     sprintf (buf, "   ");

  // get old color
  col = getColorForDay(_cal[cursorY][cursorX],
		       _cal.getMonth(), _cal.getYear(), cursorX+1);

  // draw old entry
  drawText(xPos, yPos, buf, col, getInversColor(col));

  switch (key)
  {
    case kUp:
	     cursorY--; break;
    case kDown:
	     cursorY++; break;
    case kLeft:
	     cursorX--; break;
    case kRight:
	     cursorX++; break;
    default:
	     return;
  }

  // overflow
  if (cursorX < 0)    { cursorX = maxX; cursorY--;} 
  if (cursorX > maxX) { cursorX = 0; cursorY++;}
  if (cursorY < 0)    cursorY = maxY;
  if (cursorY > maxY) cursorY = 0;

  if (_cal[cursorY][cursorX] == 0 && cursorY == maxY && key == kRight
      ||
      // this happens after overflow, if last day in month is a sunday
      cursorY == 0 && cursorX == 0 && key == kRight)
  {
    // last day in last line -> show first day of next month
    cursorX = cursorY = 0;
    _cal.increaseMonth();
    showCalendar (_cal);
    return;
  }
  else if (_cal[cursorY][cursorX] == 0 && cursorY == 0 && key == kLeft
           ||
	   // this happens after overflow, if first day in month is a monday
           cursorY == maxY && cursorX == maxX && key == kLeft)
  {
    // first day in first line -> show last day of previous month
    cursorX = maxX;
    cursorY = maxY;
    _cal.decreaseMonth();
    showCalendar (_cal);
    return;
  }
  else if (_cal[cursorY][cursorX] == 0 && key != kOk)
  {
    // empty entry -> repeat event
    showCursor(key);
    return;
  }
  else
  {
    // new position
    xPos = offsetX + cursorX*stepX;
    yPos = offsetY + cursorY*stepY;

    // show new entry
    sprintf (buf, "%2d ", _cal[cursorY][cursorX]);

    col = getColorForDay(_cal[cursorY][cursorX], _cal.getMonth(),
	                 _cal.getYear(), cursorX+1, true);

    drawText(xPos, yPos, buf, col, getInversColor(col, true));
  }

  osd->Flush();
  
}


void cPimOsdMenu::showEventsForDay(cCalendar& c)
{

  // get entry
  int day = c[cursorY][cursorX];

  if (day == 0)
     return;

  if ( cCalManager::getInstance()->hasEvent(day, c.getMonth(), 
			                    c.getYear(), cursorX+1) )
  {
     // close the main calendar osd and show a submenu containing
     // all events for the marked day
     osd->Flush();
     DELETENULL(osd);

     list = new cEventListMenu(day, c.getMonth(), c.getYear(), cursorX+1);

     list->Display();
  }
}
  

void cPimOsdMenu::showAllEvents()
{

  // close the main calendar osd and show a submenu containing
  // all events for the marked day
  osd->Flush();
  DELETENULL(osd);

  list = new cEventListMenu();

  list->Display();
}
  

void cPimOsdMenu::showCalendar(cCalendar& c)
{
  
  char buf[30];

#if VDRVERSNUM >= 10300
  const cFont *f = cFont::GetFont(fontOsd);
#else
  cFont *f = new cFont(fontOsd);
#endif

  setFont(fontOsd);

  int xPos = offsetX;
  int yPos = offsetY;

  // background
  ///////////////////////////////////////////////
  drawRectangle(5, 5,       myW-5, stepY,     clrBlack);
  drawRectangle(5, stepY,   myW-5, stepY*2,   clrYellow);
  drawRectangle(5, stepY*2, myW-5, stepY*8,   clrWhite);

  // footer
  ///////////////////////////////////////////////
  int xb = (myW-10) / 4;
  int w, h;

  // red button
  w = f->Width(tr("Today"));
  h = f->Height(tr("Today"));
  drawRectangle(5, stepY*8, 5+xb, stepY*9-5, clrRed);
  drawText(5+(xb-w)/2, stepY*8 + (stepY-h)/2, tr("Today"), clrWhite, clrRed);

  // green button
  w = f->Width("-");
  h = f->Height("-");
  drawRectangle(5+xb, stepY*8, 5+2*xb, stepY*9-5, clrGreen);
  drawText(5+xb+(xb-w)/2, stepY*8 + (stepY-h)/2, "-", clrBlack, clrGreen);

  // yellow button
  w = f->Width("+");
  h = f->Height("+");
  drawRectangle(5+2*xb, stepY*8, 5+3*xb, stepY*9-5, clrYellow);
  drawText(5+2*xb+(xb-w)/2, stepY*8 + (stepY-h)/2, "+", clrBlack, clrYellow);

  // blue button
  w = f->Width(tr("List"));
  h = f->Height(tr("List"));
  drawRectangle(5+3*xb, stepY*8, myW-5, stepY*9-5, clrBlue);
  drawText(5+3*xb+(xb-w)/2, stepY*8 + (stepY-h)/2, tr("List"),clrWhite,clrBlue);


  // draw the header with month and year
  ///////////////////////////////////////////////
  sprintf (buf, "%d   %s", c.getYear(), c.getMonthAsText()); 
  drawText (offsetX+5,offsetY-2*stepY,buf,clrYellow,clrBlack);

  // weekdays in header
  for (int j=0; j <= maxX; j++)
    {
       // calculate position
       xPos = offsetX + j*stepX;
       yPos = offsetY - stepY;
       sprintf (buf, "%s ", c.getDayOfWeekAsText(j+1));
       drawText (xPos,yPos,buf,clrBlack,clrYellow);
    }

  // TODO: draw a column with calendar week number
  /******************************************************
  setFont(weekFont);
  for (int i=0; i <= maxY; i++)
  {
    // check if there are any days at all in this line
    if (i == 0 && c[0][maxX] == 0 ||
        i == maxY && c[maxY][0] == 0)
       continue;

    // calculate position
    xPos = offsetX - stepX;
    yPos = offsetY + i*stepY;
    drawText(xPos, yPos, "KW", clrBlack, clrWhite);
  }
  setFont(fontOsd);
  ******************************************************/

  for (int i=0; i <= maxY; i++)
     for (int j=0; j <= maxX; j++)
       {	
	 // calculate position
         xPos = offsetX + j*stepX;
         yPos = offsetY + i*stepY;

         col = getColorForDay(c[i][j], _cal.getMonth(), _cal.getYear(), j+1);

	 // skip empty days
         if (c[i][j] == 0)
           strcpy (buf, "  ");
	 else
           sprintf (buf, "%2d", c[i][j]);
         drawText(xPos, yPos, buf, col, getInversColor(col));
       }

  osd->Flush();

  showCursor(kOk);
}


bool cPimOsdMenu::isToday(const int day)
{
  return ( day == _cal.getTodayDay() &&
           _cal.getMonth() == _cal.getTodayMonth() &&
           _cal.getYear()  == _cal.getTodayYear() );
}


void cPimOsdMenu::Show(void)
{

#if VDRVERSNUM >= 10307
  osd = cOsdProvider::NewOsd(startX,startY);
  if (osd)
  {
    tArea Area = { 1, 1, myW, myH, 4 };

    if (osd->CanHandleAreas(&Area, 1) == oeOk)
       osd->SetAreas(&Area, 1);
    else
       esyslog ("PIM: OSD Open failed!\n");
  }
#else
  osd = cOsd::OpenRaw (startX, startY);
  if (osd)
  {
    osd->Create(1, 1, myW, myH, 4);
    osd->AddColor(clrBlack);
    osd->AddColor(clrRed);
    osd->AddColor(clrGreen);
    osd->AddColor(clrBlack);
    osd->AddColor(clrYellow);
    osd->AddColor(clrBlue);
    osd->AddColor(clrMagenta);
  }
#endif

  showCalendar(_cal);

}


eOSState cPimOsdMenu::ProcessKey(eKeys key)
{

  if (!osd && key == kBack)
  {
     // back was pressed in sub-menu -> if it has no sub-menu itself
     // then close it and show calendar-osd again
     if (list && !list->HasSubMenu())
     {
       DELETENULL(list);
       Show();
       return osContinue;
     }
  }

  if (list)
  {
    // give the control to our sub-menu
    return list->ProcessKey(key);
  }

  // process other events
  
  eOSState state = cOsdObject::ProcessKey(key);

  if (osd)
  switch (key & 0x7fff)   // repeat events
  {
	  case kOk:
		  // any events for this day?
		  showEventsForDay (_cal);
		  break;

	  case kRed:
		  // show actual month
		  _cal.reset();
		  showCalendar (_cal);
		  break;

	  case kGreen:
		  // show previous month
		  _cal.decreaseMonth();
		  showCalendar (_cal);
		  break;

	  case kYellow:
		  // show next month
		  _cal.increaseMonth();
		  showCalendar (_cal);
		  break;

	  case kBlue:
		  // show a list of all known events
		  showAllEvents();
		  break;

	  case kUp:
	  case kDown:	  
	  case kLeft:	  
	  case kRight:
	  	  // move the cursor
		  showCursor(key);
		  break;

	  case kBack:
		  // close calendar-osd
		  state=osEnd;

          default:
		  break;
  }

  return state;

}

