/**
* @class CCPCVideo
* Classe permettant la gestion d'un ecran CPC
* @author Thierry JOUIN
* @version 1.1
* @date 31/10/2001
*/                                                                                                           

#ifndef _CCPCVIDEO_H_
#define _CCPCVIDEO_H_

#include <string>
#include "CSDLVideo.h"

// Mode CPC
enum CPCVideoMode
{
	Mode0 = 0,
	Mode1,
	Mode2
};
// Positionement d'un pixel SDL dans un pixel CPC
enum CPCSDLPixelPosition
{
	Left	= 0x0000,
	Middle	= 0x0001,
	Right	= 0x0002,
	Up		= 0x0000,
	Center	= 0x0010,
	Down	= 0x0020
};

#define VAL_R1_DEFAULT 40
#define VAL_R6_DEFAULT 25

class CCPCVideo : public CSDLVideo
{
public:
	// Table de conversion Hard->Soft couleur
	static unsigned int HardToSoftTable[32];
	// Table de conversion Soft->Hard couleur
	static unsigned int SoftToHardTable[27];

protected:
	/// CPC mode
	CPCVideoMode _videoMode;
	/// SDL CPC palette
	Uint32 _palette[16];
	/// CPC soft palette
	unsigned int _paletteCPC[16];
	/// CRTC R1
	unsigned int _CRTCR1;
	/// CRTC R6
	unsigned int _CRTCR6;

	/// Memoire video CPC
	unsigned char *_videoCPC;
	/// Taille de la mémoire vidéo CPC
	unsigned int _videoCPCSize;
	/// Largeur en pixel CPC
	unsigned int _videoCPCWidth;
	/// Hauteur en pixel CPC
	unsigned int _videoCPCHeight;

public:
	//
	// Constructeur/destructeur
	//
	/// Constructeur modeVideo, R1, R6
	CCPCVideo(CPCVideoMode i_mode,unsigned int i_vR1=VAL_R1_DEFAULT, unsigned int i_vR6=VAL_R6_DEFAULT);
	/// Constructeur par recopie
	CCPCVideo(const CCPCVideo& i_scr);
	/// Destructeur
	~CCPCVideo();
	
	//
	// Fonctions d'affichage (acces direct SDL)
	//
	/// Affiche la surface a l'ecran
	virtual void display();
	/// CLS de la vidéo
	void cls();

	//
	// Fonctions gestion de CRTC
	//
	/// Renvoie les valeurs CRTC
	void getCRTCValue(int &R1,int &R6) const;
	//void setCRTCValue(int R1,int R6);
	void setCRTCValue(int &R1,int &R6);

	//
	// Fonctions gestion de palette
	//
	/// Met a jour le mode
	void setMode(const CPCVideoMode &mode);
	/// Renvoie le mode courant
	CPCVideoMode getMode() const;
	/// Met a jour la palette (soft)
	void setSoftPalette(const unsigned int *color, const unsigned int nbColor);
	/// Met a jour la palette (soft)
	void setHardPalette(const unsigned int *color, const unsigned int nbColor);
	/// Met une encre a jour (soft)
	void setSoftInk(const unsigned int i_ink,const unsigned int i_color);
	/// Met une encre a jour (hard)
	void setHardInk(const unsigned int i_ink,const unsigned int i_color);
	/// Swap 2 ink dans une window definie
	void swapInkWindow(int i_ink1, int i_ink2, int i_tx,int i_ty,int i_bx,int i_by);
	/// Swap 2 ink dans la palette
	void swapInkPalette(int i_ink1, int i_ink2);
	/// Affiche la palette soft
	void displaySoftPalette(std::ostream &io_o);
	/// Affiche la palette soft
	void displayHardPalette(std::ostream &io_o);

	//
	// Fonctions Plot/Get pixel, coordonnées CPC (fonction du mode)
	//
	/// Test si le pixel est dans la zone visible
	bool isPixelInside(const unsigned int i_posX, const unsigned int i_posY) const;
	/// Met un pixel dans la video
	void plotPixel(const unsigned int i_ink, const int i_posX, const int i_posY);
	/// Met un pixel dans la video
	void plotPixel(const unsigned int i_ink, const float i_posX, const float i_posY);
	/// Renvoie l'ink du pixel
	int getPixel(const int i_posX, const int i_posY) const;
	/// Renvoie l'ink du pixel
	int getPixel(const float i_posX, const float i_posY) const;
	/// Renvoie l'adresse du pixel
	int getPixelAddress(int i_x,int i_y) const;

	//
	// Fonctions affichage divers
	//
	/// Affiche une ligne (coord LU-RD)
	void drawLine(const unsigned int i_ink, const unsigned int i_x1, const unsigned int i_y1, const unsigned int i_x2, const unsigned int i_y2);
	/// Affiche un rectangle (coord LU-RD)
	void fillWindow(const unsigned int i_ink, const unsigned int i_x1, const unsigned int i_y1, const unsigned int i_x2, const unsigned int i_y2);
	/// Deplace une window (coord LU-RD)
	void moveWindow(const unsigned int xDest,const unsigned int ydest, const unsigned int i_x1, const unsigned int i_y1, const unsigned int i_x2, const unsigned int i_y2);
	/// Copy une window (coord LU-RD)
	void copyWindow(const unsigned int xDest,const unsigned int ydest, const unsigned int i_x1, const unsigned int i_y1, const unsigned int i_x2, const unsigned int i_y2);

	//
	// Fonctions Plot/Get octet, adresse video
	//
	/// Test si l'adresse est dans la zone visible
	bool isAddressVisible(const int i_adr) const;
	/// Passe a la ligne suivante
	unsigned int bc26(const unsigned int i_adr) const;
	/// Renvoie l'octet a l'adresse
	unsigned char getByte(const unsigned int i_adr) const;
	/// Met un octet dans la video (adr entre 0 & 7fff)
	void putByte(const int i_adr, const unsigned char i_byte);
	/// Met un octet dans la video (adr entre 0 & 7fff)
	void putBytes(const int i_adr, const unsigned char *i_byte, const unsigned int i_nbByte);
	/// Met un octet dans la video (adr entre 0 & 7fff)
	void putWindow(const int i_adr, const unsigned char *i_byte, const unsigned int i_sizeX,const unsigned int i_sizeY);

	//
	// Fonctions chargement/sauvegarde
	//
	/// Charge des datas dans la video
	void loadBytes(int i_adr, std::string i_filename);
	/// Charge une windows dans la video
	void loadWindow(int i_adr, std::string i_filename, int i_sizeX, int i_sizeY);
	/// Charge une palette OCP
	void loadOCPPalette(std::string i_filename);
	/// Charge un screen OCP la video
	void loadOCPScreen(std::string i_filename);
	/// Charge une windows dans la video
	void loadOCPWindow(int i_adr, std::string i_filename);
	/// Sauve les datas dans un fichier
	void saveBytes(int i_adr, std::string i_filename, int i_size);
	/// Sauve un windows dans un fichier
	void saveWindow(int i_adr, std::string i_filename, int i_sizeX, int i_sizeY);
	/// Sauve un windows dans un fichier
	void saveWindow(std::string i_filename, int i_x1, int i_y1,int i_x2, int i_y2);

	//
	// Fonctions ecran CPC / ecran SDL
	//
	/// Renvoie la position ecran CPC d'un pixel ecran SDL
	void windowToCPCCoordinate(int i_x, int i_y, int &o_x, int &o_y) const;
	/// Renvoie la position ecran SDL d'un pixel ecran CPC
	void CPCToWindowCoordinate(int i_x, int i_y, int &o_x, int &o_y, CPCSDLPixelPosition i_pos = Left) const;

	//
	// Fonctions overdraw ecran SDL (coordonnées CPC !)
	// !!! NEED TO BEGIN/END OVERDRAW !!!
	//
	/// Active l'overdraw
	void beginOverdraw();
	/// Desactive l'overdraw & display
	void endOverdraw();
	/// Affiche une ligne horizontale
	void overdrawHLine(unsigned int i_y, unsigned int i_x1, unsigned int i_x2, unsigned int i_r,unsigned int i_g,unsigned int i_b,CPCSDLPixelPosition i_pos = Up);
	/// Affiche une ligne verticale
	void overdrawVLine(unsigned int i_x, unsigned int i_y1, unsigned int i_y2, unsigned int i_r,unsigned int i_g,unsigned int i_b,CPCSDLPixelPosition i_pos = Left);
	/// Affiche un window
	void overdrawWindow(unsigned i_x1,unsigned int i_y1, unsigned int i_x2, unsigned int i_y2, unsigned int i_r,unsigned int i_g,unsigned int i_b);
protected:
	//
	// Fonctions internes
	//
	/// Met un pixel dans la memoire video CPC
	void plotPixelInMemory(const unsigned int i_ink, const int i_posX, const int i_posY);
	/// Met un pixel dans la video
	void plotPixelInVideo(const unsigned int i_ink, const int i_posX, const int i_posY);
	/// Met un octet dans la memoire video CPC
	void putByteInMemory(const unsigned int i_data, const unsigned char i_byte);
	/// Met un octet dans la video
	void putByteInVideo(const unsigned int i_adr, const unsigned char i_byte);
	/// Met un octet dans la memoire video CPC
	void putBytesInMemory(const unsigned int i_data, const unsigned char *i_bytes);
	/// Met un octet dans la video
	void putBytesInVideo(const unsigned int i_adr, const unsigned char *i_bytes);
	/// Remet toute la video CPC dans la video SDL
	void putAllByteInVideo();
};

#endif
