/*
 * terminalemulation.h: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */


#ifndef __TERMINALEMULATION_H__
#define __TERMINALEMULATION_H__


#include <sys/ioctl.h>
#include <termios.h>

#include <vdr/tools.h>
#include <vdr/remote.h>

#include "ipc.h"


#define CONSOLE_DEBUG( xx )
//#define CONSOLE_DEBUG( xx ) xx;



// With the small font there are many cells possible
#define CONSOLE_MAXCOLS 100
#define CONSOLE_MAXROWS 50




// define used keys

#define BS  '\010'	// Backspace
#define HT  '\011'	// Horizontal Tab
#define LF  '\012'	// Line Feed
#define VT  '\013'	// Vertical Tab
#define FF  '\014'	// Form Feed
#define CR  '\015'	// Carriage Return
#define SO  '\016'	// Shift out
#define SI  '\017'	// Shift in

#define CAN '\030'	// Cancel
#define SUB '\032'	// Substitude
#define ESC '\033'	// Escape


// New keys that are not specified through keys.h
// Be carefull! It could be that these keys will
// be used some day from VDR itself.
#define kRefresh 1002








enum eConsTerminalState {
  eCtsNormal = 0,
  eCtsEscape,
  eCtsEscapeParameter,
  eCtsEscapeSingleCode,
  eCtsSelectCharSetG0,
  eCtsSelectCharSetG1
};



struct sConsCanvasChar {

  sConsCanvasChar()
  : ch          (' '),
    foreColor   (0),
    backColor   (0),

    Bold        (false),
    Underscore  (false),
    Blink       (false),
    Inverted    (false),
    Concealed   (false),
    useFore     (false),
    useBack     (false)
  {}
  
  sConsCanvasChar(unsigned char Ch, const sConsCanvasChar& attr)
  : ch          (Ch),
    foreColor   (attr.foreColor),
    backColor   (attr.backColor),

    Bold        (attr.Bold),
    Underscore  (attr.Underscore),
    Blink       (attr.Blink),
    Inverted    (attr.Inverted),
    Concealed   (attr.Concealed),
    useFore     (attr.useFore),
    useBack     (attr.useBack)
  {}
  
  unsigned char ch;
  
  unsigned char foreColor : 4;
  unsigned char backColor : 4;
  
  bool Bold : 1;
  bool Underscore : 1;
  bool Blink : 1;
  bool Inverted : 1;
  bool Concealed : 1;
  bool useFore : 1;
  bool useBack : 1;
};



struct sConsScreenCursorPos {

  sConsScreenCursorPos(int X, int Y, const sConsCanvasChar& Attributes, bool ModeOrigin, sConsScreenCursorPos* Prev)
  : x            (X), 
    y            (Y), 
    attributes   (Attributes),
    modeOrigin   (ModeOrigin),
    prev         (Prev)
  {}

  int x, y;
  sConsCanvasChar attributes;
  bool modeOrigin;

  sConsScreenCursorPos* prev;
};




class cConsTerminalEmulation
{
private:
  int _w, _h;
  sConsCanvasChar* _canvas[CONSOLE_MAXROWS];

  int _curX, _curY;
  sConsScreenCursorPos* _curPosSaved;

  int _scrollRegionTop, _scrollRegionBottom;

  bool _modeCurVisible;
  bool _modeOrigin;
  bool _modeWrapAround;
  bool _modeInsert;
  bool _modeNewLine;

  eConsTerminalState _state;

  int* _escapeParams;
  int _escapeParamsCount;

  bool _changed, _bell;

  sConsCanvasChar _defaultChar;

  int _tabs[CONSOLE_MAXCOLS];

  cMutex _mutex;
  bool _wantRefreshEvent;

  unsigned char _charSet[256];

  int _fd;

private:
  void Changed();

  void Clear(int fromX = 0, int fromY = 0, int toX = -1, int toY = -1);
  void ScrollUp(int Count = 1) { ScrollUp( Count, _scrollRegionTop ); }
  void ScrollUp(int Count, int FromLine);
  void ScrollDown(int Count = 1) { ScrollDown(Count, _scrollRegionTop); }
  void ScrollDown(int Count, int FromLine);

  void decodeEscapeSequence(char code);
  void decodeEscapeCode(char code);
  void decodeEscapeSingleCode(char code);

  void tabStopClear();
  void tabStopAdd(int tabstop);
  void tabStopRemove(int tabstop);

  void keyCarriageReturn();
  void keyLineFeed(bool NewLine);
  void keyBackspace();
  void keyDelete();
  void keyTab();
  void keyInsert(unsigned char ch = ' ');
  void keyBell();

  void setAttributes(int* attributes, int count);

  void setModes(int* attributes, int count);
  void resetModes(int* attributes, int count);
  void setModeCurVisible(bool visible);
  void setModeOrigin(bool origin);

  void ClearToEnd();
  void ClearFromBegin();
  void ClearLine();

  void InsertChar(int count);
  void DeleteChar(int count);
  void InsertLine(int count);
  void DeleteLine(int count);

  void reportDeviceStatus(int request);
  void reportDeviceAttributes(int request);

  void MoveTo(int col, int row);
  void MoveRelative(int d_col, int d_row);

  void setScrollRegion(int top, int bottom);

  void CursorPosSave();
  void CursorPosRestore();

  void Write(unsigned char ch);

  void SelectCharSet(int g, char set);

public:
  cConsTerminalEmulation();
  virtual ~cConsTerminalEmulation();

  void setOutputFileDescriptor(int fd) {_fd = fd;}
  void Write(const unsigned char* stream);

  const sConsCanvasChar** getCanvas() {return (const sConsCanvasChar**)_canvas;}

  int getW() { return _w; }
  int getH() { return _h; }
  bool setSize(int w, int h);
  int getCursorX() { return _curX; }
  int getCursorY() { return _modeOrigin ? _curY - _scrollRegionTop : _curY; }
  bool getCursorVisible() { return _modeCurVisible; }

  bool ToRefresh() { return _changed; }
  void Refreshed();
  bool ToRing() { return _bell; }
  void BellSeen();

  cMutex* getMutex() { return &_mutex; }
  void WantRefreshEvent(bool WantIt) { _wantRefreshEvent = WantIt; }
};



#endif // __TERMINALEMULATION_H__


