#include "EditorPage.h"
#include "tab_docs.h"
#include "dialog.h"
#include <QMainWindow>
#include <QDockWidget>
#include <QtXml>

Editor_class::Editor_class(QWidget *parent)
    : QMainWindow(parent)
{
    f_tabWid = new QTabWidget(this);
    f_tabWid->setIconSize(QSize(12,12));
    setCentralWidget(f_tabWid);
    f_tabWid->setTabsClosable(true);
    connect(f_tabWid, SIGNAL(tabCloseRequested(int)), this, SLOT(sltCloseIdx(int)));

    f_newTabsCount = 0;
    f_amountOfChanged = 0;
    
    //!!! Строки, которые показываются в интерфейса, нужно помещать в tr("...") для поддержки перевода
    
    QAction* actSave = new QAction(QIcon(":pictures/Save.png"), "Сохранить", this);
    actSave->setShortcut(QKeySequence("CTRL+S"));
    QAction* actSaveAll = new QAction(QIcon(":pictures/SaveAll.png"), "Сохранить все", this);
    actSaveAll->setShortcut(QKeySequence("CTRL+SHIFT+S"));
    QAction* actClose = new QAction(QIcon(":pictures/Close.png"), "Закрыть", this);
    actClose->setShortcut(QKeySequence("CTRL+D"));
    QAction* actNew = new QAction(QIcon(":pictures/New.png"), "Новый...", this);
    actNew->setShortcut(QKeySequence("CTRL+N"));
    QAction* actOpen = new QAction(QIcon(":pictures/Open.png"), "Открыть...", this);
    actOpen->setShortcut(QKeySequence("CTRL+O"));

    QMenu* fileMenu = new QMenu(tr("Файл"), this);
    QMenu* editMenu = new QMenu(tr("Редактировать"), this);
    QMenu* viewMenu = new QMenu(tr("Вид"), this);

    connect(actNew, &QAction::triggered, this, &Editor_class::sltNewDocument);
    connect(actOpen, &QAction::triggered, this, &Editor_class::sltOpen);
    connect(actSave, &QAction::triggered, this, &Editor_class::sltSave);
    connect(actSaveAll, &QAction::triggered, this, &Editor_class::sltSaveAll);
    connect(actClose, SIGNAL(triggered()), this, SLOT(sltClose()));
    fileMenu->addAction(actNew);
    fileMenu->addAction(actOpen);
    fileMenu->addSeparator();
    fileMenu->addAction(actSave);
    fileMenu->addAction(actSaveAll);
    fileMenu->addAction(actClose);
    fileMenu->addAction(QIcon(":pictures/SaveAs.png") ,tr("Сохранить как..."), this, &Editor_class::sltSaveAs);
    fileMenu->addAction(QIcon(":pictures/CloseAll.png") ,tr("Закрыть все"), this, &Editor_class::sltCloseAll, QKeySequence("CTRL+SHIFT+D"));

    fileMenu->addSeparator();

    fileMenu->addAction(QIcon(":pictures/Exit.png"), tr("Выход"), this, &Editor_class::sltOnClose, QKeySequence("CTRL+Q"));

    viewMenu->addAction(tr("Мой компьютер"), this, &Editor_class::sltFileBrowser, QKeySequence("CTRL+SHIFT+B"));
    viewMenu->addSeparator();
    viewMenu->addAction(tr("Вкладки"), this, &Editor_class::sltTabs, QKeySequence("CTRL+SHIFT+T"));
    menuBar()->addMenu(fileMenu);
    menuBar()->addMenu(editMenu);
    menuBar()->addMenu(viewMenu);
    editMenu->addAction("Копировать", this, &Editor_class::sltCopy);
    editMenu->addAction("Вставить", this, &Editor_class::sltPaste);
    editMenu->addSeparator();

    editMenu->addAction("Выбрать все", this, &Editor_class::sltSelectAll);
    editMenu->addAction("Вырезать", this, &Editor_class::sltCut);
    editMenu->addSeparator();
    editMenu->addAction("Удалить", this, &Editor_class::sltDelete);
    QToolBar* toolBarFile = new QToolBar(this);
    toolBarFile->addAction(actNew);
    toolBarFile->addAction(actOpen);
    toolBarFile->addAction(actSave);
    toolBarFile->addAction(actSaveAll);
    toolBarFile->addAction(actClose);
    toolBarFile->setIconSize(QSize(35, 35));
    addToolBar(Qt::TopToolBarArea, toolBarFile);
    resize(800, 600);
    f_dockTabsWid = new QDockWidget("Открытые файлы", this);

    f_dockTabsWid->hide();
    f_tableTabsView = new QListView(f_dockTabsWid);
    f_tableTabsView->setEditTriggers(QTableView::NoEditTriggers);
    f_tableTabsView->setSelectionMode(QAbstractItemView::SingleSelection);
    f_strListModel = new QStringListModel(f_tableTabsView);
    this->addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, f_dockTabsWid);

    connect(f_tableTabsView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(sltSetActiveTab(const QModelIndex&)));
    f_dockFileSysWid = new QDockWidget("Локальный Диск", this);
    f_dockFileSysWid->hide();

    f_treeFileSysView = new QTreeView(f_dockFileSysWid);
    f_sysModel = new QFileSystemModel(f_treeFileSysView);
    f_sysModel->setRootPath(QDir::rootPath());
    this->addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, f_dockFileSysWid);

    connect(f_treeFileSysView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(sltOpenIdx(const QModelIndex&)));
    getExtensionsFromIni();
}

Editor_class::~Editor_class()
{}

void Editor_class::closeEvent(QCloseEvent *event)
{
    if(sltCloseAll())
        event->accept();
    else
        event->ignore();
}

tabDoc* Editor_class::createNewDocument()
{
    tabDoc* newTab = new tabDoc();
    f_newTabName = QString("New File(%1)").arg(++f_newTabsCount);
    newTab->setFileName(f_newTabName);
    connect(newTab, SIGNAL(changeWidTitle(const QString&, const QString&)), this, SLOT(sltChangeTabTitle(const QString&, const QString&)));
    connect(newTab, SIGNAL(fileChanded(const QString&)), this, SLOT(sltFileChanged(const QString&)));
    newTab->linesHelp();
    return newTab;
}

void Editor_class::sltNewDocument()
{
    tabDoc* newTab = createNewDocument();
    f_tabWid->addTab(newTab, f_newTabName);
    f_tabWid->setCurrentWidget(newTab);
    qDebug() << "Added" << f_newTabName << "to f_openedTabsNames :";
    f_openedTabsNames << f_newTabName;
    qDebug() << f_openedTabsNames;
    f_openedTabsDirectories << newTab->getFileDirectory();
    f_strListModel->setStringList(f_openedTabsNames);

    emit  statusBar()->showMessage(tr("Made a new document named ") + f_newTabName + ".");
}

void Editor_class::getExtensionsFromIni()
{
    QDomDocument domDoc;
    QFile hLIni(":/hLIni/highlightTest.xml");

    if (hLIni.open(QIODevice::ReadOnly))
    {
        if (domDoc.setContent(&hLIni))
        {
            auto domNodeExtList = domDoc.elementsByTagName("syntax");
            qDebug() << domNodeExtList.count();
            for (int at = 0; at < domNodeExtList.count(); at++)
            {
                auto attrMap = domNodeExtList.item(at).attributes();

                for(int atAttribute = 0; atAttribute < attrMap.length(); atAttribute++)
                {
                    if(attrMap.item(atAttribute).toAttr().name() == "ext_list")
                    {
                        QString singleLangExt = attrMap.item(atAttribute).toAttr().value();
                        qDebug() << singleLangExt;
                        auto singleLangExtList = singleLangExt.split(" ");
                        f_codeExtensions << singleLangExtList;
                        qDebug() << f_codeExtensions;
                    }
                }
            }
        }
    }
    hLIni.close();
    emit  statusBar()->showMessage(tr("Загружена расцветка из highlightTest.xml."));
}

void Editor_class::sltChangeTabTitle(const QString& p_lastName, const QString& p_lastDirectory)
{
    tabDoc* senderPtr = qobject_cast<tabDoc*>(sender());
    if(!senderPtr)
        return;

    if(p_lastName.isEmpty())
        f_tabWid->setTabText(f_tabWid->indexOf(senderPtr), senderPtr->getFileName());
    else
    {
        f_openedTabsNames.replace(f_openedTabsNames.indexOf(p_lastName), senderPtr->getFileName());
        f_openedTabsDirectories.replace(f_openedTabsDirectories.indexOf(p_lastDirectory), senderPtr->getFileDirectory());
        f_tabWid->setTabText(f_tabWid->indexOf(senderPtr), senderPtr->getFileName());
    }
}


void Editor_class::sltSaveAll()
{
    for(int i = 0; i < f_tabWid->count(); i++)
    {
        tabDoc* currentTab = qobject_cast<tabDoc*>(f_tabWid->widget(i));
        f_tabWid->setTabIcon(f_tabWid->indexOf(currentTab), QIcon());
        if (currentTab)
        {
            if(currentTab->wasChanged())
                currentTab->sltSave();
        }
    }
    f_amountOfChanged = 0;
    emit  statusBar()->showMessage(tr("Saved all documents."));

}

void Editor_class::sltClose()
{
    int currentIdx = f_tabWid->currentIndex();
    QString fileName = f_tabWid->tabText(currentIdx);
    tabDoc* currentTab = qobject_cast<tabDoc*>(f_tabWid->currentWidget());

    if(!currentTab)
        return;

    if(!currentTab->wasChanged())
    {
         f_tabWid->removeTab(currentIdx);
         f_openedTabsNames.removeAll(fileName);
         f_openedTabsDirectories.removeAll(currentTab->getFileDirectory());
         f_strListModel->setStringList(f_openedTabsNames);
         qDebug() << f_openedTabsDirectories << f_openedTabsNames;
         emit  statusBar()->showMessage(tr("Closed the document with name ") + currentTab->getFileName() + ".");
         delete currentTab;
         return;
    }

    QMessageBox* saveMsg = new QMessageBox(this);
    saveMsg->setText("Save changes?");
    saveMsg->setInformativeText("Do you want to save changes to file " + currentTab->getFileName() + "?");
    saveMsg->setStandardButtons(QMessageBox::Save | QMessageBox::StandardButton::No | QMessageBox::Cancel);
    saveMsg->setDefaultButton(QMessageBox::Save);
    int option = saveMsg->exec();
    switch (option) {
      case QMessageBox::Save:
          currentTab->sltSave();
          f_amountOfChanged--;
          f_tabWid->removeTab(currentIdx);
          f_openedTabsNames.removeAll(fileName);
          f_openedTabsDirectories.removeAll(currentTab->getFileDirectory());
          f_strListModel->setStringList(f_openedTabsNames);
          emit  statusBar()->showMessage(tr("Closed the document with name ") + currentTab->getFileName() + ".");
          delete currentTab;
          break;

      case QMessageBox::No:
          f_amountOfChanged--;
          f_tabWid->removeTab(currentIdx);
          f_openedTabsNames.removeAll(fileName);
          f_openedTabsDirectories.removeAll(currentTab->getFileDirectory());
          f_strListModel->setStringList(f_openedTabsNames);
          emit  statusBar()->showMessage(tr("Closed the document with name ") + currentTab->getFileName() + ".");
          delete currentTab;
          break;
      case QMessageBox::Cancel:
          break;
      default:
          break;
    }

    qDebug() << f_openedTabsDirectories << f_openedTabsNames;

}

void Editor_class::sltCloseIdx(int p_tab)
{
    int currentIdx = p_tab;
    QString fileName = f_tabWid->tabText(currentIdx);
    tabDoc* currentTab = qobject_cast<tabDoc*>(f_tabWid->widget(currentIdx));

    if(!currentTab->wasChanged())
    {
         f_tabWid->removeTab(currentIdx);
         f_openedTabsNames.removeAll(fileName);
         f_openedTabsDirectories.removeAll(currentTab->getFileDirectory());
         f_strListModel->setStringList(f_openedTabsNames);
         qDebug() << f_openedTabsDirectories << f_openedTabsNames;
         emit  statusBar()->showMessage(tr("Closed the document with name ") + currentTab->getFileName() + ".");
         delete currentTab;
         return;
    }

    QMessageBox* saveMsg = new QMessageBox(this);
    saveMsg->setText("Save changes?");
    saveMsg->setInformativeText("Do you want to save changes to file " + currentTab->getFileName() + "?");
    saveMsg->setStandardButtons(QMessageBox::Save | QMessageBox::StandardButton::No | QMessageBox::Cancel);
    saveMsg->setDefaultButton(QMessageBox::Save);
    int option = saveMsg->exec();
    switch (option) {
      case QMessageBox::Save:
          currentTab->sltSave();
          f_amountOfChanged--;
          f_tabWid->removeTab(currentIdx);
          f_openedTabsNames.removeAll(fileName);
          f_openedTabsDirectories.removeAll(currentTab->getFileDirectory());
          f_strListModel->setStringList(f_openedTabsNames);
          emit  statusBar()->showMessage(tr("Closed the document with name ") + currentTab->getFileName() + ".");
          delete currentTab;
          break;
      case QMessageBox::No:
          f_amountOfChanged--;
          f_tabWid->removeTab(currentIdx);
          f_openedTabsNames.removeAll(fileName);
          f_openedTabsDirectories.removeAll(currentTab->getFileDirectory());
          f_strListModel->setStringList(f_openedTabsNames);
          emit  statusBar()->showMessage(tr("Closed the document with name ") + currentTab->getFileName() + ".");
          delete currentTab;
          break;
      case QMessageBox::Cancel:
          break;
      default:
          break;
    }


    qDebug() << f_openedTabsDirectories << f_openedTabsNames;


}

void Editor_class::sltSetActiveTab(QWidget* p_tab)
{
    f_tabWid->setCurrentWidget(p_tab);
}

void Editor_class::sltOpen()
{
    tabDoc* newTab = createNewDocument();
    QString newTabName = newTab->sltLoad();

    if(newTabName.isEmpty())
        return;

    if(f_openedTabsNames.contains(newTabName))
        return;


    f_tabWid->addTab(newTab, newTabName);
    f_openedTabsNames << newTabName;

    if(f_codeExtensions.contains(newTab->getFileExt()))
        newTab->sltIsCodeDoc();

    qDebug() << newTab->getFileDirectory();
    f_openedTabsDirectories << newTab->getFileDirectory();
    f_strListModel->setStringList(f_openedTabsNames);
    newTab->show();
    f_tabWid->setCurrentWidget(newTab);

    qDebug() << f_openedTabsDirectories << f_openedTabsNames;
    emit  statusBar()->showMessage(tr("Opened the document named ") + newTabName + ".");
}

void Editor_class::sltOpenIdx(const QModelIndex& p_idx)
{
    tabDoc* newTab = createNewDocument();
    QString newTabName = newTab->sltLoad(f_sysModel->filePath(p_idx));

    if(f_openedTabsNames.contains(newTabName))
        return;

    f_tabWid->addTab(newTab, newTabName);
    f_openedTabsNames << newTabName;

    if(f_codeExtensions.contains(newTab->getFileExt()))
        newTab->sltIsCodeDoc();
    qDebug() << newTab->getFileDirectory();
    f_openedTabsDirectories << newTab->getFileDirectory();
    f_strListModel->setStringList(f_openedTabsNames);
    newTab->show();
    f_tabWid->setCurrentWidget(newTab);

    qDebug() << f_openedTabsDirectories << f_openedTabsNames;

    emit  statusBar()->showMessage(tr("Opened the document named ") + newTabName + ".");
}

void Editor_class::sltSave()
{
    tabDoc* currentTab = qobject_cast<tabDoc*>(f_tabWid->currentWidget());
    if(currentTab)
    {
        if(!currentTab->wasChanged())
            return;

        currentTab->sltSave();
        f_amountOfChanged--;
        f_tabWid->setTabIcon(f_tabWid->indexOf(currentTab), QIcon());
        emit  statusBar()->showMessage(tr("Saved the document named ") + currentTab->getFileName() + ".");
    }
}

void Editor_class::sltSaveAs()
{
    tabDoc* currentTab = qobject_cast<tabDoc*>(f_tabWid->currentWidget());
    if(currentTab)
    {
        currentTab->sltSaveAs(currentTab->getFileName());
        f_amountOfChanged--;
        f_tabWid->setTabIcon(f_tabWid->indexOf(currentTab), QIcon());
        emit  statusBar()->showMessage(tr("Saved the document with new name ") + currentTab->getFileName() + ".");
    }

}

void Editor_class::sltSetActiveTab(const QModelIndex& p_idx)
{
    QString name = f_strListModel->data(p_idx).toString();
    f_tabWid->setCurrentIndex(f_openedTabsNames.indexOf(name));
}

bool Editor_class::sltCloseAll()
{
    if(f_tabWid->count() == 0 || f_amountOfChanged == 0)
    {
        f_tabWid->clear();
        f_openedTabsNames.clear();
        f_openedTabsDirectories.clear();
        f_strListModel->setStringList(f_openedTabsNames);
        emit statusBar()->showMessage(tr("Closed all documents."));
        return true;
    }

    SaveDialog* saveDial = new SaveDialog(this);
    saveDial->sltSetSizes(f_amountOfChanged, 2);
    int at_tab = 0;
    int at_item = 0;

    for(auto &&name : f_openedTabsNames)
    {
        if(qobject_cast<tabDoc*>(f_tabWid->widget(at_tab))->wasChanged())
        {
            QTableWidgetItem* itemName = new QTableWidgetItem(name);
            QTableWidgetItem* itemDirectory = new QTableWidgetItem(f_openedTabsDirectories.at(at_tab));

            qDebug() << itemName << itemDirectory;
            saveDial->sltSetContents(at_item, 0, itemName);
            saveDial->sltSetContents(at_item, 1, itemDirectory);

            at_item++;
        }
        at_tab++;
    }

    auto res = saveDial->exec();

    switch(res)
    {
    case SaveDialog::Accepted:
        sltSaveAll();
        f_tabWid->clear();
        f_openedTabsNames.clear();
        f_openedTabsDirectories.clear();
        f_strListModel->setStringList(f_openedTabsNames);
        f_amountOfChanged = 0;
        emit  statusBar()->showMessage(tr("Closed all documents."));
        return true;

        break;

    case SaveDialog::Rejected:
        f_tabWid->clear();
        f_openedTabsNames.clear();
        f_openedTabsDirectories.clear();
        f_strListModel->setStringList(f_openedTabsNames);
        f_amountOfChanged = 0;
        emit  statusBar()->showMessage(tr("Closed all documents."));
        return true;
        break;
    case -88:
        return false;
        break;
    default:
        return true;
        break;
    }

    return true;

}

void Editor_class::sltTabs() const
{
    f_strListModel->setStringList(f_openedTabsNames);
    f_tableTabsView->setModel(f_strListModel);
    f_dockTabsWid->setWidget(f_tableTabsView);
    f_dockTabsWid->show();
}

void Editor_class::sltDelete() const
{
    tabDoc* senderPtr = qobject_cast<tabDoc*>(f_tabWid->currentWidget());
    if(!senderPtr)
        return;

    senderPtr->clear();
}


void Editor_class::sltSelectAll() const
{
    tabDoc* senderPtr = qobject_cast<tabDoc*>(f_tabWid->currentWidget());
    if(!senderPtr)
        return;

    senderPtr->selectAll();
}

void Editor_class::sltFileChanged(const QString& p_tabName)
{
    f_amountOfChanged++;
    f_tabWid->setTabIcon(f_openedTabsNames.indexOf(p_tabName), QIcon(":/pictures/Asterisk.png"));
}

void Editor_class::sltFileBrowser() const
{
    f_treeFileSysView->setModel(f_sysModel);
    f_dockFileSysWid->setWidget(f_treeFileSysView);
    f_dockFileSysWid->show();
}

void Editor_class::sltOnClose()
{
    sltSaveAll();
}

void Editor_class::sltCopy() const
{
    tabDoc* senderPtr = qobject_cast<tabDoc*>(f_tabWid->currentWidget());
    if(!senderPtr)
        return;

    senderPtr->copy();
}

void Editor_class::sltCut() const
{
    tabDoc* senderPtr = qobject_cast<tabDoc*>(f_tabWid->currentWidget());
    if(!senderPtr)
        return;

    senderPtr->cut();
}


void Editor_class::sltPaste() const
{
    tabDoc* senderPtr = qobject_cast<tabDoc*>(f_tabWid->currentWidget());
    if(!senderPtr)
        return;

    senderPtr->paste();
}
