

#include "simuqt.h"

#include <vpi_user.h>

#include <qimage.h>
#include <qpixmap.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qtextedit.h>
#include <qfile.h>
#include <qfiledialog.h>
#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qprinter.h>
#include <qapplication.h>
#include <qaccel.h>
#include <qtextstream.h>
#include <qpainter.h>
#include <qpaintdevicemetrics.h>
#include <qwhatsthis.h>

#include "filesave.xpm"
#include "fileopen.xpm"
#include "fileprint.xpm"

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

deque<int> keyPressedQueue;
deque<int> keyReleasedQueue;

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,
0x0000,
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,
0x0000,
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,

};




simuqt::simuqt()
    : QMainWindow( 0, "simuqt", WDestructiveClose )
{
    printer = new QPrinter;
    QPixmap openIcon, saveIcon, printIcon;

    QToolBar * fileTools = new QToolBar( this, "file operations" );
    fileTools->setLabel( tr("File Operations") );

    openIcon = QPixmap( fileopen );
    QToolButton * fileOpen
	= new QToolButton( openIcon, tr("Open File"), QString::null,
			   this, SLOT(choose()), fileTools, "open file" );

    saveIcon = QPixmap( filesave );
    QToolButton * fileSave
	= new QToolButton( saveIcon, tr("Save File"), QString::null,
			   this, SLOT(save()), fileTools, "save file" );

    printIcon = QPixmap( fileprint );
    QToolButton * filePrint
	= new QToolButton( printIcon, tr("Print File"), QString::null,
			   this, SLOT(print()), fileTools, "print file" );


    (void)QWhatsThis::whatsThisButton( fileTools );

    QString fileOpenText = tr("<p><img source=\"fileopen\"> "
	         "Click this button to open a <em>new file</em>. <br>"
                 "You can also select the <b>Open</b> command "
                 "from the <b>File</b> menu.</p>");

    QWhatsThis::add( fileOpen, fileOpenText );

    QMimeSourceFactory::defaultFactory()->setPixmap( "fileopen", openIcon );

    QString fileSaveText = tr("<p>Click this button to save the file you "
                 "are editing. You will be prompted for a file name.\n"
                 "You can also select the <b>Save</b> command "
                 "from the <b>File</b> menu.</p>");

    QWhatsThis::add( fileSave, fileSaveText );

    QString filePrintText = tr("Click this button to print the file you "
                 "are editing.\n You can also select the Print "
                 "command from the File menu.");

    QWhatsThis::add( filePrint, filePrintText );


    QPopupMenu * file = new QPopupMenu( this );
    menuBar()->insertItem( tr("&File"), file );


    file->insertItem( tr("&New"), this, SLOT(newDoc()), CTRL+Key_N );

    int id;
    id = file->insertItem( openIcon, tr("&Open..."),
			   this, SLOT(choose()), CTRL+Key_O );
    file->setWhatsThis( id, fileOpenText );

    id = file->insertItem( saveIcon, tr("&Save"),
			   this, SLOT(save()), CTRL+Key_S );
    file->setWhatsThis( id, fileSaveText );

    id = file->insertItem( tr("Save &As..."), this, SLOT(saveAs()) );
    file->setWhatsThis( id, fileSaveText );

    file->insertSeparator();

    id = file->insertItem( printIcon, tr("&Print..."),
			   this, SLOT(print()), CTRL+Key_P );
    file->setWhatsThis( id, filePrintText );

    file->insertSeparator();

		file->insertItem ( tr("Stop Simulation"), this, SLOT(stopSimu()) );

		file->insertSeparator();

    file->insertItem( tr("&Close"), this, SLOT(close()), CTRL+Key_W );

    file->insertItem( tr("&Quit"), qApp, SLOT( closeAllWindows() ), CTRL+Key_Q );

    menuBar()->insertSeparator();

    QPopupMenu * help = new QPopupMenu( this );
    menuBar()->insertItem( tr("&Help"), help );

    help->insertItem( tr("&About"), this, SLOT(about()), Key_F1 );
    help->insertItem( tr("About &Qt"), this, SLOT(aboutQt()) );
    help->insertSeparator();
    help->insertItem( tr("What's &This"), this, SLOT(whatsThis()), SHIFT+Key_F1 );

    e = new QjbTextEdit( this, "editor" );
    e->setFocus();
    setCentralWidget( e );

		QString blank_line;

		blank_line.fill ( '+', max_cols );

		for ( int i = 0; i < max_lines; i++ )
			e->append ( blank_line + "\n" );

		e->setOverwriteMode( true );

		QFont courFont ( "Courier", 10 );

		e->setFont ( courFont );

    statusBar()->message( tr("Ready"), 2000 );

    resize( 1200, 1000 );
}


simuqt::~simuqt()
{
    delete printer;
}



void simuqt::newDoc()
{
    simuqt *ed = new simuqt;
    ed->setCaption(tr("Qt Example - Application"));
    ed->show();
}

void simuqt::choose()
{
    QString fn = QFileDialog::getOpenFileName( QString::null, QString::null,
					       this);
    if ( !fn.isEmpty() )
	load( fn );
    else
	statusBar()->message( tr("Loading aborted"), 2000 );
}


void simuqt::load( const QString &fileName )
{
    QFile f( fileName );
    if ( !f.open( IO_ReadOnly ) )
	return;

    QTextStream ts( &f );
    e->setText( ts.read() );
    e->setModified( FALSE );
    setCaption( fileName );
    statusBar()->message( tr("Loaded document %1").arg(fileName), 2000 );
}


void simuqt::save()
{
    if ( filename.isEmpty() ) {
	saveAs();
	return;
    }

    QString text = e->text();
    QFile f( filename );
    if ( !f.open( IO_WriteOnly ) ) {
	statusBar()->message( tr("Could not write to %1").arg(filename),
			      2000 );
	return;
    }

    QTextStream t( &f );
    t << text;
    f.close();

    e->setModified( FALSE );

    setCaption( filename );

    statusBar()->message( tr( "File %1 saved" ).arg( filename ), 2000 );
}


void simuqt::saveAs()
{
    QString fn = QFileDialog::getSaveFileName( QString::null, QString::null,
					       this );
    if ( !fn.isEmpty() ) {
	filename = fn;
	save();
    } else {
	statusBar()->message( tr("Saving aborted"), 2000 );
    }
}


void simuqt::print()
{
    // ###### Rewrite to use QSimpleRichText to print here as well
    const int Margin = 10;
    int pageNo = 1;

    if ( printer->setup(this) ) {		// printer dialog
	statusBar()->message( tr("Printing...") );
	QPainter p;
	if( !p.begin( printer ) )               // paint on printer
	    return;

	p.setFont( e->font() );
	int yPos	= 0;			// y-position for each line
	QFontMetrics fm = p.fontMetrics();
	QPaintDeviceMetrics metrics( printer ); // need width/height
						// of printer surface
	for( int i = 0 ; i < e->lines() ; i++ ) {
	    if ( Margin + yPos > metrics.height() - Margin ) {
		QString msg( "Printing (page " );
		msg += QString::number( ++pageNo );
		msg += ")...";
		statusBar()->message( msg );
		printer->newPage();		// no more room on this page
		yPos = 0;			// back to top of page
	    }
	    p.drawText( Margin, Margin + yPos,
			metrics.width(), fm.lineSpacing(),
			ExpandTabs | DontClip,
			e->text( i ) );
	    yPos = yPos + fm.lineSpacing();
	}
	p.end();				// send job to printer
	statusBar()->message( tr("Printing completed"), 2000 );
    } else {
	statusBar()->message( tr("Printing aborted"), 2000 );
    }
}

void simuqt::stopSimu () {
	
	stopSimuFlag = 1;

}

void simuqt::closeEvent( QCloseEvent* ce )
{
    if ( !e->isModified() ) {
	ce->accept();
	return;
    }

    switch( QMessageBox::information( this, tr("Qt Application Example"),
				      tr("Do you want to save the changes"
				      " to the document?"),
				      tr("Yes"), tr("No"), tr("Cancel"),
				      0, 1 ) ) {
    case 0:
	save();
	ce->accept();
	break;
    case 1:
	ce->accept();
	break;
    case 2:
    default: // just for sanity
	ce->ignore();
	break;
    }
}


void simuqt::about()
{
    QMessageBox::about( this, tr("Qt Application Example"),
			tr("This example demonstrates simple use of "
			"QMainWindow,\nQMenuBar and QToolBar."));
}


void simuqt::aboutQt()
{
    QMessageBox::aboutQt( this, tr("Qt Application Example") );
}


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 QjbTextEdit::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 ( keyReleasedQueue, kc, 1);

//		keyReleasedQueue.push_back ( 0xf0 );

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

		return false;

	};

	return false;

}
	
void simuqt::customEvent (QCustomEvent * ev) {

	// vpi_printf ( "in custom Event " );

	if (ev->type() == 65432) {
		
		QxycEvent * ev1 = (QxycEvent* )ev;

		e->placeCursor( QPoint(ev1->x, ev1->y), 0 );
		e->setSelection(ev1->x,ev1->y,ev1->x,(ev1->y)+1);
		e->del();
		e->insert( QChar(ev1->c + 32) );

		this->repaint();

	} 

}




int put_xy_c (int x, int y, int c)
{
// return mw_global->put_xy_c (x,y,c);

QxycEvent * evc = new QxycEvent (x,y,c);

QApplication::postEvent ( mw_global, evc );

}

int getKeyPressed () {

	if (! keyPressedQueue.empty()) {
		
		int res = keyPressedQueue.front();
		keyPressedQueue.pop_front ();
		return res;
		
	} else {

		return -1;

	}

}


int getKeyReleased () {

	if (! keyReleasedQueue.empty()) {
		
		int res = keyReleasedQueue.front();
		keyReleasedQueue.pop_front ();
		return res;		

	} else {

		return -1;

	}

}



