#include <ctype.h>
#include <QPainter>
#include <QFile>
#include <QTimer>
#include <QKeyEvent>
#include <calculator.h>


struct {
	char symbol;
	int x, y;
	const char *file;
} buttonList[] = {
	{ '=', 217, 158,    "equal" },
	{ '+', 188, 140,     "plus" },
	{ '-', 252, 140,    "minus" },
	{ '*', 192, 135,   "double" },
	{ '/', 192, 193, "division" },
	{ '(', 107, 157,     "star" },
	{ ')', 297, 157,    "sharp" }
};


const int buttonListSize = sizeof(buttonList)/sizeof(buttonList[0]);


class Button : public QLabel
{
public:
	Button(QWidget *parent, int idx) : QLabel(parent), index(idx) {
	    setDown(false);
	    move(buttonList[index].x, buttonList[index].y);
	}
	void setDown(bool down) {
	    setPixmap(QPixmap(QString("images/btn_") +  buttonList[index].file + ((down) ? "_r.png" : ".png")));
	    raise();
	}
	int index;
};


Calculator::Calculator(QWidget *parent) : QWidget(parent)
{
    QLabel *lab = new QLabel(this);
    lab->setText("Calculator written in C++");

    QLabel *bg = new QLabel(this);
    bg->setPixmap(QPixmap("images/calculator_bg.png"));
    bg->move(95, 35);

    QPalette p;
    p.setColor(QPalette::WindowText,Qt::white);
    input = new QLabel(this);
    input->setFont(QFont("Arial",14));
    input->setText("");
    input->setGeometry(120, 58, 230, 20);
    input->setPalette(p);
    output = new QLabel(this);
    output->setFont(QFont("Arial",14));
    output->setText("= 0");
    output->setGeometry(120, 89, 230, 20);
    output->setPalette(p);

    for (int i = 0; i < buttonListSize; i++)
        button[i] = new Button(this, i);
}


Calculator::~Calculator()
{
}


int Calculator::indexForKey(int key)
{
    int i = -1;
    switch (key) {
	case Qt::Key_Enter:      i = 0; break; // OK 
	case Qt::Key_Left:       i = 1; break; // Left
	case Qt::Key_Right:      i = 2; break; // Right
	case Qt::Key_Up:         i = 3; break; // Up
	case Qt::Key_Down:       i = 4; break; // Down
	case Qt::Key_Asterisk:   i = 5; break; // '*'
	case Qt::Key_NumberSign: i = 6; break; // '#'
    }
    return i;
}


static QString calculateExpression(QString input)
{
    input.remove(QChar('\''));
    input.replace(QString("+"), QString(" + "));
    input.replace(QString("-"), QString(" - "));
    input.replace(QString("/"), QString(" / "));
    input.replace(QString("*"), QString(" \\* "));
    input.replace(QString("("), QString(" \\( "));
    input.replace(QString(")"), QString(" \\) "));
    input = "expr " + input + " > /tmp/result.txt 2> /tmp/result.txt";
    ::system(input.toLatin1().data());
    QFile f("/tmp/result.txt");
    f.open(QFile::ReadOnly);
    QString result = "= " + f.readAll();
    result.replace(QString("= expr: syntax error"),QString("Wrong Input"));
    result.replace(QString("= expr: too few arguments"),QString("No Input"));
    result.replace(QString("= expr: division by zero"),QString("Can not divide by zero"));
    return result;
}


static void showPopupDialog(QString message)
{
    QLabel *popupImg = new QLabel(0); 
    QFontMetrics fm(popupImg->font());
    QImage img(480, 272, QImage::Format_RGB32);
    QPainter p(&img);
    p.drawPixmap(0, 0, QPixmap("images/depth_bg.jpg"));
    p.drawPixmap(0, 244, QPixmap("images/softykey.png"));
    p.drawImage((480-329)/2, (272-176)/2-12, QImage("images/big_popup_01.png"));
    p.drawText((480-fm.width(message))/2, 140, message);
    p.drawText(10, 10, "Popup Example in C++");
    p.end();
    popupImg->setPixmap(QPixmap::fromImage(img));
    popupImg->setGeometry(0,0,480,272);
    popupImg->show();
    QTimer::singleShot(2000, popupImg, SLOT(deleteLater()));
}


void Calculator::keyPressEvent(QKeyEvent *ke)
{
    int i = indexForKey(ke->key());
    if (i != -1) {
        if (i == 0) {
	    QString result = calculateExpression(input->text());
	    if ( result.left(1) != "=" ) {
		showPopupDialog(result);
	    	output->setText("= 0");
	    } else {
	    	output->setText(result);
	    }
	    //output->setText(calculateExpression(input->text()));
        } else {
            QString existing = input->text();
            QChar last = existing.right(1).at(0);
	    if ( last == '*' || last == '/' || last == '+' || last == '-')
	        existing = existing.left(existing.length() - 1); 
            input->setText(existing + QChar(buttonList[i].symbol));
        }
        button[i]->setDown(true);
	return;
    }

    switch ( ke->key() ) {
	case Qt::Key_0: input->setText(input->text() + "0"); return;
	case Qt::Key_1: input->setText(input->text() + "1"); return;
	case Qt::Key_2: input->setText(input->text() + "2"); return;
	case Qt::Key_3: input->setText(input->text() + "3"); return;
	case Qt::Key_4: input->setText(input->text() + "4"); return;
	case Qt::Key_5: input->setText(input->text() + "5"); return;
	case Qt::Key_6: input->setText(input->text() + "6"); return;
	case Qt::Key_7: input->setText(input->text() + "7"); return;
	case Qt::Key_8: input->setText(input->text() + "8"); return;
	case Qt::Key_9: input->setText(input->text() + "9"); return;
    }

    // Handle any other keys
    if ( ke->key() == Qt::Key_Context1 ) {            // OK
	QString result = calculateExpression(input->text());
	if ( result.left(1) != "=" ) {
	    showPopupDialog(result);
	    output->setText("= 0");
	} else {
	    output->setText(result);
	}
    } else if ( ke->key() == Qt::Key_Context2 ) {     // AC
        input->setText("");
        output->setText("= 0");
    } else if ( ke->key() == Qt::Key_Context3 ) {  // Backspace
        input->setText(input->text().left(input->text().length() - 1)); 
    }
}


void Calculator::keyReleaseEvent(QKeyEvent *ke)
{
    int i = indexForKey(ke->key());
    if (i != -1)
        button[i]->setDown(false);
}

