#include <fstream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <vdr/osdbase.h>
#include <vdr/config.h>
#include "ripitosd.h"
#include "i18n.h"
#include "ripitstatus.h"

#define LINES_IN_DISPLAY 16
#define CHARS_PER_LINE 60

const cFont *font;
class cRipitStatus;

string percentString(float percent)
{
 string pString;
 pString="[";
 int i;
 for (i=0;i<percent;i++) pString +="|";
 for (;i<100;i++) pString +=" ";
 pString +="]";;
 return pString;
}

cRipitOsd::cRipitOsd() :cOsdMenu(tr("AudioCD copy"), 8,10)
{
  font = cFont::GetFont(fontSml);
  offset = 0;
  old_time = 0;
  filechanged = false;
}

cRipitOsd::~cRipitOsd()
{
  DisplayMenu()->SetTitle(tr("AudioCD Ripper"));
}

bool cRipitOsd::Rip_On(void)
{
  return access("/tmp/ripit.process",F_OK) == 0;
}

eOSState cRipitOsd::ProcessKey(eKeys Key)
{
     switch(Key) {
          case kDown:
                offset++;
                break;
          case kUp:
                if(offset>0) offset--;
                break;
          default: break;
     }

     eOSState state = cOsdMenu::ProcessKey(Key);
     if (state == osUnknown) {
	std::string cmd;
    	switch (Key) {
          case kRed:
	        if (!Rip_On()) {
		  Start_Encode(NULL);
	        }	
                break;
	  case kBlue:
		if (Rip_On()) {
		Abort_Encode();
		}
		break;
          case kYellow:
		//lame
		cmd =  std::string("sudo /bin/sed s/\"^@coder.*\"/\"@coder          = (0);          # 0 - Lame, 1 - OggVorbis, 2 - Flac,\"/ -i ripit.pl");
		::system(cmd.c_str());
                break;
          case kGreen:
		//ogg
		cmd =  std::string("sudo /bin/sed s/\"^@coder.*\"/\"@coder          = (1);          # 0 - Lame, 1 - OggVorbis, 2 - Flac,\"/ -i ripit.pl");
		::system(cmd.c_str());
                break;
          default: break;
	}	
     } 
  Display();
  return state;
}


void cRipitOsd::Start_Encode(const char *Device)
{
  char *buffer;
  char godown[256]="", noquiet[256]="", eject[256]="", remote[256]="", ripopts[256]="", presetarg[256]="", crcarg[256]="", device[64]="";
  int lowbit = 0;
  int maxbit = 0;
  old_time = 0;

  if(Device)
    strcpy(device,Device);
  else
    strcpy(device,RipitSetup.Ripit_dev);

  if(RipitSetup.Ripit_halt)     strcpy(godown ,"--halt");  else strcpy(godown,"");
  if(RipitSetup.Ripit_noquiet)  strcpy(noquiet,"");        else strcpy(godown,"--quiet");
  if(RipitSetup.Ripit_eject)    strcpy(eject  ,"--eject"); else strcpy(eject,"");
  
  if(!RipitSetup.Ripit_remote)
    strcpy(remote,"");
  else
    strcpy(remote,RipitSetup.Ripit_remotevalue);
  
  if(RipitSetup.Ripit_fastrip) {
    strcpy(ripopts, "-Z");
  } else {
    strcpy(ripopts, ""); 
  }

  switch(RipitSetup.Ripit_lowbitrate) {
    case 0: lowbit = 32; break;
    case 1: lowbit = 64; break;
    case 2: lowbit = 96; break;
    case 3: lowbit = 112; break;
    case 4: lowbit = 128; break;
    case 5: lowbit = 160; break;
    case 6: lowbit = 192; break;
    case 7: lowbit = 224; break;
    case 8: lowbit = 256; break;
    case 9: lowbit = 320; break;
    default: break;
  }

  switch(RipitSetup.Ripit_maxbitrate) {
    case 0: maxbit = 32; break;
    case 1: maxbit = 64; break;
    case 2: maxbit = 96; break;
    case 3: maxbit = 112; break;
    case 4: maxbit = 128; break;
    case 5: maxbit = 160; break;
    case 6: maxbit = 192; break;
    case 7: maxbit = 224; break;
    case 8: maxbit = 256; break;
    case 9: maxbit = 320; break;
    default: break;
  }

  if       (RipitSetup.Ripit_preset ==  0) strcpy(presetarg, "");
  else if  (RipitSetup.Ripit_preset ==  1) strcpy(presetarg, "--preset 64");
  else if  (RipitSetup.Ripit_preset ==  2) strcpy(presetarg, "--alt-preset 192");
  else if  (RipitSetup.Ripit_preset ==  3) strcpy(presetarg, "--preset extreme -V 2 --vbr-new -h");
  else if  (RipitSetup.Ripit_preset ==  4) strcpy(presetarg, "--preset 320 -h");

  if(RipitSetup.Ripit_crc) {
    strcpy(crcarg, "-p");
  } else {
    strcpy(crcarg, ""); 
  }

  asprintf(&buffer,"`echo 'Ripping process started....' > /tmp/ripit.log; touch /tmp/ripit.process; nice -n %i ripit.pl %s %s %s %s --bitrate %i --maxrate %i --device %s --lameopt '%s %s %s' --ripopt '%s' --nointeraction --outputdir '%s'`&",
					RipitSetup.Ripit_nice,
					noquiet,
					eject,
					remote,
					godown,
					lowbit,
					maxbit,
					device,
					presetarg,
					RipitSetup.Ripit_encopts,
					crcarg,
					ripopts,
					RipitSetup.Ripit_dir);

  dsyslog("Ripit: Executing '%s'",buffer);
  cRipitStatus *ripStatus = new cRipitStatus("/tmp/ripit.log", "ripping CD");
  ripStatus-> Start();
  SystemExec(buffer);
  free(buffer);
}

void cRipitOsd::Abort_Encode(void)
{
  char *buffer;
  asprintf(&buffer, "killall ripit.pl ; killall oggenc ; killall lame ; killall cdparanoia ; echo '%s' > /tmp/ripit.log; rm -f /tmp/ripit.process", tr("PROCESS MANUALLY ABORTED"));   
  esyslog("Ripit: Executing '%s'\nProcess manually aborted ...!!!\n",buffer);
  old_time = 0;
  SystemExec(buffer);
  free(buffer);
}

void cRipitOsd::Display(void)
{
  cOsdMenu::Display();

  // check for running process  
  if (Rip_On()) {
   // DisplayMenu()->SetTitle(tr("Process started..."));
    //DisplayMenu()->SetText(tr("Ready To Rumble"), 0);
    Clear();
    //Add ( new cOsdItem( tr("Process started")),0);
    Add(new cOsdItem(totalTracksStr.c_str(),osUnknown,false));
    Add(new cOsdItem("",osUnknown,false));
    Add(new cOsdItem(ripTitle.c_str(),osUnknown,false));
    Add(new cOsdItem(encodeTitle.c_str(),osUnknown,false));
    SetHelp(NULL, NULL, NULL, tr("Abort"));
  } else {    
    //DisplayMenu()->SetTitle(tr("No process started"));
    //DisplayMenu()->SetText(tr("No process started"), 0);
    Clear();
    Add ( new cOsdItem( tr("No riping in progress"),osUnknown,false));
    SetHelp(tr("Copy"), NULL, NULL, NULL);
    return;
  }    

  if(stat("/tmp/ripit.log", &fstats)==0){
    if(fstats.st_mtime != old_time) { // only re-read file if it has changed 
      //printf("reading file\n");
      old_time = fstats.st_mtime;
      filechanged = true;
      std::ifstream logfile("/tmp/ripit.log");
      std::string line;
      lines.clear();
      encodeTitle.clear();
      ripTitle.clear();
      ripCount = encodeCount = totalTracks = 0;
      int tmp;
      // read logfile
      if(logfile.is_open()) {
        while(!logfile.eof()) {
          getline(logfile, line);
          if (line.find("Tracks")==0) // Tracks 1 2 3 4 5 6 7 8 will be ripped
                  {
		     std::stringstream oss;
                     oss<< line.substr(7);
		     while(oss.good()) oss>>tmp;
		     totalTracks = tmp;
		     oss.clear(); // clear error flags on oss
		  }
	  else if (line.find("Ripper : ") == 0) // Ripper : 01 ...
	  { 
		  ripCount++; 
		  if (ripCount == totalTracks) ripTitle = tr("Ripped: \t") + percentString(ripCount*100.0/totalTracks)+ "\t" + tr("completed");
		  else
		  ripTitle = tr("Ripped: \t") + percentString(ripCount*100.0/totalTracks)+ "\t"+line.substr(9);
	  }
	  else if (line.find("Encoder: finished -> ") == 0)
	  {
		  encodeCount++;
		  encodeTitle = tr("Encoded: \t") + percentString(encodeCount*100.0/totalTracks) +"\t" +line.substr(20); 
	  }
	  else if (line.find("!! DONE") == 0)
	  {
		   encodeTitle = tr("Completed");
                   ripTitle = "";
		 
	  }
	  else if (line == tr("PROCESS MANUALLY ABORTED"))
	  {
		  encodeTitle = tr("Aborted");
                  ripTitle = "";
	  }
          //printf("getline: %s\n", line.c_str());
       //   if(line.size()<CHARS_PER_LINE)
         //   lines.push_back(line);
         // else
          //  lines.push_back(line.substr(0,CHARS_PER_LINE-3)+="..."); // truncate string to avoid line wrapping
        }
        logfile.close();
        std::stringstream oss;
        oss<<tr("Total Tracks: ")<<totalTracks;
	totalTracksStr = oss.str();
	//lines.push_back(oss.str());
	//lines.push_back(ripTitle);
	//lines.push_back(encodeTitle);
	Clear();
	Add(new cOsdItem(totalTracksStr.c_str(),osUnknown,false));
	Add(new cOsdItem("",osUnknown,false));
	Add(new cOsdItem(ripTitle.c_str(),osUnknown,false));
	Add(new cOsdItem(encodeTitle.c_str(),osUnknown,false));
      }
    } else {
      filechanged = false;
      //printf("file didn't change!\n");
    }
  } else
    printf("fstat failed!\n"); 

  //printf("offset: %i\n", offset);
  // scroll to end of logfile if it has changed
  if(filechanged && (lines.size() > LINES_IN_DISPLAY)) {
    //printf("filechanged: %i - lines.size(): %i\n", filechanged, lines.size());
    offset = lines.size() - LINES_IN_DISPLAY;
  }

  // display logfile
  std::string buffer;
  for(unsigned int i=offset; i<lines.size(); i++){
    buffer+=lines.at(i).c_str();
    buffer+="\n";
    //printf("line %i: %s\n", i, lines.at(i).c_str());
  }

  //printf("text: %s\n", buffer.c_str());
  //DisplayMenu()->SetText(buffer.c_str(), 0);
}

