/*
* Image plugin to VDR (C++)
*
* (C) 2004-2005 Andreas Brachold <anbr at users.berlios.de>
* based on (C) 2003 Kai Tobias Burwieck <kai -at- burwieck.net>
*
* This code is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/

#include <time.h>

#include "control-image.h"
#include "data-image.h"
#include "setup-image.h"
#include "config.h"
#include "i18n.h"
#include "list.h"
#include "bitmap.h"
#include "parselog.h"

#include <vdr/status.h>
#include <vdr/tools.h>
#include <vdr/plugin.h>
#include <vdr/osd.h>

//////////////////////////////////////////////////////////////////////////////
/** C-tor Create for control-object to control the image-player
*/
cImageControl::cImageControl()
:cOsdObject()
{
  m_tStarted = time(NULL);
  m_bSlideShowActiv = CoverSetup.m_bSlideShow;

  coversize = 0;
  visible=false;
  CanLoadCover=false;
  osd = NULL;

  std::string datei;
  datei = configdir;
  datei = datei + "/downloads/music_cover/";

  if(CoverLog.ParseLog()) {
  
    cFileSource *src = new cFileSource(datei.c_str());

    cDirItem *item = new cDirItem(src);
    if(item) {
      cSlideShow *newss = new cSlideShow(item);
      if(newss->Load() && newss->Count()) {
        SetSlideShow(newss);
        }
      else {
        delete newss;  
      }

    delete item;
    }
    delete src;
  }
  else {
    esyslog("coverviewer: ERROR: Could not parse logfile. Aborting!");
  }    
}


void cImageControl::SetSlideShow(cSlideShow * pNewSlideShow)
{
  theSlideShow.Assign(pNewSlideShow);
}

//////////////////////////////////////////////////////////////////////////////
/** D-tor Destroy control-object to control the image-player
*/
cImageControl::~cImageControl()
{
  // Free OSD Data
  theSlideShow.Shutdown();
  Hide();
}

void cImageControl::Hide()
{
  if(osd) { delete osd; osd=NULL; }
  visible = false;
}


void cImageControl::Show()
{
  if (FileName()== NULL ) {
    esyslog("coverviewer : Oops can't load coverpicture : %s\n",FileName());
    }
  else {
    cCoverBitmap *coverbmp;

    bmpcolors=16;
    w1=120;
    h1=120;
    fh=27;
    fw=6;

    int tab;
    int w     =119;
    int h     =119;
    int depth =8;

    coversize=CoverSetup.Coversize;
    switch(coversize) {
          case 0:
	    bmpcolors = 248;
	    w1 = 120;
	    h1 = 120;
            depth = 8;
            w     = 119;
            h     = 119;
	    x1    = h1 -1;
	  break;  
	  case 1:  
	    bmpcolors = 248;
	    w1 = 274;
	    h1 = 274;
            depth = 8;
            w     = 273;
            h     = 273;
	    x1    = h1 -1;
	  break;
	  case 2:
	    bmpcolors = 248;
	    w1 = 300;
	    h1 = 256;
            depth = 8;
            w     = 299;
            h     = 255;
	    x1    = h1 -1;
	  break;
	  case 3:
	    bmpcolors = 248;
	    w1 = CoverSetup.max_osdwidth;
	    h1 = CoverSetup.max_osdheight;
            depth = 8;
            w     = CoverSetup.max_osdwidth -1;
            h     = CoverSetup.max_osdheight -1;
	    x1    = h1 -2*fh -2;
	  break;
    }	        

    if((coverbmp = cCoverBitmap::Load(FileName(), 255, x1, w1, bmpcolors)) !=NULL) {
      Hide();
    
      CanLoadCover=true;

      osd=cOsdProvider::NewOsd(CoverSetup.max_osdleft, CoverSetup.max_osdtop);

      if(!osd) return;

      tArea Area[] = {{ 0, 0, w, h, depth}, };
      eOsdError result = osd->CanHandleAreas(Area, sizeof(Area) / sizeof(Area));
      if (result == oeOk) {
        osd->SetAreas(Area, sizeof(Area) / sizeof(Area));
        }
      else {
        const char *errormsg = NULL;
        switch (result) {
          case oeTooManyAreas:
            errormsg = "Too many OSD areas"; break;
          case oeTooManyColors:
            errormsg = "Too many colors"; break;
          case oeBppNotSupported:
            errormsg = "Depth not supported"; break;
          case oeAreasOverlap:
            errormsg = "Areas are overlapped"; break;
          case oeWrongAlignment:
            errormsg = "Areas not correctly aligned"; break;
          case oeOutOfMemory:
            errormsg = "OSD memory overflow"; break;
          case oeUnknown:
            errormsg = "Unknown OSD error"; break;
          default:
            break;
        } 	

        esyslog("coverviewer: ERROR! OSD open failed! Can't handle areas (%d)-%s\n", result, errormsg);
        if(osd) { delete osd; osd=0; }
        return;
      }  
 
      if(CanLoadCover) {

        osd->GetBitmap(0)->SetColor(1, tColor(0xFF000000));
        osd->GetBitmap(0)->SetColor(0, tColor(0xFFFFFFFF));

        osd->DrawRectangle(0 , 0, w , h , osd->GetBitmap(0)->Color(0));

        if(coversize==3) {
          char *buf;
          asprintf(&buf, "%s %i %s %i",tr("Cover:"), ImageCurrent(), tr("of"), ImageTotal());
          osd->DrawText( 0, 1, buf , osd->GetBitmap(0)->Color(0), osd->GetBitmap(0)->Color(1), cFont::GetFont(fontSml), w1, fh, taCenter);
          free(buf);

          tab = w / 4;
  
          osd->DrawRectangle( 0, h -fh, w, h, osd->GetBitmap(0)->Color(1));

          osd->DrawEllipse( 14, h - fh +8, 26, h - fh +21, clrRed, 0);
          osd->DrawText(    34, h - fh, tr("Parent"), osd->GetBitmap(0)->Color(0), osd->GetBitmap(0)->Color(1), cFont::GetFont(fontSml), 20*fw, fh , taLeft);  

          osd->DrawEllipse( tab +8, h - fh +8, tab +20, h - fh +21, clrGreen, 0);
          osd->DrawText(    tab +28, h - fh, tr("Album"), osd->GetBitmap(0)->Color(0), osd->GetBitmap(0)->Color(1), cFont::GetFont(fontSml), 20*fw, fh , taLeft);  

          osd->DrawEllipse( 2*tab +8, h - fh +8, 2*tab +20, h - fh +21, clrYellow, 0);
          osd->DrawText(    2*tab +28, h - fh, tr("Trackname"), osd->GetBitmap(0)->Color(0), osd->GetBitmap(0)->Color(1), cFont::GetFont(fontSml), 20*fw, fh , taLeft);  

          osd->DrawEllipse( 3*tab +8, h - fh +8, 3*tab +20, h - fh +21, clrBlue, 0);
          osd->DrawText(    3*tab +28, h - fh, tr("Artist"), osd->GetBitmap(0)->Color(0), osd->GetBitmap(0)->Color(1), cFont::GetFont(fontSml), 20*fw, fh , taLeft);  

          osd->DrawBitmap( 0, fh +1, coverbmp->Get(), clrTransparent, clrTransparent, true);
          }
	else  
          osd->DrawBitmap( 0, 1, coverbmp->Get(), clrTransparent, clrTransparent, true);
	

        CanLoadCover = false;
        m_tStarted = time(NULL);

        if(CoverSetup.EnableFade) FadeIn(); else Flush();

      }

    }
    else delete coverbmp;

  }              

}


void cImageControl::FadeIn(void)
{
#if VDRVERSNUM >= 10500
  SetNeedsFastResponse(true);
#else
  needsFastResponse = true;
#endif

  int i;
  int alpha = 0;
  int fd = 15;
  int count = 0;
  
  while (!(fd==0)) {

    if(osd){
      count++;
      alpha = alpha + 16;

      if(alpha > 255) alpha = 0;


      osd->DrawRectangle(0, 0, w1-1, 1, osd->GetBitmap(0)->Color(1));
      osd->DrawRectangle(count, 0, count +1, 1, osd->GetBitmap(0)->Color(0));

      for ( i = 1; i < 256; i++) {
        osd->GetBitmap(0)->SetColor(i, (((osd->GetBitmap(0)->Color(i))<<8)>>8) | (alpha << 24));
      }
      Flush();
    }

    fd--;
  }

#if VDRVERSNUM >= 10500
  SetNeedsFastResponse(false);
#else
  needsFastResponse = false;
#endif
}


void cImageControl::FadeOut(void)
{
#if VDRVERSNUM >= 10500
  SetNeedsFastResponse(true);
#else
  needsFastResponse = true;
#endif

  int i;
  int alpha = 255;
  int fd = 16;
  int count = 0;
  
  while (!(fd==0)) {

    if(osd){
      count++;
    
      alpha = alpha - 16;
      if(alpha < 0) alpha = 0;

      osd->DrawRectangle(0, 0, w1-1, 1, osd->GetBitmap(0)->Color(1));
      osd->DrawRectangle(count, 0, count +1, 1, osd->GetBitmap(0)->Color(0));

      for ( i = 1; i < 256; i++) {
        osd->GetBitmap(0)->SetColor(i, (((osd->GetBitmap(0)->Color(i))<<8)>>8) | (alpha << 24));
      }
      Flush();
    }

    fd--;
  }

#if VDRVERSNUM >= 10500
  SetNeedsFastResponse(false);
#else
  needsFastResponse = false;
#endif
}




void cImageControl::Flush(void)
{
  if(osd) osd->Flush();
}  


//////////////////////////////////////////////////////////////////////////////
/** VDR-Callback entry for Key was processed
@return eOSState
@param eKeys Key - the processed Keycode
*/
eOSState cImageControl::ProcessKey(eKeys Key)
{
  // Check for next image
  SlideImage();

  eOSState state = cOsdObject::ProcessKey(Key);

  if(state==osUnknown) {
    switch(Key) {

         //processed global keybindings
         // Toggle between Play/Pause
         case kPlay:     
         case kPause:   ToogleSlideShowActiv();
                       break;

         // Stop Plugin
	 case kRed:
         case kBack:
         case kStop:     return osEnd;

         // Navigate between images
         case kUp:
         case kLeft:
	                if( ImageTotal() >1) {
		          PrevImage(1);
		          CanLoadCover = true;
		          Show();
		        }
		        break;
         case kDown:
         case kRight:
	                if( ImageTotal() >1) {
		          NextImage(1);
		          CanLoadCover = true;
		          Show();
		        }
		        break;
 
         case kOk:
	                break;

         case kGreen:   //Cover
	                CopyCover();
			return osEnd;
	                break;

	 case kYellow:  // Trackname
	                CopyTrack();
			return osEnd;
	                break;

         case kBlue:    // Coverdir
                        CopyArtist();
			return osEnd;
	                break;
 
         default: break;
    }

  state = osContinue;
  }

  return state;

}


void cImageControl::CopyCover(void)
{
  char *cmd;
  std::string datei;
  datei = CoverLog.log_basedir + "cover.jpg"; 
  asprintf(&cmd, "cp -f \"%s\"  \"%s\"", FileName(), datei.c_str());
  dsyslog("coverviewer: save as Album :Executing '%s'", cmd);
  system(cmd);
  free(cmd); 
}

void cImageControl::CopyTrack(void)
{
  char *cmd;
  std::string datei;
  datei = CoverLog.log_filename + "jpg";
  asprintf(&cmd, "cp -f \"%s\"  \"%s\"", FileName(), datei.c_str());
  dsyslog("coverviewer: save as Trackname: Executing '%s'", cmd);
  system(cmd);
  free(cmd); 
}

void cImageControl::CopyArtist(void)
{
  char *cmd;
  std::string datei;
  datei = CoverLog.log_coverdir + "/" + CoverLog.log_artist + ".jpg";
  asprintf(&cmd, "cp -f \"%s\"  \"%s\"", FileName(), datei.c_str());
  dsyslog("coverviewer: save as Artist: Executing '%s'", cmd);
  system(cmd);
  free(cmd); 
}

/*
    printf("ARTIST   ='%s'\n", CoverLog.log_artist.c_str());
    printf("ALBUM    ='%s'\n", CoverLog.log_album.c_str());
    printf("COVERDIR ='%s'\n", CoverLog.log_coverdir.c_str());
    printf("BASEDIR  ='%s'\n", CoverLog.log_basedir.c_str());
    printf("FILENAME ='%s'\n", CoverLog.log_filename.c_str());
*/



//////////////////////////////////////////////////////////////////////////////
/** Toogle between Play and Stop of the current SlideShow 
*/
void cImageControl::ToogleSlideShowActiv(void)
{
  m_bSlideShowActiv = !m_bSlideShowActiv;
}


//////////////////////////////////////////////////////////////////////////////
/** Check to get access for to viewed file
@return bool - false access was denied
*/
bool cImageControl::CheckAccess() const
{
  const char *szFileName = FileName();

  if(szFileName 
    && 0 == access(szFileName,F_OK))
  {
    return true;
  }        

  return false;
}


void cImageControl::OriginalImage(bool bCached)
{
  if(!CheckAccess())
  {
    esyslog("coverviewer: Operation failed");
  }
}



void cImageControl::NextImage(int Step)
{
//  m_bSlideShowActiv = m_bSlideShowBefore;
  theSlideShow.NextImage(Step);
  OriginalImage(true);
//  m_tStarted = time(NULL);
}

void cImageControl::PrevImage(int Step)
{
//  m_bSlideShowActiv = m_bSlideShowBefore;
  theSlideShow.PrevImage(Step);
  OriginalImage(true);
//  m_tStarted = time(NULL);
}

int cImageControl::ImageTotal(void) const
{
  return theSlideShow.ImageTotal();
}

int cImageControl::ImageCurrent(void) const
{
  return theSlideShow.ImageCurrent();
}

const char* cImageControl::FileName(void) const
{
  std::string datei;
  datei = configdir;
  datei = datei + "/coverviewer/data/nopic.png";

  if(ImageTotal() > 0) {
    cImage* pImage = theSlideShow.GetImage();
    return pImage?pImage->Name():NULL;
    }
  else {
    return datei.c_str();
  }
}

void cImageControl::SlideImage()
{
  if( m_bSlideShowActiv && ImageTotal() >0 )
  {
    if(CoverSetup.m_nSSsec <= 
        (time(NULL) - m_tStarted))
    {
      CanLoadCover = true;
      if(CoverSetup.EnableFade)  FadeOut();
      NextImage(1);
      Show();
    }
  }

}
