/***************************************************************************
 *   Copyright (C) 2008 by Jürgen Böhm   *
 *   juergen.boehm@aviduratas.de   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <qrect.h>

#include "qjbdisplayvport.h"

#include "simemu.h"

#include <X11/Xlib.h>
#include <X11/X.h>




using namespace std;


static int xtoscan[128] =

{

// 00 to 0f

0x0000,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,

0x0000,
0x0076,
0x0016,
0x001E,
0x0026,
0x0025,
0x002E,
0x0036,

// 10 to 1f

0x003D,
0x003E,
0x0046,
0x0045,
0x004E,
0x0055,
0x0066,
0x000D,

0x0015,
0x001D,
0x0024,
0x002D,
0x002C,
0x0035,
0x003C,
0x0043,

// 20 to 2f

0x0044,
0x004D,
0x0054,
0x005B,
0x005A,
0x0014,
0x001C,
0x001B,

0x0023,
0x002B,
0x0034,
0x0033,
0x003B,
0x0042,
0x004B,
0x004C,

// 30 to 3f

0x0052,
0x000E,
0x0012,
0x005D,
0x001A,
0x0022,
0x0021,
0x002A,

0x0032,
0x0031,
0x003A,
0x0041,
0x0049,
0x004A,
0x0059,
0x007C,

// 40 to 4f

0x0011,
0x0029,
0x0058,
0x0005,
0x0006,
0x0004,
0x000C,
0x0003,

0x000B,
0x0083,
0x000A,
0x0001,
0x0009,
0x0077,
0x007E,
0x006C,

// 50 to 5f

0x0075,
0x007D,
0x007B,
0x006B,
0x0073,
0x0074,
0x0079,
0x0069,

0x0072,
0x007A,
0x0070,
0x0071,
0x0000,
0x0000,
0x0061,
0x0078,

// 60 to 6f

0x0007,
0xE06C,
0xE075,
0xE07D,
0xE06B,
0x0000,
0xE074,
0xE069,

0xE072,
0xE07A,
0xE070,
0xE071,
0xE05A,
0xE014,
0x0000,
0x0000,

// 70 to 7f

0x0000,
0xE011,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,

0x0000,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000,

};



/*
QjbDisplayVPort::QjbDisplayVPort()
{
}


QjbDisplayVPort::~QjbDisplayVPort()
{
}
*/

void enqueueScanCode ( deque<int> &qq, int data, int released ) {

	if (data) {

		if ((data >> 8) == 0xE0)
			qq.push_back (0xE0);

		if (released)
			qq.push_back (0xF0);

		qq.push_back ( data & 0xFF );

	};

} 


bool QjbDisplayVPort::x11Event ( XEvent* xev) {

	if (xev->type == KeyPress) {

		XKeyEvent *xkev = (XKeyEvent*) xev;

		int kc = xkev->keycode;

		kc = xtoscan[kc];

		enqueueScanCode ( keyPressedQueue, kc, 0 );

//		keyPressedQueue.push_back ( xkev->keycode );

		return false;

	} else if (xev->type == KeyRelease) {

		XKeyEvent *xkev = (XKeyEvent*) xev;

		int kc = xkev->keycode;

		kc = xtoscan[kc];

		enqueueScanCode ( keyPressedQueue, kc, 1);

//		enqueueScanCode ( keyReleasedQueue, kc, 1);

//		keyReleasedQueue.push_back ( 0xf0 );

//		keyReleasedQueue.push_back ( xkev->keycode );

		return false;

	};

	return false;

}




char* QjbDisplayVPort::getMem (int lines, int cols) {

			char* p = new char[4 * lines * cols];

			if (p)
				return p;
			else {
					throw bad_alloc();
			};

}


void QjbDisplayVPort::setFontInfo () {

    fm = new QFontMetrics ( *outFont );
    pixelWidthX = fm->maxWidth(); //+fm->leftBearing('@')+fm->rightBearing('@');
    pixelHeight = fm->height()+1;

}




void QjbDisplayVPort::drawCharacter (QPainter* p, int row, int col) {

	int pos = row * icols + col;

	unsigned char c = (pos < bufsize) ? mem[4*pos] : 0;

	if (mem[4*pos+1] == 1) {

		p->setBackgroundColor ( QColor ( 30, 30, 210 ) );
		p->setPen ( QColor ( 230, 230, 230 ) );

	}

	c = ((32 <= c) && (c <= 127)) ? c : 32;

	int cxx = col * pixelWidthX;
	int cyy = row * pixelHeight + fm->ascent ();

	int ccx, ccy;

	p->drawText ( cxx + 2, cyy, QString(QChar(c)) );

	p->setPen(QColor(0,0,0));
	p->setBackgroundColor(qcolb);

}


int ndiv (int q, int d) {

	int r = q / d;
	if (q % d != 0)
		r += 1;

	return r;

}


void QjbDisplayVPort::drawContents ( QPainter * p, int clipx, int clipy, int clipw, int cliph ) {


//	QScrollView::drawContents (p, clipx, clipy, clipw, cliph );

	clipx -= 2;

	int leftCol = clipx / pixelWidthX;
	int rightCol = ndiv ((clipx + clipw-1),  pixelWidthX );

	int upperRow = clipy / pixelHeight;
	int lowerRow = ndiv ((clipy + cliph-1),  pixelHeight);

//	cerr << "lc rc ur lr = " << leftCol << "  " << rightCol << " " << upperRow << " " << lowerRow << endl;


	p->setPen (QColor (0,0,0));
	p->setBackgroundMode ( OpaqueMode );
	p->setFont ( *outFont );

	qcolb = p->backgroundColor();


	if ((upperRow < ilines) && (leftCol < icols)) {

		lowerRow = (lowerRow < ilines) ? lowerRow : ilines - 1;

		rightCol = (rightCol < icols) ? rightCol : icols - 1;

		for (int i = upperRow; i <= lowerRow; i++ ) {
			for (int j = leftCol; j <= rightCol; j++ ) {
	
				drawCharacter (p, i, j );
	
			};
		};

	};

}



void QjbDisplayVPort::paintEvent ( QPaintEvent * ev) {

	QPainter p(this);

	QRect r = ev->rect ();

	drawContents ( &p, r.x(), r.y(), r.width(), r.height() );


};


void QjbDisplayVPort::byteWrite (int offset, char val)
{

	mem[offset] = val;


	offset = offset / 4;

	int line = offset / icols;
	int col = offset % icols;

	repaint ( col * pixelWidthX - 1, line * pixelHeight - 1 , pixelWidthX + 3, pixelHeight + 3 );

	qApp->processEvents ();




}


void QjbDisplayVPort::wordWrite (int offset, int val)
{

//	byteWrite ( offset + 3, ((char) (val & 255)) );
	val = val>>8;
//	byteWrite ( offset + 2, ((char) (val & 255)) );
	val = val>>8;
//	byteWrite ( offset + 1, ((char) (val & 255)) );

	mem[offset+1] = ((char) (val & 255));
	val = val>>8;
	byteWrite ( offset, ((char) (val & 255)) );

}


