#include <string>
#include "menu_recs.h"
#include "tracks.h"
#include <vdr/menu.h>
#include <vdr/interface.h>
#include "deluxe_config.h"
#include "menu_tracks.h"
#include "menu_convert.h"
#include "audio_thread.h"
#include "replay_control.h"
#include "log.h"
#include <iostream>  
#include <fstream>   
#include "i18n.h"

using std::string;
using std::string;
using std::ifstream;

static int CompareRecording(const void *p1, const void *p2)
{
  return (int)((*(cRecording **)p1)->start - (*(cRecording **)p2)->start);
}

string GetRecordingChannelID(cRecording* recording)
{
    string channelID = "";
    string filenameMarker = string(recording->FileName()) + "/deluxe";
    // open input file
    ifstream file(filenameMarker.c_str());
    // file opened?
    if (! file) 
	LogFile.eSysLog( "could not open file '%s'", filenameMarker.c_str());
    else
    {
	file >> channelID;
	if (channelID == "")
	    channelID = "S19.2E-1-1092-10100";
    }
    return channelID;
}

cMenuRecItem::cMenuRecItem(cRecording* Recording)
{
    recording = Recording;
    if (recording)
	filename = strdup(Recording->FileName());
    Set();
}

cMenuRecItem::~cMenuRecItem()
{
    if (filename) free(filename);
}

void cMenuRecItem::Set(void)
{
    SetText(recording->Title('\t'));
}

// --- cMenuRecs ----------------------------------------------------------
cMenuRecs::cMenuRecs()
:cOsdMenu("", 9, 7, 7)
{
    ScanRecordings();
    UpdateTitle();
    if (cMenuTracks::lastReplayed > -1)
	cRemote::Put(kRed);
}

bool cMenuRecs::ScanRecordings(void)
{
    cRecording **pArray = NULL;
    int num = 0;
    
    Clear();
    for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) 
    {    
	string markerFile = string(recording->FileName()) + "/deluxe";
	if (access(markerFile.c_str(), F_OK) != 0)
	    continue;
	pArray = (cRecording **)realloc(pArray, (num + 1) * sizeof(cRecording *));
	pArray[num++] = recording;	
    }

    qsort(pArray, num, sizeof(cRecording *), CompareRecording);

    for (int a = 0; a < num; a++)
    {
	bool select = cDeluxeReplayControl::LastReplayed()?(strcmp(cDeluxeReplayControl::LastReplayed(), pArray[a]->FileName())==0):false; 
	Add(new cMenuRecItem(pArray[a]), select);
    }

    delete pArray;

    SetHelp(NULL);
    Display();
    return true;
}

void cMenuRecs::UpdateTitle()
{
    char *buffer = NULL;
    asprintf(&buffer, "%d %s", Count(), tr("Deluxe Recordings"));
    SetTitle(buffer);
    SetHelp(tr("Button$Songs"), trVDR("Button$Mark"), tr("Button$Convert"), trVDR("Button$Delete")); 
    Display();
    free(buffer);
}

cRecording *cMenuRecs::GetRecording(cMenuRecItem *Item)
{
    cRecording *recording = Recordings.GetByName(Item->FileName());
    if (!recording)
	Skins.Message(mtError, tr("Error while accessing recording!"));
    return recording;
}

void cMenuRecs::Mark()
{
    int offset = DeluxeConfig.offset;
    cMenuRecItem *ri = (cMenuRecItem*)Get(Current());
    cRecording *recording = GetRecording(ri);
    if (!recording) return;

    string channelID = GetRecordingChannelID(recording);

    string strMarksFilename = string(recording->FileName()) + "/marks.vdr";
    remove(strMarksFilename.c_str());
    
    cMarks marks;
    marks.Load(recording->FileName());
    cIndexFile index(recording->FileName(), false);
    
    for(cTrack* track = Tracks.First(); track; track = Tracks.Next(track)) 
    {
	if (track->channelID != channelID) continue;

	int indexIStart = index.GetNextIFrame((track->starttime - recording->start + offset) * FRAMESPERSEC, true);
	int indexIStop = index.GetNextIFrame((track->starttime + track->duration - recording->start + offset) * FRAMESPERSEC, false);
	if (indexIStart < 0 || indexIStop < 0 || track->status > 0)
	    continue;

	char szYear[5] = "";
	sprintf(szYear, "%04d", track->year);
	string markcomment = string(track->artist) + string("|") + 
	    string(track->title) + string("|") +
	    szYear;

	cMark *markStart = NULL;
	if (indexIStart <= index.Last())
	{
	    markStart = marks.Add(indexIStart);
	    markStart->comment = strdup(markcomment.c_str());
	}
	cMark *markStop = NULL;

	if (indexIStop <= index.Last())
	    markStop = marks.Add(indexIStop);
    }	    
    marks.Save();    
    Skins.Message(mtInfo, tr("Marks created!"));
}

eOSState cMenuRecs::Delete(void)
{
   if (HasSubMenu() || Count() == 0)
      return osContinue;
   
   cMenuRecItem *ri = (cMenuRecItem*)Get(Current());
   cRecording *recording = GetRecording(ri);
   if (!recording) return osContinue;
   
   if (ri) 
   {
      if (Interface->Confirm(tr("Delete recording?"))) {
         cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
         if (rc) 
         {
            if (Interface->Confirm(tr("Timer still recording - really delete?"))) 
            {
               cTimer *timer = rc->Timer();
               if (timer) 
               {
                  timer->Skip();
                  cRecordControls::Process(time(NULL));
                  if (timer->IsSingleEvent()) 
                  {
                     isyslog("deleting timer %s", *timer->ToDescr());
                     Timers.Del(timer);
                  }
                  Timers.SetModified();
               }
            }
            else
               return osContinue;
         }
         if (recording->Delete()) 
         {
            cDeluxeReplayControl::ClearLastReplayed(recording->FileName());
            Recordings.DelByName(recording->FileName());
            cOsdMenu::Del(Current());
            Display();
         }
         else
            Skins.Message(mtError, tr("Error while deleting recording!"));
      }
   }
   UpdateTitle();
   return osContinue;
}

eOSState cMenuRecs::Play(void)
{
    cMenuRecItem *ri = (cMenuRecItem*)Get(Current());
    cRecording *recording = GetRecording(ri);
    if (recording) 
    {
	if (recording->IsNew())
	{
	    cResumeFile ResumeFile(recording->FileName());
	    cMarks marks;
	    marks.Load(recording->FileName());
	    if (marks.First())
		ResumeFile.Save(marks.First()->position);
	}
	cDeluxeReplayControl::SetRecording(recording->FileName(), recording->Title());
	cControl::Shutdown();
	cControl::Launch(new cDeluxeReplayControl);
	return osEnd;
    }
    return osContinue;
}

eOSState cMenuRecs::ProcessKey(eKeys Key)
{
  eOSState state = cOsdMenu::ProcessKey(Key);
  if (state == osUnknown && !HasSubMenu() && Current() >= 0) 
  {
      switch (Key) 
      {
	  case kOk:
	      state = Play();	      
	      break;
	  case kRed:
	  {
	      cMenuRecItem *ri = (cMenuRecItem*)Get(Current());
	      cRecording *recording = GetRecording(ri);
	      if (recording)
		  state = AddSubMenu(new cMenuTracks(recording));
	  }
	  break;
	  case kGreen:
	      Mark();
	      break;
	  case kYellow:
	  {
	      if (!cConvertToAudioThread::m_Instance)
	      {		  
		  cMenuRecItem *ri = (cMenuRecItem*)Get(Current());
		  cRecording *recording = GetRecording(ri);
		  if (recording)
		  {
		      cMarks marks;
		      marks.Load(recording->FileName());
		      if (marks.Count() < 2)
		      {
			  Skins.Message(mtError, tr("No marks available!"));
			  return osContinue;
		      }
		      state = AddSubMenu(new cMenuConvert(recording));
		  }
	      }
	      else
	      {
		  if (Interface->Confirm(tr("Conversion in progress! Abort conversion?")))
		      cConvertToAudioThread::Exit();
	      }
	  }
	  break;
	  case kBlue:
	      state = Delete();
	      break;
      default: break;
    }
  }
  return state;
}
