#ifndef __dvb_sec_h
#define __dvb_sec_h

#include <lib/base/ebase.h>
#include <lib/dvb/idvb.h>
#include <lib/base/stl_types.h>
#include <list>

#ifndef SWIG
class eSecCommand
{
public:
	enum { modeStatic, modeDynamic };
	enum {
		NONE, SLEEP, SET_VOLTAGE, SET_TONE, GOTO,
		SEND_DISEQC, SEND_TONEBURST, SET_FRONTEND,
		SET_TIMEOUT, IF_TIMEOUT_GOTO, 
		IF_VOLTAGE_GOTO, IF_NOT_VOLTAGE_GOTO,
		SET_POWER_LIMITING_MODE,
		SET_ROTOR_DISEQC_RETRYS, IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO,
		MEASURE_IDLE_INPUTPOWER, MEASURE_RUNNING_INPUTPOWER,
		IF_MEASURE_IDLE_WAS_NOT_OK_GOTO, IF_INPUTPOWER_DELTA_GOTO,
		UPDATE_CURRENT_ROTORPARAMS, INVALIDATE_CURRENT_ROTORPARMS,
		UPDATE_CURRENT_SWITCHPARMS, INVALIDATE_CURRENT_SWITCHPARMS,
		SET_ROTOR_PENDING,
		CLEAR_ROTOR_PENDING,
		IF_NOT_ROTOR_PENDING_GOTO,
		IF_ROTORPOS_VALID_GOTO,
		IF_BLINDSCAN_GOTO,
		IF_TUNER_LOCKED_GOTO,
		IF_TONE_GOTO, IF_NOT_TONE_GOTO,
		START_TUNE_TIMEOUT,
		SET_ROTOR_MOVING,
		SET_ROTOR_STOPPED,
		DELAYED_CLOSE_FRONTEND,
		IF_ACQUIRE_SEC_LOCK_GOTO,
		CLEAR_SEC_LOCK,
		IF_LINKED_IN_USE_GOTO,
		UPDATE_OPARM,
		SET_TUNER_INPUT
	};
	int cmd;
	struct rotor
	{
		union {
			int deltaA;   // difference in mA between running and stopped rotor
			int lastSignal;
		};
		int okcount;  // counter
		int steps;    // goto steps
		int direction;
	};
	struct pair
	{
		union
		{
			int voltage;
			int tone;
			int val;
		};
		int steps;
	};
	union
	{
		int val;
		int steps;
		int timeout;
		int voltage;
		int tone;
		int toneburst;
		int msec;
		int mode;
		rotor measure;
		eDVBDiseqcCommand diseqc;
		pair compare;
	};
	eSecCommand( int cmd )
		:cmd(cmd)
	{}
	eSecCommand( int cmd, int val )
		:cmd(cmd), val(val)
	{}
	eSecCommand( int cmd, eDVBDiseqcCommand diseqc )
		:cmd(cmd), diseqc(diseqc)
	{}
	eSecCommand( int cmd, rotor measure )
		:cmd(cmd), measure(measure)
	{}
	eSecCommand( int cmd, pair compare )
		:cmd(cmd), compare(compare)
	{}
	eSecCommand()
		:cmd(NONE)
	{}
};

class eSecCommandList
{
	typedef std::list<eSecCommand> List;
	List secSequence;
public:
	typedef List::iterator iterator;
private:
	iterator cur;
public:
	eSecCommandList()
		:cur(secSequence.end())
	{
	}
	void push_front(const eSecCommand &cmd)
	{
		secSequence.push_front(cmd);
	}
	void push_back(const eSecCommand &cmd)
	{
		secSequence.push_back(cmd);
	}
	void push_back(eSecCommandList &list)
	{
		secSequence.insert(end(), list.begin(), list.end());
	}
	void clear()
	{
		secSequence.clear();
		cur=secSequence.end();
	}
	inline iterator &current()
	{
		return cur;
	}
	inline iterator begin()
	{
		return secSequence.begin();
	}
	inline iterator end()
	{
		return secSequence.end();
	}
	int size() const
	{
		return secSequence.size();
	}
	operator bool() const
	{
		return secSequence.size();
	}
	eSecCommandList &operator=(const eSecCommandList &lst)
	{
		secSequence = lst.secSequence;
		cur = begin();
		return *this;
	}
};
#endif

class eDVBSatelliteDiseqcParameters
{
#ifdef SWIG
	eDVBSatelliteDiseqcParameters();
	~eDVBSatelliteDiseqcParameters();
#endif
public:
	enum { AA=0, AB=1, BA=2, BB=3, SENDNO=4 /* and 0xF0 .. 0xFF*/  };	// DiSEqC Parameter
	enum t_diseqc_mode { NONE=0, V1_0=1, V1_1=2, V1_2=3, SMATV=4 };	// DiSEqC Mode
	enum t_toneburst_param { NO=0, A=1, B=2 };
#ifndef SWIG
	__u8 m_committed_cmd;
	t_diseqc_mode m_diseqc_mode;
	t_toneburst_param m_toneburst_param;

	__u8 m_repeats;	// for cascaded switches
	bool m_use_fast;	// send no DiSEqC on H/V or Lo/Hi change
	bool m_seq_repeat;	// send the complete DiSEqC Sequence twice...
	__u8 m_command_order;
	/* 	diseqc 1.0)
			0) commited, toneburst
			1) toneburst, committed
		diseqc > 1.0)
			2) committed, uncommitted, toneburst
			3) toneburst, committed, uncommitted
			4) uncommitted, committed, toneburst
			5) toneburst, uncommitted, committed */
	__u8 m_uncommitted_cmd;	// state of the 4 uncommitted switches..
#endif
};

class eDVBSatelliteSwitchParameters
{
#ifdef SWIG
	eDVBSatelliteSwitchParameters();
	~eDVBSatelliteSwitchParameters();
#endif
public:
	enum t_22khz_signal {	HILO=0, ON=1, OFF=2	}; // 22 Khz
	enum t_voltage_mode	{	HV=0, _14V=1, _18V=2, _0V=3, HV_13=4 }; // 14/18 V
#ifndef SWIG
	t_voltage_mode m_voltage_mode;
	t_22khz_signal m_22khz_signal;
	__u8 m_rotorPosNum; // 0 is disable.. then use gotoxx
#endif
};

class eDVBSatelliteRotorParameters
{
#ifdef SWIG
	eDVBSatelliteRotorParameters();
	~eDVBSatelliteRotorParameters();
#endif
public:
	enum { NORTH, SOUTH, EAST, WEST };
	enum { FAST, SLOW };
#ifndef SWIG
	eDVBSatelliteRotorParameters() { setDefaultOptions(); }

	struct eDVBSatelliteRotorInputpowerParameters
	{
		bool m_use;	// can we use rotor inputpower to detect rotor running state ?
		__u8 m_delta;	// delta between running and stopped rotor
		unsigned int m_turning_speed; // SLOW, FAST, or fast turning epoch
	};
	eDVBSatelliteRotorInputpowerParameters m_inputpower_parameters;

	unsigned int m_degree_per_second;

	struct eDVBSatelliteRotorGotoxxParameters
	{
		__u8 m_lo_direction;	// EAST, WEST
		__u8 m_la_direction;	// NORT, SOUTH
		double m_longitude;	// longitude for gotoXX? function
		double m_latitude;	// latitude for gotoXX? function
	};
	eDVBSatelliteRotorGotoxxParameters m_gotoxx_parameters;

	void setDefaultOptions() // set default rotor options
	{
		m_inputpower_parameters.m_turning_speed = FAST; // fast turning
		m_inputpower_parameters.m_use = true;
		m_inputpower_parameters.m_delta = 60;
		m_degree_per_second = 5; // 0.5 degree per second for 13V ... + 25% for 18V
		m_gotoxx_parameters.m_lo_direction = EAST;
		m_gotoxx_parameters.m_la_direction = NORTH;
		m_gotoxx_parameters.m_longitude = 0.0;
		m_gotoxx_parameters.m_latitude = 0.0;
	}
#endif
};

#ifndef SWIG
struct eDVBSatelliteLNBParameters
{
	int m_slot_mask; // useable by slot ( 1 | 2 | 4...)

	unsigned int m_lof_hi,	// for 2 band universal lnb 10600 Mhz (high band offset frequency)
				m_lof_lo,	// for 2 band universal lnb  9750 Mhz (low band offset frequency)
				m_lof_threshold;	// for 2 band universal lnb 11750 Mhz (band switch frequency)

	bool m_increased_voltage; // use increased voltage ( 14/18V )

	FastHashMap<int, eDVBSatelliteSwitchParameters> m_satellites;
	eDVBSatelliteDiseqcParameters m_diseqc_parameters;
	eDVBSatelliteRotorParameters m_rotor_parameters;

	int m_prio; // to override automatic tuner management ... -1 is Auto

#define guard_offset_min -8000
#define guard_offset_max 8000
#define guard_offset_step 8000
#define MAX_SATCR 32
#define MAX_LNBNUM 32

	int SatCR_positions;
	int SatCR_idx;
	int SatCR_mode;
	int SatCR_pin;
	unsigned int SatCRvco;
	int PowerOnDelay; // some Unicable LNBs need long time to powerup after voltage enable...
/*
	int old_frequency;
	int old_polarisation;
	int old_orbital_position;
	int guard_offset_old;
*/
	int guard_offset;
	int LNBNum;
	int TunerInput; /* -1 when unused */
};
#endif

class eDVBRegisteredFrontend;

class eDVBSatelliteEquipmentControl: public iDVBSatelliteEquipmentControl
{
	DECLARE_REF(eDVBSatelliteEquipmentControl);
public:
	enum {
		DELAY_AFTER_CONT_TONE_DISABLE_BEFORE_DISEQC=0,  // delay after continuous tone disable before diseqc command
		DELAY_AFTER_FINAL_CONT_TONE_CHANGE, // delay after continuous tone change before tune
		DELAY_AFTER_FINAL_VOLTAGE_CHANGE, // delay after voltage change at end of complete sequence
		DELAY_BETWEEN_DISEQC_REPEATS, // delay between repeated diseqc commands
		DELAY_AFTER_LAST_DISEQC_CMD, // delay after last diseqc command
		DELAY_AFTER_TONEBURST, // delay after toneburst
		DELAY_AFTER_ENABLE_VOLTAGE_BEFORE_SWITCH_CMDS, // delay after enable voltage before transmit toneburst/diseqc
		DELAY_AFTER_VOLTAGE_CHANGE_BEFORE_MEASURE_IDLE_INPUTPOWER, // delay after voltage change before measure idle input power
		DELAY_AFTER_ENABLE_VOLTAGE_BEFORE_MOTOR_CMD, // delay after enable voltage before transmit motor command
		DELAY_AFTER_MOTOR_STOP_CMD, // delay after transmit motor stop
		DELAY_AFTER_VOLTAGE_CHANGE_BEFORE_MOTOR_CMD, // delay after voltage change before transmit motor command
		DELAY_BEFORE_SEQUENCE_REPEAT, // delay before the complete sequence is repeated (when enabled)
		MOTOR_COMMAND_RETRIES, // max transmit tries of rotor command when the rotor dont start turning (with power measurement)
		MOTOR_RUNNING_TIMEOUT, // max motor running time before timeout
		DELAY_AFTER_VOLTAGE_CHANGE_BEFORE_SWITCH_CMDS, // delay after change voltage before transmit toneburst/diseqc
		DELAY_AFTER_DISEQC_RESET_CMD,
		DELAY_AFTER_DISEQC_PERIPHERIAL_POWERON_CMD,
		DELAY_AFTER_VOLTAGE_CHANGE_BEFORE_UNICABLE_CMD,
		DELAY_AFTER_UNICABLE_CMD,
		DELAY_AFTER_UNICABLE_FINAL_VOLTAGE_CHANGE,
		MAX_PARAMS
	};
private:
#ifndef SWIG
	static eDVBSatelliteEquipmentControl *instance;
	eDVBSatelliteLNBParameters m_lnbs[512]; // at the moment we have max 2 FBC Tuners.. a 8 channels... max 32 LNB per channel
	int m_lnbidx; // current index for set parameters
	FastHashMap<int, eDVBSatelliteSwitchParameters>::iterator m_curSat;
	eSmartPtrList<eDVBRegisteredFrontend> &m_avail_frontends, &m_avail_simulate_frontends;
	int m_rotorMoving;
	int m_unused; // was m_not_linked_slot_mask
#endif
#ifdef SWIG
	eDVBSatelliteEquipmentControl();
	~eDVBSatelliteEquipmentControl();
#endif
	static int m_params[MAX_PARAMS];
public:
#ifndef SWIG
	eDVBSatelliteEquipmentControl(eSmartPtrList<eDVBRegisteredFrontend> &avail_frontends, eSmartPtrList<eDVBRegisteredFrontend> &avail_simulate_frontends);
	RESULT prepare(iDVBFrontend &frontend, dvb_frontend_parameters &parm, const eDVBFrontendParametersSatellite &sat, int frontend_id, unsigned int tunetimeout);
	void prepareClose(iDVBFrontend &frontend, bool typeChanged=false);
	int canTune(const eDVBFrontendParametersSatellite &feparm, iDVBFrontend *, int frontend_id, int *highest_score_lnb=0);
	bool currentLNBValid() { return m_lnbidx > -1 && (size_t)m_lnbidx < ARRAY_SIZE(m_lnbs); }
#endif
	static eDVBSatelliteEquipmentControl *getInstance() { return instance; }
	static void setParam(int param, int value);
	RESULT clear();
/* LNB Specific Parameters */
	RESULT addLNB();
	RESULT setLNBSlotMask(int slotmask);
	RESULT setLNBLOFL(int lofl);
	RESULT setLNBLOFH(int lofh);
	RESULT setLNBThreshold(int threshold);
	RESULT setLNBIncreasedVoltage(bool onoff);
	RESULT setLNBPrio(int prio);
	RESULT setLNBNum(int LNBNum);
	RESULT setLNBTunerInput(int index);
	RESULT getLNBTunerInput();
/* DiSEqC Specific Parameters */
	RESULT setDiSEqCMode(int diseqcmode);
	RESULT setToneburst(int toneburst);
	RESULT setRepeats(int repeats);
	RESULT setCommittedCommand(int command);
	RESULT setUncommittedCommand(int command);
	RESULT setCommandOrder(int order);
	RESULT setFastDiSEqC(bool onoff);
	RESULT setSeqRepeat(bool onoff); // send the complete switch sequence twice (without rotor command)
/* Rotor Specific Parameters */
	RESULT setLongitude(float longitude);
	RESULT setLatitude(float latitude);
	RESULT setLoDirection(int direction);
	RESULT setLaDirection(int direction);
	RESULT setUseInputpower(bool onoff);
	RESULT setInputpowerDelta(int delta);  // delta between running and stopped rotor
	RESULT setRotorTurningSpeed(int speed);  // set turning speed..
	RESULT setDegreePerSecond(int degree); // set motor speed in tenth of degree per second ... used only when inputpower is not used
/* Unicable Specific Parameters */
	RESULT setLNBSatCR(int SatCR_idx);
	RESULT setLNBSatCRvco(int SatCRvco);
	RESULT setLNBSatCRpin(int SatCRpin);
	RESULT setLNBSatCRpositions(int SatCR_positions);
	RESULT setLNBSatCRmode(int mode);
	RESULT getLNBSatCR();
	RESULT getLNBSatCRvco();
	RESULT getLNBSatCRpin();
	RESULT getLNBSatCRpositions();
	RESULT getLNBSatCRmode();
	RESULT setLNBPowerOnDelay(int ms);
/* Satellite Specific Parameters */
	RESULT addSatellite(int orbital_position);
	RESULT setVoltageMode(int mode);
	RESULT setToneMode(int mode);
	RESULT setRotorPosNum(int rotor_pos_num);
	RESULT setTunerLinked(int from, int to, int which=3); // bitmask of 1 = normal, 2 = simulate
	RESULT setTunerDepends(int from, int to);
	void setSlotNotLinked(int tuner_no); // not used anymore... is a NOP

	intPairList getFrequencyRangeList(int slot_no, int orb_pos);
	intList getBandCutOffFrequency(int slot_no, int orb_pos);
	void setRotorMoving(int, bool); // called from the frontend's
	bool isRotorMoving();
};

#endif
