#include <QString>
#include "docsupdater.h"
#include "tools.h"


DocsUpdater::DocsUpdater(UpdateController* updateController, QObject *parent):
    QObject(parent),
    updateController(updateController),
    flagStop(false)
{

}

DocsUpdater::~DocsUpdater()
{

}

//PUBLIC
void DocsUpdater::lockAccessToDocsXML()
{
    mtxAccess.lock();
}

void DocsUpdater::unLockAccessToDocsXML()
{
    mtxAccess.unlock();
}

QList<SubProc> DocsUpdater::getListSubProcForDMcode(QString dmCode)
{
    QMutexLocker locker(&mtxAccess);

    if(!listSubProcMap.contains(dmCode))
        return QList<SubProc>();

    return listSubProcMap.value(dmCode);
}

bool DocsUpdater::updateDocsXML()
{
    QMutexLocker locker(&mtxAccess);

    QString nameDocsFile = tasksAMMfileName; //кручу верчу запутать хочу!
    QString pathDocsFile = updateController->getPathAdditionalFile(nameDocsFile);

    QDomDocument docTasksDOM;
    if(! Tools::loadXMLtoDOM(pathDocsFile, &docTasksDOM))
        return false;

    QDomElement manifestElement = docTasksDOM.firstChildElement("manifest");
    if(manifestElement.isNull())
        return false;

    deleteAllModulsAMM();
    listTasksAMM.clear();

    listSubProcMap.clear();
    DMmodulesMap.clear();

    domElementParserAMM(manifestElement, nullptr);

    if(! Tools::saveDOMtoXML(pathDocsFile, &docTasksDOM))
    {
        deleteAllModulsAMM();
        listTasksAMM.clear();

        listSubProcMap.clear();
        DMmodulesMap.clear();

        return false;
    }

    //Проставляем canplay
    for (auto it = listSubProcMap.begin(); it != listSubProcMap.end(); ++it)
    {
        QList<SubProc> listSP = it.value();
        QString keyToReplace = it.key();

        if(listSP.count())
        {
            for(int i = 0; i < listSP.count(); i++)
            {
                QString dmCode = listSP.at(i).getDmCode();
                DM* module = getDMmoduleByDMcode(dmCode);
                if(module)
                {
                    SubProc sp = listSP.at(i);
                    sp.setModeList(module->getModeList());
                    listSP.replace(i, sp);
                }
            }

            if (!keyToReplace.isEmpty())
            {
                listSubProcMap[keyToReplace] = listSP;
            }
        }
    }

    return true;
}


//PRIVATE
void DocsUpdater::domElementParserAMM(QDomElement element, Module* moduleParent)
{
    QString name;

    if(flagStop)
        return;

    QDomElement childElement = element.firstChildElement();
    if(childElement.isNull())
        return;

    Module* module = nullptr;

    do
    {
       name = childElement.nodeName();

       QDomNamedNodeMap nodeMap = childElement.attributes();

       if(name == "doc")
       {
           module = new PM();
       }
       else if(name == "pm")
       {
           module = new PM();
           PM* PMmodul = static_cast<PM*>(module);

           PMmodul->initialize(nodeMap.namedItem("modelIdentCode").nodeValue(),
                               nodeMap.namedItem("pmIssuer").nodeValue(),
                               nodeMap.namedItem("pmNumber").nodeValue(),
                               nodeMap.namedItem("pmVolume").nodeValue());

           if(moduleParent)
           {
               PMmodul->setParentModule(moduleParent);

               PM* PMmodulParent = static_cast<PM*>(moduleParent);
               PMmodulParent->addChildModule(module);
           }
       }
       else if(name == "dm")
       {
           module = new DM();
           DM* DMmodul = static_cast<DM*>(module);

           DMmodul->initialize(nodeMap.namedItem("modelIdentCode").nodeValue(),
                               nodeMap.namedItem("systemDiffCode").nodeValue(),
                               nodeMap.namedItem("systemCode").nodeValue(),
                               nodeMap.namedItem("subSystemCode").nodeValue(),
                               nodeMap.namedItem("subSubSystemCode").nodeValue(),
                               nodeMap.namedItem("assyCode").nodeValue(),
                               nodeMap.namedItem("disassyCode").nodeValue(),
                               nodeMap.namedItem("disassyCodeVariant").nodeValue(),
                               nodeMap.namedItem("infoCode").nodeValue(),
                               nodeMap.namedItem("infoCodeVariant").nodeValue(),
                               nodeMap.namedItem("itemLocationCode").nodeValue());

           if(moduleParent)
           {
               DMmodul->setParentModule(moduleParent);

               PM* PMmodulParent = static_cast<PM*>(moduleParent);
               PMmodulParent->addChildModule(module);
           }

           DMmodulesMap.insert(DMmodul->dmCode(), DMmodul);
       }
       else if(name == "rus" || name == "eng")
       {
           if(moduleParent)
           {
               if(moduleParent->getType() == ModuleType::TYPE_PM)
               {//PM
                   PM* PMmodulParent = static_cast<PM*>(moduleParent);

                   if(name == "rus")
                        PMmodulParent->setLangStructRus(nodeMap.namedItem("title").nodeValue());
                   else
                        PMmodulParent->setLangStructEng(nodeMap.namedItem("title").nodeValue());
               }
               else
               {//DM
                   DM* DMmodulParent = static_cast<DM*>(moduleParent);

                   if(name == "rus")
                   {
                        DMmodulParent->setLangStructRus(nodeMap.namedItem("techName").nodeValue(),
                                                        nodeMap.namedItem("infoName").nodeValue(),
                                                        nodeMap.namedItem("pdf").nodeValue(),
                                                        nodeMap.namedItem("bookmark").nodeValue(),
                                                        nodeMap.namedItem("xml").nodeValue());

                        QString dmCode = DMmodulParent->dmCode();
                        QString canplay = "";
                        QList<SubProc> listSubProc;
                        if(processingScenXML(dmCode, canplay, listSubProc))
                        {
                            DMmodulParent->setModeList(SubProc::parseCanplay(canplay));
                            nodeMap.namedItem("canplay").setNodeValue(canplay);

                            listSubProcMap.insert(dmCode, listSubProc);
                        }
                        else
                        {
                            DMmodulParent->setModeList(SubProc::parseCanplay(canplay));
                            nodeMap.namedItem("canplay").setNodeValue(canplay);
                        }
                   }
                   else
                       DMmodulParent->setLangStructEng(nodeMap.namedItem("techName").nodeValue(),
                                                       nodeMap.namedItem("infoName").nodeValue(),
                                                       nodeMap.namedItem("pdf").nodeValue(),
                                                       nodeMap.namedItem("bookmark").nodeValue(),
                                                       nodeMap.namedItem("xml").nodeValue());
               }
           }

       }

        domElementParserAMM(childElement, module);

        if(moduleParent == nullptr)
            listAllModulesAMM.append(module);

        if(module)
            if(module->getType() == ModuleType::TYPE_DM)
            {
                TaskAmmFim* task = nullptr;
                task = new TaskAmmFim();
                task->setID(module->getID());
                task->ammProcedure.title = static_cast<DM*>(module)->getLangStructRus().techName;
                task->ammProcedure.dmCode = static_cast<DM*>(module)->dmCode();

                listTasksAMM.append(*task);
                delete task;
            }

    }while (! (childElement = childElement.nextSiblingElement()).isNull());
}

void DocsUpdater::deleteAllModulsAMM()
{
    for(Module* module: listAllModulesAMM)
    {
        if(module->getType() == ModuleType::TYPE_PM)
            delete static_cast<PM*>(module);
        else
            delete static_cast<DM*>(module);
    }
    listAllModulesAMM.clear();
}

bool DocsUpdater::processingScenXML(const QString dmCode, QString &canplay, QList<SubProc> &listSubProc)
{
    listSubProc.clear();

    ModeList modeList;
    canplay = "";
    QString signDemo = "-";
    QString signTrain = "-";
    QString signExam = "-";
    QString signAuto = "-";

    QString nameScenXMLFile = "/" + dmCode + ".xml";
    QString pathScenXMLFile = updateController->getPathScensFile(nameScenXMLFile);


    QDomDocument docScenDOM;
    if(! Tools::loadXMLtoDOM(pathScenXMLFile, &docScenDOM))
        return false;

    QDomElement scenarioElement = docScenDOM.firstChildElement("scenario");
    if(scenarioElement.isNull())
        return false;


    QDomElement demoElement = scenarioElement.firstChildElement("demo");
    if(!demoElement.isNull())
    {
        //canplay
        if(demoElement.toElement().attribute("canplay") == "True")
        {
            signDemo = "+";
            modeList.demo = true;
        }

        //subProc
        selectSubProc(demoElement, listSubProc);
    }

    QDomElement trainElement = scenarioElement.firstChildElement("train");
    if(!trainElement.isNull())
    {
        //canplay
        if(trainElement.toElement().attribute("canplay") == "True")
        {
            signTrain = "+";
            modeList.train = true;
        }

        //subProc
        selectSubProc(trainElement, listSubProc);
    }

    QDomElement examElement = scenarioElement.firstChildElement("exam");
    if(!examElement.isNull())
    {
        //canplay
        if(examElement.toElement().attribute("canplay") == "True")
        {
            signExam = "+";
            modeList.exam = true;
        }

        //subProc
        selectSubProc(examElement, listSubProc);
    }

    QDomElement autoElement = scenarioElement.firstChildElement("auto");
    if(!autoElement.isNull())
    {
        //canplay
        if(autoElement.toElement().attribute("canplay") == "True")
        {
            signAuto = "+";
            modeList.autoM = true;
        }

        //subProc
        //Из этого режима не берем!
    }

    canplay = QString("%1/%2/%3/%4").arg(signDemo, signTrain, signExam, signAuto);

    return true;
}

void DocsUpdater::selectSubProc(QDomElement &modeElement, QList<SubProc> &listSubProc)
{
    QDomNodeList nodeList = modeElement.elementsByTagName("node");
    for(int i = 0; i < nodeList.count(); i++)
    {
        QDomNode node = nodeList.at(i);
        if(node.toElement().attribute("type") == "Subproc")
        {
            QDomElement subProcElement = node.firstChildElement("subproc");
            if(!subProcElement.isNull())
            {
                SubProc subProc;
                subProc.setDmCode(subProcElement.toElement().attribute("dmCode"));
                subProc.setTitle(subProcElement.toElement().attribute("title"));

                if(! listSubProc.contains(subProc))
                    listSubProc.append(subProc);
            }
        }
    }
}

DM *DocsUpdater::getDMmoduleByDMcode(QString dmCode)
{
    if(!DMmodulesMap.contains(dmCode))
        return nullptr;

    return DMmodulesMap.value(dmCode);
}
