#include "editor.h"
#include <Model/ink.h>
#include <Model/menu.h>
#include <Model/information.h>
#include <Common/constants.h>
#include <QAbstractItemModel>
#include <QFileInfo>
#include <QQuickItem>
#include <math.h>
#include <QColor>
#include <QVariant>
#include <QQmlEngine>


QStringList *Editor::errorList;

int Editor::type;

Interfaz* Editor::edit(QObject *myObject)
{        
    QQuickItem *item = qobject_cast<QQuickItem*>(myObject);

    Interfaz *interfaz = new Interfaz();
    interfaz->setWidth(((int)item->width()));
    interfaz->setHeigth(((int)item->height()));

    getBackground(interfaz, item);
    if(errorList->isEmpty())
    {

        QQuickItem *grid = qobject_cast<QQuickItem*>(item->children().last());
        if(grid)
        {
            int cellWidth = grid->property("cellWidth").toInt();
            int cellHeight = grid->property("cellHeight").toInt();
            int cols = round(grid->width() / cellWidth);
            int rows = round(grid->height() / cellHeight);

            interfaz->setNumberOfCols(cols);
            interfaz->setNumberOfRows(rows);
            interfaz->setNumberOfElements(cols*rows);

            type = getType(myObject);

            switch (type) {
            case 1:
                menu(interfaz, item);
                break;
            case 2:
                information(interfaz, item);
                break;
            case 3:
                ink(interfaz, item);
                break;
            default:
                errorList->append(QObject::tr("No se ha podido determinar el tipo de la interfaz a editar \n"));
                break;
            }
        }
    }

    return (errorList->isEmpty()) ? interfaz : nullptr;
}

int Editor::getType(QObject *myObject)
{
    QQuickItem *grid = qobject_cast<QQuickItem*>(myObject->children().last());

    QString interfaceType = grid->property("objectName").toString();

    if(interfaceType == "menuScreen")
        return 1;
    else if(interfaceType == "informationScreen")
        return 2;
    else if(interfaceType == "inkScreen")
        return 3;
    else
        return -1;

}

Interfaz *Editor::edit(QString file)
{
    QQmlEngine *engine = new QQmlEngine;
    QQmlComponent component(engine, QUrl::fromLocalFile(file));
    errorList = new QStringList();
    Interfaz* model = nullptr;

    if(component.status() != component.Ready)
    {
        QList<QQmlError> errors = component.errors();
        for(int i = 0; i < component.errors().size(); i++)
        {
            errorList->append(errors.at(i).toString());
        }
    }
    else
    {
        QObject *myObject = component.create();
        if(myObject == 0)
        {
            QList<QQmlError> errors = component.errors();
            for(int i = 0; i < component.errors().size(); i++)
            {
                errorList->append(errors.at(i).toString());
            }
        }
        else
        {
            model = edit(myObject);
        }
    }

    return model;

}

int Editor::getType()
{
    return Editor::type;
}

QStringList* Editor::getErrorList()
{
    return errorList;
}

void Editor::getBackground(Interfaz *interfaz, QQuickItem *item)
{    
    QVariant color = (item->property("color"));
    QColor normalColor =  color.value<QColor>();
    if(normalColor.name() != (QString("#ffffff")) && item->children().size() < 3)
    {
        interfaz->setHasImageBackground(false);
        interfaz->setColorBackground(normalColor.name());
    }
    else
    {
        interfaz->setHasImageBackground(true);
        QQuickItem *image = qobject_cast<QQuickItem*>(item->children().at(0));
        if(image)
        {
            QVariant source = image->property("source");
            QString path = source.toString().replace("file:///", "");
            if(fileExist(path))
            {
                interfaz->setImageBackground(source.toString());
            }
            else
            {
                errorList->append(QString(QObject::tr("La imagen %1 de fondo de la interfaz no existe en el sistema \n")).arg(path));
            }
        }
        else
        {
            errorList->append(QObject::tr("La interfaz no dispone de un fondo válido \n"));
        }
    }
}

void Editor::ink(Interfaz *interfaz, QQuickItem *ink)
{
    int childNumber = 0;
    if(interfaz->getHasImageBackground())
    {
        childNumber = 1;
    }
    QAbstractItemModel  *list = qobject_cast<QAbstractItemModel *>(ink->children().at(childNumber));

    ((Ink*) interfaz)->createInkColors(list->rowCount());

    QModelIndex idx;
    QMap<int, QVariant> listElement;
    QMap<int, QVariant>::iterator it;

    for(int i = 0; i < list->rowCount(); i++)
    {
        idx = list->index(i, 0);
        listElement = list->itemData(idx);

        for(it = listElement.begin(); it != listElement.end(); it++)
        {
            QColor color = QColor(it.value().toString());
            if(color.isValid())
            {
                ((Ink*) interfaz)->addColor(i, color);
            }
            else
            {
                if(it.value().typeName() == "double")
                {
                    errorList->append(QString(QObject::tr("Las propiedades del nivel de tinta %1 no son correctas. El color debe ser un valor hexadecimal correcto y el porcentaje un número decimal positivo \n")).arg(i));
                }
            }
        }
    }
}


void Editor::menu(Interfaz *interfaz, QQuickItem *menu)
{
    bool automaticPosition = true;
    bool hasTitle = false;

    int childNumber = 0;
    if(interfaz->getHasImageBackground())
    {
        childNumber = 1;
    }

    QAbstractItemModel  *list = qobject_cast<QAbstractItemModel *>(menu->children().at(childNumber));

    interfaz->setNumberOfElements(list->rowCount());
    ((Menu*)interfaz)->createIcons();

    for(int i = 0; i < list->rowCount(); i++)
    {

        QModelIndex idx = list->index(i, 0);
        QMap<int, QVariant> listElement = list->itemData(idx);
        QMap<int, QVariant>::iterator it;

        QHash<int, QByteArray> roles = list->roleNames();

        for(it = listElement.begin(); it != listElement.end(); it++)
        {
            QString rol = QString(roles.value(it.key()));
            if (it.value().type() == QMetaType::Double)
            {
                automaticPosition = false;
                QString rol = QString(roles.value(it.key()));
                if(rol == Constants::Parser::MenuView::marginTop)
                {
                    ((Menu*)interfaz)->setIconTopMargin(i, it.value().toInt());
                }
                else if(rol == Constants::Parser::MenuView::marginBottom)
                {
                    ((Menu*)interfaz)->setIconBottomMargin(i, it.value().toInt());
                }
                else if(rol == Constants::Parser::MenuView::marginLeft)
                {
                    ((Menu*)interfaz)->setIconLeftMargin(i, it.value().toInt());
                }
                else if(rol == Constants::Parser::MenuView::marginRight)
                {
                    ((Menu*)interfaz)->setIconRightMargin(i, it.value().toInt());
                }else
                {
                    errorList->append(QString(QObject::tr("El icono %1 posee el atributo %2 no reconocido por el sistema \n")).arg(i).arg(rol));
                }
            }
            else
            {
                if(rol == Constants::Parser::MenuView::image)
                {
                    QString path = (*it).toString().replace("file:///", "");
                    if(fileExist(path))
                    {
                        ((Menu*)interfaz)->setIconPath(i, (*it).toString());
                    }
                    else
                    {
                        errorList->append(QString(QObject::tr("La imagen %2 del icono %1 no existe en el sistema \n")).arg(i).arg(path));
                    }

                }
                else
                {
                    if(rol == Constants::Parser::MenuView::name)
                    {
                        QString title = (*it).toString();
                        if(!title.isEmpty())
                        {
                            hasTitle = true;
                        }
                        ((Menu*)interfaz)->setIconTitle(i, title);
                    }
                    else
                    {
                        errorList->append(QString(QObject::tr("El atributo %2 del icono %1 no es reconocido por el sistema \n")).arg(i).arg(rol));
                    }
                }
            }
        }
    }

    ((Menu*)interfaz)->setAutomaticPosition(automaticPosition);
    ((Menu*)interfaz)->setHasTitle(hasTitle);
}

void Editor::information(Interfaz *interfaz, QQuickItem *information)
{
    int childNumber = 0;
    if(interfaz->getHasImageBackground())
    {
        childNumber = 1;
    }

    QAbstractItemModel  *list = qobject_cast<QAbstractItemModel *>(information->children().at(childNumber));

    interfaz->setNumberOfElements(list->rowCount());
    ((Information*) interfaz)->createCards();

    for(int i = 0; i < list->rowCount(); i++)
    {
        QMap<int, QVariant> *properties = new QMap<int, QVariant>();
        QMap<int, QVariant> *values = new QMap<int, QVariant>();

        QModelIndex idx = list->index(i, 0);
        QMap<int, QVariant> listElement = list->itemData(idx);
        QMap<int, QVariant>::iterator it;

        QHash<int, QByteArray> roles = list->roleNames();

        for(it = listElement.begin(); it != listElement.end(); it++)
        {
            QString rol = QString(roles.value(it.key()));
            QString value = it.value().toString();
            if(rol == Constants::Parser::InformationView::iconOption)
            {
                QString path = value.replace("file:///", "");
                ((Information*)interfaz)->setHasIcons(!path.isEmpty());
                if(!path.isEmpty())
                {
                    if(fileExist(path))
                    {
                        ((Information*)interfaz)->setCardImage(i, path);
                    }
                    else
                    {
                        errorList->append(QString(QObject::tr(("La imagen %2 del icono %1 no existe en el sistema \n")).arg(i).arg(path)));
                    }
                }

            }
            else if(rol == Constants::Parser::InformationView::titleOption)
            {
                ((Information*)interfaz)->setCardTitle(i,value);
            }
            else if(rol == Constants::Parser::InformationView::id)
            {

            }else if(rol == Constants::Parser::InformationView::colElementRol)
            {
                if(value.size() == 1 && value.at(value.size() - 1).isDigit())
                {
                    ((Information*)interfaz)->setCardCols(value.toInt());
                }
                else
                {
                    errorList->append(QString(QObject::tr("El atributo %2  del icono %1 no es reconocido por el sistema \n")).arg(i).arg(rol));
                }
            }else if(rol == Constants::Parser::InformationView::rowElementRol)
            {
                if(value.size() == 1 && value.at(value.size() - 1).isDigit())
                {
                    ((Information*)interfaz)->setCardRows(value.toInt());
                }
                else
                {
                    errorList->append(QString(QObject::tr(("El atributo %2  del icono %1 no es reconocido por el sistema \n")).arg(i).arg(rol)));
                }
            }
            else
            {
                if(rol.at(rol.size() - 1).isDigit())
                {
                    int numProperty = (rol.at(rol.size() -1)).digitValue();
                    if(rol.contains(QString("property")))
                    {
                        properties->insert(numProperty,value);
                    }
                    else
                    {
                        if(rol.contains(QString("value")))
                        {
                            values->insert(numProperty, value);
                        }
                        else
                        {
                            errorList->append(QString(QObject::tr("El atributo %2  del icono %1 no es reconocido por el sistema \n")).arg(i).arg(rol));
                        }
                    }
                }
                else
                {
                    errorList->append(QString(QObject::tr("El atributo %2  del icono %1 no es reconocido por el sistema \n")).arg(i).arg(rol));
                }
            }
        }
        QMap<int, QVariant>::iterator valueIt;
        QMap<int, QVariant>::iterator propertyIt;

        for(int j = 0; j < properties->size(); j++)
        {
            if(j < values->size())
            {
                propertyIt = properties->find(j);
                valueIt = values->find(j);
                if(propertyIt != properties->end())
                {
                    if(valueIt != values->end())
                    {
                        QString value = valueIt.value().toString();
                        QString property = propertyIt.value().toString();
                        if(!value.isEmpty() && !property.isEmpty())
                        {
                            ((Information*)interfaz)->addProperty(i, property, value);
                        }
                    }
                    else
                    {
                        errorList->append(QObject::tr("La tarjeta %1 tiene un valor incorrecto en la propiedad %2.[Atributo value]. \n").arg(i).arg(j));
                    }
                }
                else
                {
                    errorList->append(QObject::tr("La tarjeta %1 tiene un valor incorrecto en la propiedad %2.[Atributo property]. \n").arg(i).arg(j));
                }
            }
            else
            {
                errorList->append(QObject::tr("Es obligatorio que todas las propiedades tengan un valor un valor. \n"));
            }
        }
    }
}

bool Editor::fileExist(const QString path)
{
    QFileInfo file = QFileInfo(path);
    return file.exists() && file.isFile();
}
