#include "receiptgenerator.h"
#include <settingsservice.h>
#include <settings/globalsettings.h>

#include <QTextCodec>
#include <QFile>

#ifdef _WIN32
#include <Windows.h>
#include <winspool.h>
#endif

const QString ReceiptGenerator::DIACRITIC = "ÂâÁáÄäĂăĄąĆćČčÇçĎďĐđÉéËëĚěĘęÍíÎîĹĺĽľŁłŃńŇňÓóÖöÔôŐőŔŕŘřŚśŠšŞşŤťŢţÚúÜüŮůŰűÝýŹźŽžŻż";
const QString ReceiptGenerator::NON_DIACRITIC = "AaAaAaAaAaCcCcCcDdDdEeEeEeEeIiIiLlLlLlNnNnOoOoOoOoRrRrSsSsSsTtTtUuUuUuUuYyZzZzZz";

ReceiptGenerator::ReceiptGenerator()
{

}

void ReceiptGenerator::setVoucher(const QSharedPointer<Voucher> &voucher)
{
    m_voucher = voucher;
}

void ReceiptGenerator::setSettings(const ShopSettingsPtr &settings)
{
    m_settings = settings;
}

void ReceiptGenerator::save()
{
    SettingsService srvShopSettings("SHOP");
    ShopSettingsPtr shopSettings = srvShopSettings.loadSettings<ShopSettings>();

    QString outFile = m_outputFile;

    if (outFile.isEmpty())
    {
        outFile = shopSettings->output();
    }

    QFile file(outFile);
    file.open(QIODevice::WriteOnly);
    file.write(generate());
    file.close();
}

void ReceiptGenerator::print()
{
#ifdef _WIN32
    SettingsService srvShopSettings("SHOP");
    ShopSettingsPtr shopSettings = srvShopSettings.loadSettings<ShopSettings>();
    QString printer = shopSettings->output();

    HANDLE hPrinter;
    DOC_INFO_1 docInfo;
    DWORD dwJob;
    DWORD dwBytes;
    BOOL bStatus = FALSE;

    if (OpenPrinter((LPWSTR)printer.toStdWString().c_str(), &hPrinter, NULL))
    {
        docInfo.pDocName = L"Uctenka";
        docInfo.pOutputFile = NULL;
        docInfo.pDatatype = L"RAW";

        dwJob = StartDocPrinter(hPrinter, 1, (LPBYTE)&docInfo);
        if (dwJob > 0)
        {
            if (!StartPagePrinter(hPrinter))
            {
                ClosePrinter(hPrinter);
                return;
            }
            QByteArray data = generate();
            BOOL bPrinted = WritePrinter(hPrinter, (LPBYTE)data.data(), data.length(), &dwBytes);
            EndPagePrinter(hPrinter);
            EndDocPrinter(hPrinter);

            if (!bPrinted)
            {
                DWORD dwErr = GetLastError();
                int i = 1;
            }
        }
    }

    ClosePrinter(hPrinter);
#else
    save();
#endif
}

QString ReceiptGenerator::outputFile() const
{
    return m_outputFile;
}

void ReceiptGenerator::setOutputFile(const QString &outputFile)
{
    m_outputFile = outputFile;
}

QByteArray ReceiptGenerator::generate()
{
    QByteArray out;

    char printMode = 8 | 16 ;

    SettingsService srvGsSettings("CORE");
    SettingsService srvShopSettings("SHOP");

    ShopSettingsPtr shopSettings = srvShopSettings.loadSettings<ShopSettings>();
    GlobalSettingsPtr gs = srvGsSettings.loadSettings<GlobalSettings>();

    bool hasDoubleItem = false;
    bool first = true;

    do
    {
        out.append("\x1b\x40\x1b\x61\x01");
        out.append(prepareString(gs->firmName()));
        out.append("\x0a");
        out.append(prepareString(gs->street() + " " + gs->houseNumber()));
        out.append("\x0a");
        out.append(prepareString(gs->zipCode() + " " + gs->city()));
        out.append("\x0a");
        out.append(prepareString("IC: " + QString::number(gs->ic())));
        out.append("\x0a");
        out.append(prepareString("DIC: " + gs->dic()));
        out.append("\x0a");
        out.append(prepareString("ID provozovny: " + shopSettings->eetShopId()));
        out.append("\x0a");
        out.append(prepareString("ID pokladny: " + shopSettings->eetRegisterId()));
        out.append("\x0a");
        out.append(prepareString("Cislo uctenky: " + m_voucher->numSer()));
        out.append("\x0a");

        out.append("\x1b\x21");
        out.append(printMode);
        for (int i = 0; i < shopSettings->lettersPerLine(); i++ )
        {
            out.append("-");
        }
        out.append("\x1b\x21");
        out.append((char)0);
        out.append("\x0a");

        foreach (QSharedPointer<VoucherItem> item, m_voucher->items()) {
            QString count = QString::number(item->count());
            QString name = item->name();
            QString price = QString::number(item->price().toDouble(), 'f', 2);

            hasDoubleItem = hasDoubleItem || name == shopSettings->doublePrintItem();

            int numSpaces = 0;
            name = count + "x " + name;

            if (gs->vatPayer())
            {
                out.append(prepareString("DPH " + QString::number(item->vatRate().toDouble(), 'f', 0)) + "%");
                out.append("\x0a");
            }

            if ((name.length() + price.length()) < shopSettings->lettersPerLine())
            {
                numSpaces = shopSettings->lettersPerLine() - (name.length() + price.length());
                out.append(prepareString(name));
            }
            else
            {
                numSpaces = shopSettings->lettersPerLine() - (name.length() + price.length());
                out.append(prepareString(name));
                out.append("\x0a");
            }

            for (int i = 0; i < numSpaces; i++)
            {
                out.append(" ");
            }
            out.append(prepareString(price));
            out.append("\x0a");
        }

        out.append("\x1b\x21");
        out.append(printMode);
        for (int i = 0; i < shopSettings->lettersPerLine(); i++ )
        {
            out.append("-");
        }
        out.append("\x1b\x21");
        out.append((char)0);
        out.append("\x0a");

        if (gs->vatPayer())
        {
            QString zaklad = "Zaklad DPH ";
            QString dph = "DPH ";
            QString output;
            QDecDouble zero(0);

            if (m_voucher->vatAmountHigh() > zero)
            {
                output = zaklad + QString::number(m_voucher->vatRateHigh().toDouble()) + "%";
                out.append(prepareString(output));
                QString amount = QString::number(m_voucher->priceVatHigh().toDouble(), 'f', 2);
                int numSpaces = shopSettings->lettersPerLine() - (output.length() + amount.length());
                for (int i = 0; i < numSpaces; i++)
                {
                    out.append(" ");
                }
                out.append(prepareString(amount));
                out.append("\x0a");

                output = dph + QString::number(m_voucher->vatRateHigh().toDouble()) + "%";
                out.append(prepareString(output));
                amount = QString::number(m_voucher->vatAmountHigh().toDouble(), 'f', 2);
                numSpaces = shopSettings->lettersPerLine() - (output.length() + amount.length());
                for (int i = 0; i < numSpaces; i++)
                {
                    out.append(" ");
                }
                out.append(prepareString(amount));
                out.append("\x0a");
            }

            if (m_voucher->vatAmountFirstLower() > zero)
            {
                output = zaklad + QString::number(m_voucher->vatRateFirstLower().toDouble()) + "%";
                out.append(prepareString(output));
                QString amount = QString::number(m_voucher->priceVatFirstLower().toDouble(), 'f', 2);
                int numSpaces = shopSettings->lettersPerLine() - (output.length() + amount.length());
                for (int i = 0; i < numSpaces; i++)
                {
                    out.append(" ");
                }
                out.append(prepareString(amount));
                out.append("\x0a");

                output = dph + QString::number(m_voucher->vatRateFirstLower().toDouble()) + "%";
                out.append(prepareString(output));
                amount = QString::number(m_voucher->vatAmountFirstLower().toDouble(), 'f', 2);
                numSpaces = shopSettings->lettersPerLine() - (output.length() + amount.length());
                for (int i = 0; i < numSpaces; i++)
                {
                    out.append(" ");
                }
                out.append(prepareString(amount));
                out.append("\x0a");
            }

            if (m_voucher->VatAmountSecondLower() > zero)
            {
                output = zaklad + QString::number(m_voucher->vatRateSecondLower().toDouble()) + "%";
                out.append(prepareString(output));
                QString amount = QString::number(m_voucher->priceVatSecondLower().toDouble(), 'f', 2);
                int numSpaces = shopSettings->lettersPerLine() - (output.length() + amount.length());
                for (int i = 0; i < numSpaces; i++)
                {
                    out.append(" ");
                }
                out.append(prepareString(amount));
                out.append("\x0a");

                output = dph + QString::number(m_voucher->vatRateSecondLower().toDouble()) + "%";
                out.append(prepareString(output));
                amount = QString::number(m_voucher->VatAmountSecondLower().toDouble(), 'f', 2);
                numSpaces = shopSettings->lettersPerLine() - (output.length() + amount.length());
                for (int i = 0; i < numSpaces; i++)
                {
                    out.append(" ");
                }
                out.append(prepareString(amount));
                out.append("\x0a");
            }

            out.append("\x1b\x21");
            out.append(printMode);
            for (int i = 0; i < shopSettings->lettersPerLine(); i++ )
            {
                out.append("-");
            }
            out.append("\x1b\x21");
            out.append((char)0);
            out.append("\x0a");

        }

        out.append("\x1b\x21");
        out.append(printMode);
        out.append("Celkem:");

        QString totalPrice = QString::number(m_voucher->totalPrice().toDouble(), 'f', 2);
        int numSpaces = shopSettings->lettersPerLine() - (8 + totalPrice.length());
        for (int i = 0; i < numSpaces; i++)
        {
            out.append(" ");
        }

        out.append(prepareString(totalPrice));
        out.append("\x1b\x21");
        out.append((char)0);
        out.append("\x0a");
        out.append("Datum:");
        out.append(prepareString(m_voucher->payDateTime().toString()));
        out.append("\x0a");
        if (!m_voucher->eetBkp().isEmpty())
        {
            out.append("Rezim EET: bezny");
            out.append("\x0a");
            out.append("BKP:");
            out.append("\x0a");
            out.append(prepareString(m_voucher->eetBkp()));
            out.append("\x0a");
            out.append("FIK:");
            out.append("\x0a");
            out.append(prepareString(m_voucher->eetFik()));
            out.append("\x0a");
            out.append("\x0a");
        }
        out.append("\x0a");
        out.append("\x0a");
        out.append("\x0a");

        if (shopSettings->doublePrint() && hasDoubleItem && first)
        {
            out.append("\x0a");
            out.append("\x0a");
            first = false;
        }
        else if (!first)
        {
            first = true;
        }
    } while (shopSettings->doublePrint() && hasDoubleItem && !first);

    return out;
}

QByteArray ReceiptGenerator::prepareString(const QString &str)
{
    QString strOut = str;

     //ToDo - dát do nastavení

    for (int i = 0; i < DIACRITIC.length(); i++)
    {
        strOut = strOut.replace(DIACRITIC.at(i), NON_DIACRITIC.at(i));
    }

    QTextCodec *codec = QTextCodec::codecForName("IBM850");
    return codec->fromUnicode(strOut);
}
