/*
 * serled.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */
//c - c++
#include "iostream"
#include "fstream"
#include "string"
#include "vector"

//vdr
#include <vdr/plugin.h>
#include "vdr/status.h"


//this
#include "SerLEDDevice.H"
#include "SerLED.H"
#include "SerLEDStatus.H"
#include "SerLEDStatusOn.H"
#include "SerLEDStatusFlash.H"
#include "SerLEDMonitor.H"
#include "time2usec.H"
#include "readline.H"
#include "devices_reg.H"

using namespace std;




static const char *VERSION        = "0.1.4";
static const char *DESCRIPTION    = "Status LEDs";
//static const char *MAINMENUENTRY  = NULL;

class cPluginSerled : public cPlugin 
	{
	private:
//----------------------------private data members------------------------------
	//! serial devices
		vector<SerLEDDevice *> _devices;
		SerLEDDevice *_current_device;
	//! leds
		vector<SerLED *> _leds;
		SerLED *_current_led;
	//! states
		vector<SerLEDStatus *>  _status;
	//! items from config file
		vector<string> items;
	//! name of config file
		string _config_file_name;
	//! status monitor
		SerLEDMonitor *_monitor;
//----------------------------private member functions--------------------------
	/** read settings for serial device from file
	@param inf setup file
	*/
		bool read_device(istream &inf);
	/** read settings for an led
	@param inf setup file
	*/
		bool read_led(istream &inf);
	/** add to status monitor
	@param led LED class
	@param sn stauts number
	@param type status string
	*/
		bool add_monitor(SerLED *led, int sn, const string & type);
	/** return an error message
	@param msg error message
	*/
		void error_message(const char *msg);
public:
//---------------------------constructor - destructor---------------------------
	/**  deafult constructor */
	  	cPluginSerled(void);
	/** destructor */
		virtual ~cPluginSerled();
//---------------------------public member functions----------------------------
	/** return information about plugin*/	
		virtual const char *Version(void) { return VERSION; }
		virtual const char *Description(void) { return DESCRIPTION; }
		virtual const char *CommandLineHelp(void);
	/** Process command line arguments 
	    @param argc number of parameters 
	    @param argv vector with parameters
	*/	
	    virtual bool ProcessArgs(int argc, char *argv[]);
//  virtual bool Initialize(void);
	/** start plugin */
	    	virtual bool Start(void);
	/** clean up*/    
		virtual void Housekeeping(void);
  };
  
//=======================implementations======================================  

//////////////////////////////////
// read_device(istram &inf)	//
//////////////////////////////////

bool cPluginSerled :: read_device(istream &inf)
	{
	cout<<"read device"<<endl;
	if(!readline(inf, items)) return false;
//check for device definition file
	if(items[0]!="DEVICE" || items.size()<2)
		{
		error_message("DEVICE expected");
		return false;
		}
	_current_device = CreateDevice(items);
	if(_current_device ==NULL)
		{
		cerr<<"Unknown device type '"<<items[1]<<"'!"<<endl;
		return false;
		}
	_devices.push_back(_current_device);
//	cerr<<"new serled device '"<<items[1]<<"'"<<endl;
	while(read_led(inf));	
	return true;
	}
	
	
//////////////////////////////////	
// read_led(istream &inf)	//
//////////////////////////////////

bool cPluginSerled :: read_led(istream &inf)
	{
	cout<<"red_led"<<endl;
	if(!readline(inf, items)) 
		{
		cerr<<"readline failed!"<<endl;
		return false;
		}
	if(items[0]=="/DEVICE") 
		{
		cout<<"end od device"<<endl;
		return false;
		}
	int led_nr(_current_device->GetLEDNumber(items));
	cout<<"led_nr="<<led_nr<<endl;
//check for inverted connection
	if(led_nr==-1)
		{
		error_message("Invalid led type");
		return false;
		}
	_current_device->Off(led_nr);
	_current_led=new SerLED(_current_device, led_nr);
	_leds.push_back(_current_led);
	string end_tag("/"+items[0]);	
//scan led options
	while(readline(inf, items))
		{
	//end tag found
		if(items[0]==end_tag) return true;
	//on tag
		if(items[0]=="ON")
			{
//			cerr<<"serled status on"<<endl;
			if(items.size()!=2)
				{
				error_message("invalid number of arguments");
				return false;
				}
			SerLEDStatusOn *st = new SerLEDStatusOn(_current_device, led_nr);
			int s_nr=_leds[_leds.size() - 1]->AddState(static_cast<SerLEDStatus *>(st));
			if(!add_monitor(_current_led, s_nr, items[1]))
				{
				cerr<<"cannot add monitor"<<endl;
				return false;
				}
			_status.push_back(static_cast<SerLEDStatus *>(st));
			}
	//flash tag
		if(items[0]=="FLASH")
			{
			if(items.size()!=4)
				{
				error_message("invalid number of arguments");
				return false;
				}
//			cerr<<"serled status flash "<<items[1]<<" "<<items[2]<<endl;			
			SerLEDStatusFlash *st = new SerLEDStatusFlash(_current_device, led_nr, time2usec(items[1]), time2usec(items[2]));
			int s_nr=_leds[_leds.size() - 1]->AddState(static_cast<SerLEDStatus *>(st));
			if(!add_monitor(_current_led, s_nr, items[3]))
				{
				cerr<<"cannot add monitor!"<<endl;
				return false;
				}
			_status.push_back(static_cast<SerLEDStatus *>(st));
			}
			
		}
	return true;
	}


//////////////////////////////////////////////////////////////////
// add_monitor(SerLED *led, int sn, const string & type)	//
//////////////////////////////////////////////////////////////////

bool cPluginSerled::add_monitor(SerLED *led, int sn, const string & type)
	{
	if(type=="replay")
		{
//		cerr<<"status replay"<<endl;
		_monitor->AddReplayStatus(led, sn);
		return true;
		}
	if(type=="record")
		{
//		cerr<<"status record"<<endl;
		_monitor->AddRecordStatus(led, sn);
		return true;
		}	
	if(type=="all_record")
		{
//		cerr<<"status alrecord"<<endl;		
		_monitor->AddAllRecordStatus(led, sn);
		return true;
		}
	if(type=="cutting")
		{
//		cerr<<"status cutting"<<endl;
		_monitor->AddCuttingStatus(led, sn);
		return true;
		}
	if(type=="red")
		{
		_monitor->AddColorStatus(led, sn, SerLEDMonitor::red);
		return true;
		}
	if(type=="green")
		{
		_monitor->AddColorStatus(led, sn, SerLEDMonitor::green);
		return true;
		}
	if(type=="blue")
		{
		_monitor->AddColorStatus(led, sn, SerLEDMonitor::blue);
		return true;
		}
	if(type=="yellow")
		{
		_monitor->AddColorStatus(led, sn, SerLEDMonitor::yellow);
		return true;
		}
//	cerr<<"serled: syntax error inconfig file"<<endl;
	return false;
	}

//////////////////////////////////////////
// error_message(const char *msg)	//
//////////////////////////////////////////

void cPluginSerled::error_message(const char *msg)
	{
	cerr<<msg<<endl;
	cerr<<"offending setup line:"<<endl;
	for(unsigned int i=0; i<items.size(); i++)
		cerr<<" "<<items[i];
	cerr<<endl;
	}


//////////////////////////
// cPluginSerled(void)	//
//////////////////////////

cPluginSerled::cPluginSerled(void)
{
//	cerr<<"creating status monitor class"<<endl;
	_monitor=new SerLEDMonitor();
//	cerr<<"done"<<endl;
}


//////////////////////////
// ~cPluginSerled()	//
//////////////////////////

cPluginSerled::~cPluginSerled()
	{
//	cerr<<"cPluginSerled::~cPluginSerled"<<endl;
	for(unsigned int i=0; i<_devices.size(); i++)
		delete _devices[i];
//	cerr<<"devices deleted!"<<endl;
	for(unsigned int i=0; i<_leds.size(); i++)
		delete _leds[i];
//	cerr<<"leds deleted"<<endl;
	for(unsigned int i=0; i<_status.size(); i++)
		delete _status[i];
//	cerr<<"status deleted"<<endl;
	if(_monitor!=NULL) delete _monitor;
//	cerr<<"done"<<endl;
	}

const char *cPluginSerled::CommandLineHelp(void)
{
  return "  [<setup file>] (default=/etc/vdr/serled)";
}

bool cPluginSerled::ProcessArgs(int argc, char *argv[])
	{
//open setup file
	if(argc>1)
		{
		_config_file_name=argv[1];
		}
	else
		{
		_config_file_name="/etc/vdr/serled";
		}
	return true;
	}


bool cPluginSerled::Start(void)
	{
	ifstream inf(_config_file_name.c_str());
	if(inf.fail())
		{
		cerr<<"Setup file for serled not found!"<<endl;
		return false;
		}
//read 	lines
	string line;
	vector<string> items;
//current device
	while(read_device(inf));
   	_monitor->StartCutWatch();
	return true;
	}

void cPluginSerled::Housekeeping(void)
{
}



VDRPLUGINCREATOR(cPluginSerled); // Don't touch this!
