#include <qlabel.h>
#include <qpushbutton.h>
#include <qlayout.h>
#include <qfiledialog.h>
#include <qscrollview.h>
#include <qspinbox.h>
#include <qcheckbox.h>
#include <qvalidator.h>
#include <qimage.h>
#include <qmessagebox.h>
#include <qcombobox.h>
#include <qfile.h>
#include <qdesktopwidget.h>

#include "mainwindow.h"

MainWindow::MainWindow()
{
    // Determinate screen size
    QDesktopWidget *dw = new QDesktopWidget();
    QRect rect( dw->screenGeometry(this) );
    screenWidth = rect.width();
    screenHeight = rect.height();
    delete dw;

    // AALib initialization parameters
    params = aa_defparams;
    params.font = &aa_fontcourier;

    // Window title
    QString version = QString("%1.%2.%3").arg(QString::number(Major_Version))
        .arg(QString::number(Minor_Version)).arg(QString::number(Mini_Version));

    setCaption(QString("Pic2AA v%1").arg(version));

    // Main window
    QScrollView *sv = new QScrollView(this);
    image = new QLabel(sv);
    sv->addChild(image);

    QPushButton* open = new QPushButton("Open", this);
    QLabel* lWidth = new QLabel("Width (characters):", this);
    QLabel* lHeight = new QLabel("Height (characters):", this);
    synchro = new QCheckBox("Synchronized", this);
    width = new QSpinBox(this);
    height = new QSpinBox(this);
    QPushButton* convert = new QPushButton("Convert", this);
    QPushButton* preview = new QPushButton("Preview", this);
    QLabel* lFont = new QLabel("Render font:", this);
    font = new QComboBox(false, this);
    QLabel* lFormat = new QLabel("Save format:", this);
    format = new QComboBox(false, this);

    width->setMinValue(20);
    height->setMinValue(10);
    width->setMaxValue(300);
    height->setMaxValue(150);
    width->setValue(80);
    height->setValue(40);
    height->setEnabled(true);
    synchro->setChecked(false);

    font->insertItem("FontCourier");
    font->insertItem("Font8");
    font->insertItem("Font9");
    font->insertItem("Font14");
    font->insertItem("Font16");
    font->insertItem("FontLine");
    font->insertItem("FontGL");
    font->insertItem("FontX13");
    font->insertItem("FontX16");
    font->insertItem("FontX13B");

    format->insertItem("Text");
    format->insertItem("ANSI");
    format->insertItem("nHTML");
    format->insertItem("HTML");
    format->insertItem("HTML Alt");
    format->insertItem("More");
    format->insertItem("HP");
    format->insertItem("HP2");
    format->insertItem("Zephyr");
    format->insertItem("IRC");

    QGridLayout *g = new QGridLayout(this);
    g->addMultiCellWidget(sv, 0, 1, 0, 1);
    g->addWidget(lWidth, 2, 0);
    g->addWidget(width, 2, 1);
    g->addWidget(lHeight, 3, 0);
    g->addWidget(height, 3, 1);
    g->addMultiCellWidget(synchro, 4, 4, 0, 1, Qt::AlignHCenter);
    g->addWidget(lFont, 5, 0);
    g->addWidget(font, 5, 1);
    g->addWidget(lFormat, 6, 0);
    g->addWidget(format, 6, 1);
    g->addMultiCellWidget(preview, 7, 7, 0, 1);
    g->addWidget(open, 8, 0);
    g->addWidget(convert, 8, 1);
    g->setRowSpacing(7, 40);

    this->resize(450, 450);

    connect(open, SIGNAL(clicked()), this, SLOT(openFile()));
    connect(synchro, SIGNAL(stateChanged(int)), this, SLOT(synchroChanged(int)));
    connect(convert, SIGNAL(clicked()), this, SLOT(convertToAA()));
    connect(preview, SIGNAL(clicked()), this, SLOT(showPreview()));
}

void MainWindow::openFile()
{
    QString file = QFileDialog::getOpenFileName("~/",
            "Images (*.png *.xpm *.jpg *.gif *.bmp *.pnm *.xbm)",
            this,
            "open file dialog",
            "Choose image file"
        );

    if (file)
        image->setPixmap( QPixmap(file) );
}

void MainWindow::synchroChanged(int status)
{
    height->setEnabled(!status);
}

void MainWindow::convertToAA()
{
    if (!image->pixmap())
        return;

    // Filename to save under
    QString file = QFileDialog::getSaveFileName(
            "~/",
            QString::null,
            this,
            "save file dialog",
            "Choose a filename to save under"
        );

    if (QFile::exists(file))
    {
        int ret = QMessageBox::warning(
                this,
                "File exists",
                "Do you want to overwrite existing file?",
                QMessageBox::Yes,
                QMessageBox::No
            );

        if (ret == QMessageBox::No)
            return;

        if (!QFile::remove(file))
        {
            QMessageBox::critical(
                    this,
                    "Error",
                    QString("Cannot remove file %1!").arg(file),
                    QMessageBox::Ok,
                    QMessageBox::NoButton
                );

            return;
        }
    }

    // Converting pixmap
    QPixmap pixmap(*(image->pixmap()));

    if (width->value() <= 20)
        width->setValue(20);

    if (height->value() <= 10)
        height->setValue(10);

    params.width = width->value();
    if (synchro->isChecked())
    {
        double ratio = double(pixmap.height())/pixmap.width();
        params.height = int(params.width*ratio+0.5); // +0.5 for quick rounding
    }
    else
    {
        params.height = height->value();
    }

    // Setting up selected configuration
    setupFont();
    setupFormat();

    // Initiating AA-Lib engine
    saveData.name = (char*)file.latin1();
    context = aa_init(&save_d, &params, &saveData);

    int w = aa_imgwidth(context), h = aa_imgheight(context);
    unsigned char* buff = aa_image(context);

    // Drawing AA image
    QImage img(pixmap.convertToImage().scale(w, h));
    for ( int y = 0; y < h; y++ )
    {
        for ( int x = 0; x < w; x++ )
            *(buff+x+(y*w)) = (unsigned char)qGray(img.pixel(x, y));
    }

    aa_fastrender(context, 0, 0, aa_scrwidth(context), aa_scrheight(context));
    aa_flush(context);

    // Closing AA context
    aa_close(context);
    context = NULL;
}

void MainWindow::showPreview()
{
    if (!image->pixmap())
        return;

    // Converting pixmap
    QPixmap pixmap(*(image->pixmap()));

    if (width->value() <= 20)
        width->setValue(20);

    if (height->value() <= 10)
        height->setValue(10);

    params.width = width->value();
    if (synchro->isChecked())
    {
        double ratio = double(pixmap.height())/pixmap.width();
        params.height = int(params.width*ratio+0.5); // +0.5 for quick rounding
    }
    else
    {
        params.height = height->value();
    }

    // Width and height checking
    if ( int(params.height*14.222+0.5) > screenHeight )
    {
        int suggested = int(double(screenHeight)/14.222);
        QMessageBox::warning(
                this,
                "Warning!",
                QString("Preview with this height (%1) cannot be displayed.\nMaximal displayable height is %2.")
                    .arg(QString::number(params.height)).arg(QString::number(suggested)),
                QMessageBox::Ok,
                QMessageBox::NoButton
            );

        return;
    }
    if ( int(params.width*8.2+0.5) > screenWidth )
    {
        int suggested = int(double(screenWidth)/8.2);
        QMessageBox::warning(
                this,
                "Warning!",
                QString("Preview with this width (%1) cannot be displayed.\nMaximal displayable width is %2.")
                    .arg(QString::number(params.width)).arg(QString::number(suggested)),
                QMessageBox::Ok,
                QMessageBox::NoButton
            );

        return;
    }

    // Setting up selected configuration
    setupFont();

    // Initiating AA-Lib engine
    context = aa_init(&X11_d, &params, NULL);

    int w = aa_imgwidth(context), h = aa_imgheight(context);
    unsigned char* buff = aa_image(context);

    // Drawing AA image preview
    QImage img(pixmap.convertToImage().scale(w, h));
    for ( int y = 0; y < h; y++ )
    {
        for ( int x = 0; x < w; x++ )
            *(buff+x+(y*w)) = (unsigned char)qGray(img.pixel(x, y));
    }

    aa_fastrender(context, 0, 0, aa_scrwidth(context), aa_scrheight(context));
    aa_flush(context);
}

void MainWindow::setupFont()
{
    switch (font->currentItem())
    {
        case 0:
            params.font = &aa_fontcourier;
            break;
        case 1:
            params.font = &aa_font8;
            break;
        case 2:
            params.font = &aa_font9;
            break;
        case 3:
            params.font = &aa_font14;
            break;
        case 4:
            params.font = &aa_font16;
            break;
        case 5:
            params.font = &aa_fontline;
            break;
        case 6:
            params.font = &aa_fontgl;
            break;
        case 7:
            params.font = &aa_fontX13;
            break;
        case 8:
            params.font = &aa_fontX16;
            break;
        case 9:
            params.font = &aa_fontX13B;
            break;
    }
}

void MainWindow::setupFormat()
{
    switch (format->currentItem())
    {
        case 0:
            saveData.format = &aa_text_format;
            break;
        case 1:
            saveData.format = &aa_ansi_format;
            break;
        case 2:
            saveData.format = &aa_nhtml_format;
            break;
        case 3:
            saveData.format = &aa_html_format;
            break;
        case 4:
            saveData.format = &aa_html_alt_format;
            break;
        case 5:
            saveData.format = &aa_more_format;
            break;
        case 6:
            saveData.format = &aa_hp_format;
            break;
        case 7:
            saveData.format = &aa_hp2_format;
            break;
        case 8:
            saveData.format = &aa_zephyr_format;
            break;
        case 9:
            saveData.format = &aa_irc_format;
            break;
    }
}
