#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstdlib>
#include <ctype.h>

#include <vdr/thread.h>

#include "commons.h"

#ifndef CCBYTE
	#define CCBYTE 1
	#define byte unsigned char
	#define RAWBUFFER 2048
	#define CC_BUFFER_SIZE 1000
	#define CC_QUEUE_SIZE 1000
#endif //CCBYTE

typedef struct CC_Data
{
	byte type; //0 = text, 1= command
	byte *data;
	int length;
};

class cCCExtractor{
 public:
	cCCExtractor(void);
	~cCCExtractor(void);
	
	bool Init(int bufferSize);
	void InitParser();
	void SetChannel(int chn);
	byte GetByte(byte in, bool itv);
	
	bool Reset(void);
	bool ParseBuffer(byte *buffer, int len);
	
	CC_Data *PopCC();
	
 protected:
 	bool EqualBytes(byte *s1, const byte *s2, int len);	//compares two byte strings

	bool ExtractCC4Dish(byte *buffer, int len);//extracts the DishNet compatible CC - not yet implemented
	bool ExtractCC4R4K(byte *buffer, int len); //extracts the R4000 compatible CC - not yet implemented
	bool ExtractCC4R5K(byte *buffer, int len); //extracts the R5000 compatible CC - not yet implemented
	bool ExtractCC4DVD(byte *buffer, int len); //extracts the DVD compatible CC - not yet implemented
 	
 	bool SplitCC(byte* input); //splits the CC data in lines; returns true if a complete line is available
	bool GetCCData(byte *line, int len); //transfers the a line of data to queue if the current line matches the desired CC type
 	bool QueueData(byte type, byte* data, int len); //transfers data to queue
 			
	bool PrintData1(byte c1); //stores data on channel 1
	bool PrintData2(byte c1); //stores data on channel 2 - useful only for DVD
	
 private:
#ifdef CC_DEBUG
 	FILE *logFile;
 	FILE *sccFile; 	
	FILE *logCCFile;
#endif

  int nExtractField;
  int nChannel;
  byte channels;

  bool bInUserData;
   
  byte *rawBuffer1;
  byte *rawBuffer2;
  byte guideBuffer[CC_BUFFER_SIZE]; // buffer used to store all CC binary data in USER DATA fields
  byte frameBuffer[CC_BUFFER_SIZE]; // buffer used to cumulate the P-frame data

  int nBufferSize; // the size of memory buffer to store the CC data during this process
  int nRaw1CCSize;
  int nRaw2CCSize;

  int parserPos; // position where the parsing in buffer started
  int framePos; // position in P-frame buffer
  
  int nUDPos; // last position in user data loop relatively to the start of user data segment
  
  byte header[4];

  static const byte startUserDataHeader[];
  static const byte endUserDataHeader[];
  static const byte dishDVBHeader[];
  static const byte r4000DVBHeader[];
  static const byte r5000DVBHeader[];
  static const byte dvdHeader[];

//raw data extraction
private:
 byte newLine[RAWBUFFER];
 byte ccRaw[RAWBUFFER];
 
 int rawPos;
 bool bEOL;
 bool bInline;
 bool bSkipHeader; //not yet used
 bool bCR;
 int nColumns;
 
 int lineLength;

//CC construction
private:
 CC_Data ccContent[CC_BUFFER_SIZE];
 
 CC_Data queue[CC_BUFFER_SIZE * 10];
 bool bWasText;
 int ccCnt;
 
 cMutex m_mutex;
 int qPos;
 
 //debug
 int cnt;
};
