#include <QtWidgets>
#include "Utilities.h"
#include "MdiWindow.h"
#include "ui_ExtensibleObjectModelUI.h"


MdiWindow::MdiWindow(QWidget *parent) :
    QMainWindow(parent), appWindow(nullptr)
{
    //setupServer();
}


QObject* MakeTestObjectTree();
void EnumPropertyEditorTest();
void MdiWindow::init(Ui_MainWindow* ui)
{
    server = 0;
    appWindow = ui;
    mdiArea = ui->mdiArea;//new QMdiArea;
    connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(updateActions()));
    connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(updatePreview()));

    windowMapper = new QSignalMapper(this);
    connect(windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*)));

    QObject::connect(appWindow->actionNew,          SIGNAL(triggered(bool)), this, SLOT(newFile()));
    QObject::connect(appWindow->actionOpen,         SIGNAL(triggered(bool)), this, SLOT(open()));
    QObject::connect(appWindow->actionSave,         SIGNAL(triggered(bool)), this, SLOT(save()));
    QObject::connect(appWindow->actionSave_As,      SIGNAL(triggered(bool)), this, SLOT(saveAs()));
    QObject::connect(appWindow->actionSwitchRTL,    SIGNAL(triggered(bool)), this, SLOT(switchLayoutDirection()));
#ifndef QT_NO_CLIPBOARD
    QObject::connect(appWindow->actionCut,          SIGNAL(triggered(bool)), this, SLOT(cut()));
    QObject::connect(appWindow->actionCopy,         SIGNAL(triggered(bool)), this, SLOT(copy()));
    QObject::connect(appWindow->actionPaste,        SIGNAL(triggered(bool)), this, SLOT(paste()));
#endif
    QObject::connect(appWindow->actionBold,         SIGNAL(triggered(bool)), this, SLOT(bold()));
    QObject::connect(appWindow->actionItalic,       SIGNAL(triggered(bool)), this, SLOT(italic()));
    QObject::connect(appWindow->actionQuote,        SIGNAL(triggered(bool)), this, SLOT(quote()));
    QObject::connect(appWindow->actionCode,         SIGNAL(triggered(bool)), this, SLOT(code()));
    QObject::connect(appWindow->actionHeading_1,    SIGNAL(triggered(bool)), this, SLOT(heading1()));
    QObject::connect(appWindow->actionHeading_2,    SIGNAL(triggered(bool)), this, SLOT(heading2()));
    QObject::connect(appWindow->actionHeading_3,    SIGNAL(triggered(bool)), this, SLOT(heading3()));
    QObject::connect(appWindow->actionHeading_4,    SIGNAL(triggered(bool)), this, SLOT(heading4()));
    QObject::connect(appWindow->actionHyperlink,    SIGNAL(triggered(bool)), this, SLOT(hyperlink()));
    QObject::connect(appWindow->actionImage,        SIGNAL(triggered(bool)), this, SLOT(image()));
    QObject::connect(appWindow->actionUnordered_List, SIGNAL(triggered(bool)), this, SLOT(unorderedList()));
    QObject::connect(appWindow->actionOrdered_List,   SIGNAL(triggered(bool)), this, SLOT(orderedList()));
    QObject::connect(appWindow->actionHorizontal_Rule,SIGNAL(triggered(bool)), this, SLOT(horizontalRule()));
    QObject::connect(appWindow->actionTimestamp,    SIGNAL(triggered(bool)), this, SLOT(timestamp()));
    QObject::connect(appWindow->actionPage_Number,  SIGNAL(triggered(bool)), this, SLOT(pageNumber()));
    QObject::connect(appWindow->actionPage_Count,   SIGNAL(triggered(bool)), this, SLOT(pageCount()));
    QObject::connect(appWindow->actionOptions,      SIGNAL(triggered(bool)), this, SLOT(options()));
    QObject::connect(appWindow->actionSave_All,     SIGNAL(triggered(bool)), this, SLOT(saveAll()));
    QObject::connect(appWindow->actionSelect_All,   SIGNAL(triggered(bool)), this, SLOT(selectAll()));
    QObject::connect(appWindow->actionDelete,       SIGNAL(triggered(bool)), this, SLOT(del()));
    QObject::connect(appWindow->actionUndo,         SIGNAL(triggered(bool)), this, SLOT(undo()));
    QObject::connect(appWindow->actionRedo,         SIGNAL(triggered(bool)), this, SLOT(redo()));
    QObject::connect(appWindow->actionFind,         SIGNAL(triggered(bool)), this, SLOT(find()));
    QObject::connect(appWindow->actionFind_Next,    SIGNAL(triggered(bool)), this, SLOT(findNext()));
    QObject::connect(appWindow->actionFind_Previous,SIGNAL(triggered(bool)), this, SLOT(findPrevious()));
    QObject::connect(appWindow->actionGo_to_Line,   SIGNAL(triggered(bool)), this, SLOT(goToLine()));
    QObject::connect(appWindow->action_Tile_Windows,SIGNAL(triggered(bool)), this, SLOT(tileSubWindows()));
    QObject::connect(appWindow->action_Windowed,    SIGNAL(triggered(bool)), this, SLOT(cascadeSubWindows()));
    QObject::connect(appWindow->actionTabbed,       SIGNAL(triggered(bool)), this, SLOT(tabSubWindows()));
    QObject::connect(appWindow->actionClose,        SIGNAL(triggered(bool)), mdiArea, SLOT(closeActiveSubWindow()));
    QObject::connect(appWindow->actionClose_All,    SIGNAL(triggered(bool)), mdiArea, SLOT(closeAllSubWindows()));
    QObject::connect(appWindow->actionNext,         SIGNAL(triggered(bool)), mdiArea, SLOT(activateNextSubWindow()));
    QObject::connect(appWindow->actionPrevious,     SIGNAL(triggered(bool)), mdiArea, SLOT(activatePreviousSubWindow()));

    QObject::connect(appWindow->actionSupport,       SIGNAL(triggered(bool)), this, SLOT(support()));
    QObject::connect(appWindow->actionWebsite,      SIGNAL(triggered(bool)), this, SLOT(website()));

    statusBar()->showMessage(tr("Ready"));
    updateActions();

    setUnifiedTitleAndToolBarOnMac(true);
#if QT_VERSION >= 0x050000
    menuBar()->setNativeMenuBar(false);
#endif

/*
    EnumPropertyEditorTest();
    updateObjectTree(MakeTestObjectTree());
    //changeProjectTree(this);
*/

    Project *p = new Project;
    p->setObjectName("P1");
    p->m_Author = "John";
    //p->m_Name = "Project Name";

/*
    Output *out = new Output;
    out->m_Title = "Title";
    out->m_Filename = "OutFile.pdf";
    out->m_FileType = Output::PDF;
    p->setOutput(out);

    Template *tmpl = new Template;
    tmpl->m_Filename = "Templ.tmpl";
    tmpl->m_Color = QColor(1,2,3);
    p->setTemplate(tmpl);
*/

    p->setTitle("Title");
    p->setOutputFilename("OutFile.pdf");
    p->setOutputFileType(Project::PDF);
    p->setTemplate("Templ.tmpl");
    p->setColor(QColor(1,2,3));


    Input *in = new Input;
    in->setObjectName("InFile1");
    in->m_Filename = "InFile1.md";
    p->AddInput(in);

    Input *in2 = new Input;
    in2->setObjectName("InFile2");
    in2->m_Filename = "InFile2.md";
    p->AddInput(in2);
    /*
    in.m_Filename = "InFile2.md";
    p.m_Inputs.append(in);
    in.m_Filename = "InFile3.md";
    p.m_Inputs.append(in);
    */

    //solution.m_Projects.append(p);

    //solution.AddProject(p);

    /*
    p.m_Name = "Project Name 2";
    p.m_Output.m_Title = "Title 2";
    p.m_Output.m_Filename = "OutFile2.pdf";
    solution.m_Projects.append(p);
    */

    //changeProjectTree(&solution);

    //tabifyDockWidget(appWindow->projectDock, appWindow->objectsDock);
    //tabifyDockWidget(appWindow->projectDock, appWindow->propertiesDock);
    appWindow->projectDock->raise();
    appWindow->eventLogDock->hide();
    appWindow->consoleDock->hide();

    readSettings();
}


void MdiWindow::closeEvent(QCloseEvent *event)
{
    YQ_LOG_DEBUG("Closing all documents (received MdiWindow::closeEvent)");
    mdiArea->closeAllSubWindows();
    if (mdiArea->currentSubWindow()) {
        YQ_LOG_DEBUG("Ignoring MdiWindow::closeEvent");
        event->ignore();
    } else {
        writeSettings();
        YQ_LOG_DEBUG("Accepting MdiWindow::closeEvent");
        event->accept();
    }
}


void MdiWindow::newFile()
{
    YQ_LOG_DEBUG("newFile");
    MdiChild *child = createMdiChild();
    child->newFile();
    child->show();
}


void MdiWindow::open()
{
    YQ_LOG_DEBUG("open");
    QString fileName = QFileDialog::getOpenFileName(this);
    if (!fileName.isEmpty()) {
        QMdiSubWindow *existing = findMdiChild(fileName);
        if (existing) {
            mdiArea->setActiveSubWindow(existing);
            return;
        }

        if (openFile(fileName))
            statusBar()->showMessage(tr("File loaded"), 2000);
    }
}


bool MdiWindow::openFile(const QString &fileName)
{
    YQ_LOG_DEBUG("openFile %s", fileName.toLatin1().data());
    MdiChild *child = createMdiChild();
    const bool succeeded = child->loadFile(fileName);
    if (succeeded)
        child->show();
    else
        child->close();
    return succeeded;
}


void MdiWindow::save()
{
    YQ_LOG_DEBUG("save");
    if (activeMdiChild() && activeMdiChild()->save())
        statusBar()->showMessage(tr("File saved"), 2000);
}


void MdiWindow::saveAs()
{
    YQ_LOG_DEBUG("saveAs");
    if (activeMdiChild() && activeMdiChild()->saveAs())
        statusBar()->showMessage(tr("File saved"), 2000);
}


#ifndef QT_NO_CLIPBOARD
void MdiWindow::cut()
{
    if (activeMdiChild())
        activeMdiChild()->cut();
}


void MdiWindow::copy()
{
    if (activeMdiChild())
        activeMdiChild()->copy();
}


void MdiWindow::paste()
{
    if (activeMdiChild())
        activeMdiChild()->paste();
}
#endif


void MdiWindow::support()
{
    QDesktopServices::openUrl(QUrl("http://www.subflexion.com/MakePDF/support.html"));
    lower();
}


void MdiWindow::website()
{
    QDesktopServices::openUrl(QUrl("http://www.subflexion.com/MakePDF/about.html"));
}


void MdiWindow::upgradeClicked()
{
    QDesktopServices::openUrl(QUrl("http://www.subflexion.com/MakePDF/register.html"));
}


void MdiWindow::bold()
{
    if (activeMdiChild()) activeMdiChild()->bold();
}
void MdiWindow::italic()
{
    if (activeMdiChild()) activeMdiChild()->italic();
}
void MdiWindow::quote()
{
    if (activeMdiChild()) activeMdiChild()->quote();
}
void MdiWindow::code()
{
    if (activeMdiChild()) activeMdiChild()->code();
}
void MdiWindow::heading1()
{
    if (activeMdiChild()) activeMdiChild()->heading1();
}
void MdiWindow::heading2()
{
    if (activeMdiChild()) activeMdiChild()->heading2();
}
void MdiWindow::heading3()
{
    if (activeMdiChild()) activeMdiChild()->heading3();
}
void MdiWindow::heading4()
{
    if (activeMdiChild()) activeMdiChild()->heading4();
}
void MdiWindow::hyperlink()
{
    if (activeMdiChild()) activeMdiChild()->hyperlink();
}
void MdiWindow::image()
{
    if (activeMdiChild()) activeMdiChild()->image();
}
void MdiWindow::unorderedList()
{
    if (activeMdiChild()) activeMdiChild()->unorderedList();
}
void MdiWindow::orderedList()
{
    if (activeMdiChild()) activeMdiChild()->orderedList();
}
void MdiWindow::horizontalRule()
{
    if (activeMdiChild()) activeMdiChild()->horizontalRule();
}
void MdiWindow::timestamp()
{
    if (activeMdiChild()) activeMdiChild()->timestamp();
}
void MdiWindow::pageNumber()
{
    if (activeMdiChild()) activeMdiChild()->pageNumber();
}
void MdiWindow::pageCount()
{
    if (activeMdiChild()) activeMdiChild()->pageCount();
}
void MdiWindow::options()
{
}
void MdiWindow::saveAll()
{
}
void MdiWindow::selectAll()
{
    if (activeMdiChild()) activeMdiChild()->selectAll();
}
void MdiWindow::del()
{
    if (activeMdiChild()) activeMdiChild()->del();
}
void MdiWindow::undo()
{
    if (activeMdiChild()) activeMdiChild()->undo();
}
void MdiWindow::redo()
{
    if (activeMdiChild()) activeMdiChild()->redo();
}
void MdiWindow::find()
{
    if (activeMdiChild()) activeMdiChild()->find();
}
void MdiWindow::findNext()
{
    if (activeMdiChild()) activeMdiChild()->findNext();
}
void MdiWindow::findPrevious()
{
    if (activeMdiChild()) activeMdiChild()->findPrevious();
}
void MdiWindow::goToLine()
{
    if (activeMdiChild()) activeMdiChild()->goToLine();
}


#include "html.h"
#include "document.h"
#include "DocConvert.h"
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QHttpPart>


void MdiWindow::handleRequest()
{
    if (server->hasPendingConnections())
    {
        QTcpSocket* sock = server->nextPendingConnection();
        sock->waitForReadyRead();
        QByteArray ba = sock->readAll();
        //if (sock->canReadLine())
        {
            QString str(ba);
            QStringList tokens = str.split(QRegExp("[ \r\n][ \r\n]*"));
            bool haveGet = false;
            bool haveDoc = false;
            for (int i = 0; i < tokens.size(); i++) {
                if (tokens[i] == "GET")
                    haveGet = true;
                if (tokens[i].contains(QString("pdf"), Qt::CaseInsensitive))
                    haveDoc = true;
            }
            if (haveGet && haveDoc) //tokens[0] == "GET" && tokens[1].contains(QString("pdf"), Qt::CaseInsensitive ))
            {
                QTextStream os(sock);
                os.setAutoDetectUnicode(true);
                os << "HTTP/1.0 200 Ok\r\n"
                    "Content-Type: application/pdf; charset=\"utf-8\"\r\n"
                    "Content-Length: " << pdfContents.size() <<
                    "\r\n"
                    "\r\n";
                //os << pdfContents.data();
                //"<h1>Nothing to see here</h1>\n"
                //<< QDateTime::currentDateTime().toString() << "\n";
                os.flush();
                sock->flush();
                sock->write(pdfContents.data(), pdfContents.size());
                sock->flush();
                //sock->write(ba);
            }
            else
            {
               QTextStream os(sock);
                os.setAutoDetectUnicode(true);
                os << "HTTP/1.0 404 Ok\r\n"
                      "\r\n"
                      "\r\n";
            }
        }
        sock->waitForBytesWritten();
        sock->waitForDisconnected();
        sock->close();
        delete sock;
    }
}


void MdiWindow::setupServer()
{
    // setup the web server
    server = new QTcpServer;
    if (!server->listen(QHostAddress::LocalHost, 12345))
    {
        qFatal("Failed to open web socket server.");
    }
    connect(server, SIGNAL(newConnection()), this, SLOT(handleRequest()));
/*

    // open a browser window with the client HTML page
    QUrl url = QUrl::fromLocalFile(BUILD_DIR "/index.html");
    url.setQuery(QStringLiteral("webChannelBaseUrl=") + server.serverUrl().toString());
    QDesktopServices::openUrl(url);
    dialog.displayMessage(QObject::tr("Initialization complete, opening browser at %1.").arg(url.toDisplayString()));
*/
}


void MdiWindow::updatePreview()
{
    MdiChild* child = activeMdiChild();
    if (child)
    {
        static int ver = 0;
        //char fileName[1024];
        //sprintf(fileName, "test/test-%i.pdf", ver);
        ver++;
        const char *fileName = "test/test.pdf";
        QByteArray text = child->toPlainText().toLatin1();
        char* data;
        size_t size;

        DocConvert converter;
        converter.SetSourceData(text.data(), text.size());
        converter.Convert();
        converter.GetHTMLData(&data, &size);

        converter.OutputPDF(fileName);

        appWindow->previewText->setText(QString(QLatin1String(data, size)));

        pdfContents.resize(5*1024*1024);
        size = 5*1024*1024;
        converter.GetPDFData(pdfContents.data(), &size);
        pdfContents.resize(size);
        //pdfContents = QByteArray(data, size);

        //QTimer::singleShot(100, this, SLOT(setWebPreviewURL()));
        // ../../../build-MakePDF-Desktop-Debug/
        //appWindow->webPreview->setUrl(QUrl(QString("file:///home/jryland/Code/applications/MakePDF/3rdParty/pdf.js/web/viewer.html?file=http://localhost:12345/") + fileName));
        appWindow->webPreview->setUrl(QUrl(QString("http://localhost:12345/") + fileName));
        QTimer::singleShot(1000, this, SLOT(refreshWebPreview()));
    }
}


void MdiWindow::setWebPreviewURL()
{
    const char *fileName = "test/test.pdf";
    appWindow->webPreview->setUpdatesEnabled(false);
    //appWindow->webPreview->setUrl(QUrl(QString("file:///home/jryland/Code/applications/MakePDF/3rdParty/pdf.js/web/viewer.html?file=../../../build-MakePDF-Desktop-Debug/") + fileName));
    appWindow->webPreview->setUrl(QUrl(QString("file:///home/jryland/Code/applications/MakePDF/build-MakePDF-Desktop-Debug/pdf.js/web/viewer.html?file=../../../build-MakePDF-Desktop-Debug/") + fileName));
    QTimer::singleShot(1000, this, SLOT(refreshWebPreview()));
}


void MdiWindow::refreshWebPreview()
{
    appWindow->webPreview->setUpdatesEnabled(true);
}


void MdiWindow::updateActions()
{
    bool hasMdiChild = (activeMdiChild() != 0);
    bool hasSelection = (hasMdiChild && activeMdiChild()->textCursor().hasSelection());

    appWindow->actionSave->setEnabled(hasMdiChild);
    appWindow->actionSave_As->setEnabled(hasMdiChild);
    appWindow->actionSave_All->setEnabled(hasMdiChild);
    appWindow->actionClose->setEnabled(hasMdiChild);
#ifndef QT_NO_CLIPBOARD
    appWindow->actionCut->setEnabled(hasSelection);
    appWindow->actionCopy->setEnabled(hasSelection);
    appWindow->actionPaste->setEnabled(hasMdiChild);
#endif
    appWindow->actionSelect_All->setEnabled(hasMdiChild);
    appWindow->actionDelete->setEnabled(hasMdiChild);
    appWindow->actionUndo->setEnabled(hasMdiChild);
    appWindow->actionRedo->setEnabled(hasMdiChild);
    appWindow->actionFind->setEnabled(hasMdiChild);
    appWindow->actionFind_Next->setEnabled(hasMdiChild);
    appWindow->actionFind_Previous->setEnabled(hasMdiChild);
    appWindow->actionGo_to_Line->setEnabled(hasMdiChild);
    appWindow->actionBold->setEnabled(hasMdiChild);
    appWindow->actionItalic->setEnabled(hasMdiChild);
    appWindow->actionQuote->setEnabled(hasMdiChild);
    appWindow->actionCode->setEnabled(hasMdiChild);
    appWindow->actionHeading_1->setEnabled(hasMdiChild);
    appWindow->actionHeading_2->setEnabled(hasMdiChild);
    appWindow->actionHeading_3->setEnabled(hasMdiChild);
    appWindow->actionHeading_4->setEnabled(hasMdiChild);
    appWindow->actionHyperlink->setEnabled(hasMdiChild);
    appWindow->actionImage->setEnabled(hasMdiChild);
    appWindow->actionUnordered_List->setEnabled(hasMdiChild);
    appWindow->actionOrdered_List->setEnabled(hasMdiChild);
    appWindow->actionHorizontal_Rule->setEnabled(hasMdiChild);
    appWindow->actionTimestamp->setEnabled(hasMdiChild);
    appWindow->actionPage_Number->setEnabled(hasMdiChild);
    appWindow->actionPage_Count->setEnabled(hasMdiChild);
    appWindow->actionClose_All->setEnabled(hasMdiChild);
    appWindow->actionNext->setEnabled(hasMdiChild);
    appWindow->actionPrevious->setEnabled(hasMdiChild);
    appWindow->action_Tile_Windows->setEnabled(hasMdiChild);
    appWindow->action_Windowed->setEnabled(hasMdiChild);

    //appWindow->actionTabbed->setEnabled(hasMdiChild);
    //separatorAct->setVisible(hasMdiChild);

    appWindow->menuView->clear();
    appWindow->menuView->addAction(appWindow->action_Tile_Windows);
    appWindow->menuView->addAction(appWindow->action_Windowed);
    appWindow->menuView->addAction(appWindow->actionTabbed);
    appWindow->menuView->addSeparator();
    appWindow->menuView->addAction(appWindow->actionNext);
    appWindow->menuView->addAction(appWindow->actionPrevious);

    QList<QMdiSubWindow *> windows = mdiArea->subWindowList();
    if (!windows.isEmpty())
        appWindow->menuView->addSeparator();

    for (int i = 0; i < windows.size(); ++i) {
        MdiChild *child = qobject_cast<MdiChild *>(windows.at(i)->widget());
        QString text = QString("%1 %2").arg(i + 1).arg(child->userFriendlyCurrentFile());
        if (i < 9)
            text = "&" + text;
        QAction *action = appWindow->menuView->addAction(text);
        action->setCheckable(true);
        action->setChecked(child == activeMdiChild());
        connect(action, SIGNAL(triggered(bool)), windowMapper, SLOT(map()));
        windowMapper->setMapping(action, windows.at(i));
    }
}


MdiChild *MdiWindow::createMdiChild()
{
    MdiChild *child = new MdiChild;
    mdiArea->addSubWindow(child);
    connect(child, SIGNAL(documentContentsChanged()), this, SLOT(updatePreview()));
    connect(child, SIGNAL(closing()), this,  SLOT(updateActions()));
#ifndef QT_NO_CLIPBOARD
    connect(child, SIGNAL(copyAvailable(bool)), appWindow->actionCut,  SLOT(setEnabled(bool)));
    connect(child, SIGNAL(copyAvailable(bool)), appWindow->actionCopy, SLOT(setEnabled(bool)));
#endif
    return child;
}


void MdiWindow::cascadeSubWindows()
{
    mdiArea->setViewMode(QMdiArea::SubWindowView);
    mdiArea->cascadeSubWindows();
}


void MdiWindow::tileSubWindows()
{
    mdiArea->setViewMode(QMdiArea::SubWindowView);
    mdiArea->tileSubWindows();
}


void MdiWindow::tabSubWindows()
{
    mdiArea->setViewMode(QMdiArea::TabbedView);
}


void MdiWindow::readLicense()
{
    YQ_LOG_DEBUG("Reading license");
    QSettings settings(QSettings::NativeFormat, QSettings::UserScope, "Subflexion", "MakePDF");
}


void MdiWindow::readSettings()
{
    YQ_LOG_DEBUG("Reading settings");
    QSettings settings(QSettings::NativeFormat, QSettings::UserScope, "Subflexion", "MakePDF");
    settings.beginGroup("MainWindow");
    restoreState(settings.value("DockLayout").toByteArray());
    move(settings.value("Position", QPoint(200, 200)).toPoint());
    resize(settings.value("Size", QSize(400, 400)).toSize());
    settings.endGroup();
    settings.beginGroup("License");
    QString user = settings.value("User").toString();
    QString licenseType = settings.value("Type").toString();
    settings.endGroup();
}


void MdiWindow::writeSettings()
{
    YQ_LOG_DEBUG("Saving settings");
    QSettings settings(QSettings::NativeFormat, QSettings::UserScope, "Subflexion", "MakePDF");
    settings.beginGroup("MainWindow");
    settings.setValue("DockLayout", saveState());
    settings.setValue("Position", pos());
    settings.setValue("Size", size());
    settings.endGroup();
}


MdiChild *MdiWindow::activeMdiChild()
{
    if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow())
        return qobject_cast<MdiChild *>(activeSubWindow->widget());
    return 0;
}


QMdiSubWindow *MdiWindow::findMdiChild(const QString &fileName)
{
    QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();

    foreach (QMdiSubWindow *window, mdiArea->subWindowList()) {
        MdiChild *mdiChild = qobject_cast<MdiChild *>(window->widget());
        if (mdiChild && mdiChild->currentFile() == canonicalFilePath)
            return window;
    }
    return 0;
}


void MdiWindow::switchLayoutDirection()
{
    if (layoutDirection() == Qt::LeftToRight)
        qApp->setLayoutDirection(Qt::RightToLeft);
    else
        qApp->setLayoutDirection(Qt::LeftToRight);
}


void MdiWindow::setActiveSubWindow(QWidget *window)
{
    if (!window)
        return;
    mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));
}



#include "Objects.h"
QObject* MakeTestObjectTree()
{
    QObject* o = new MyObjectTest;
    return o;
}


void EnumEditor::ListSelectionChanged()
{
    QList<QListWidgetItem*> items = lw->selectedItems();
    if (!items.count())
        return;
    QString combinedString = items.at(0)->text();
    for (int i = 1; i < items.count(); i++)
        combinedString += " | " + items.at(i)->text();
    int value = m_metaEnum.keysToValue(combinedString.toLocal8Bit().data());
    sb->setValue(value);
    str->setText(m_metaEnum.valueToKeys(value).data());
}


void EnumEditor::ComboSelectionChanged()
{
    QString combinedString = cb->currentText();
    sb->setValue(m_metaEnum.keysToValue(combinedString.toLocal8Bit().data()));
    str->setText(combinedString);
}


EnumEditor::EnumEditor(QMetaEnum metaEnum)
{
    m_metaEnum = metaEnum;
    QGridLayout* grid = new QGridLayout();
    QLabel* l1 = new QLabel("Name");
    QLabel* l2 = new QLabel("Enum");
    QLabel* l3 = new QLabel("Value");
    QLabel* l4 = new QLabel("String");
    grid->addWidget(l1, 0, 0);
    grid->addWidget(l2, 1, 0);
    grid->addWidget(l3, 2, 0);
    grid->addWidget(l4, 3, 0);
    QLabel* v1 = new QLabel(metaEnum.name());

    QWidget* v2 = 0;
    if (metaEnum.isFlag())
    {
        lw = new QListWidget();
        lw->setSelectionMode(QAbstractItemView::MultiSelection);
        for (int i = 0; i < metaEnum.keyCount(); i++)
        {
            lw->addItem(metaEnum.valueToKey(metaEnum.value(i)));
        }
        v2 = lw;
        connect(lw, SIGNAL(itemSelectionChanged()), this, SLOT(ListSelectionChanged()));
    }
    else
    {
        cb = new QComboBox();
        for (int i = 0; i < metaEnum.keyCount(); i++)
        {
            cb->addItem(metaEnum.valueToKey(metaEnum.value(i)));
        }
        connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(ComboSelectionChanged()));
        v2 = cb;
    }

    sb = new QSpinBox();
    str = new QLabel();
    grid->addWidget(v1, 0, 1);
    grid->addWidget(v2, 1, 1);
    grid->addWidget(sb, 2, 1);
    grid->addWidget(str, 3, 1);
    setLayout(grid);
    show();
}


void EnumPropertyEditorTest()
{
    MyObjectTest* o = new MyObjectTest;
    for (int i = 0; i < o->metaObject()->enumeratorCount(); i++)
        new EnumEditor(o->metaObject()->enumerator(i));
}



#include "ObjectVisitor.h"


class SerializeVisitor : public Visitor
{
public:
    SerializeVisitor(const char* fileName) { file = fopen(fileName, "wb"); }
    virtual ~SerializeVisitor() { fclose(file); }
    virtual void enterObject(const char* className, const char* objectName)
    {
        std::string p = (path.size()) ? path.back() + "/" : "";
        path.push_back(p + objectName);
        fprintf(file, "[%s]\n", path.back().c_str());
        fprintf(file, "class=%s\n", className);
    }
    virtual void leaveObject(const char* className, const char* objectName)
    {
        fprintf(file, "; end of %s\n\n", objectName);
        path.pop_back();
        //fprintf(file, "--Leaving %s (%s)\n", objectName, className);
    }
    virtual void visit(const char* className,
                        const char* propertyName, QVariant::Type typ, QVariant& value)
    {
        //fprintf(file, "----Property:  %s %s::%s = %s\n", QVariant::typeToName(typ),
        //            className, propertyName, value.toString().toLocal8Bit().data());
        fprintf(file, "%s=%s\n", propertyName, value.toString().toLocal8Bit().data());
    }
private:
    FILE* file;
    std::vector<std::string> path;
};


#include <QLayout>
#include <QAction>
#include <QActionGroup>
#include <QPdfWriter>

#define CLASS_FACTORY(ClassName, ...) \
            else if (strcmp(className, #ClassName) == 0) return new ClassName(__VA_ARGS__)

QObject* classObjectFactory(const char* className)
{
    if (false) {}
    CLASS_FACTORY(QObject);
    CLASS_FACTORY(QWidget);
    CLASS_FACTORY(QTableView);
    CLASS_FACTORY(QTableWidget);
    CLASS_FACTORY(QLabel);
    CLASS_FACTORY(QPushButton);
    CLASS_FACTORY(QVBoxLayout);
    CLASS_FACTORY(QHBoxLayout);
    CLASS_FACTORY(QAction, nullptr);
    CLASS_FACTORY(QActionGroup, nullptr);
    CLASS_FACTORY(QButtonGroup);
    CLASS_FACTORY(QFileSelector);
    //CLASS_FACTORY(QPdfWriter);
    //CLASS_FACTORY(QSound);
    CLASS_FACTORY(QThread);
    CLASS_FACTORY(QTimer);
    printf("Unrecognized class name, ignoring\n");
    return 0;
}


class DeserializeVisitor : public Visitor
{
public:
    DeserializeVisitor(const char* fileName) { file = fopen(fileName, "rb"); }
    virtual ~DeserializeVisitor() { fclose(file); }
    virtual void enterObject(const char* className, const char* objectName)
    {
        std::string p = (path.size()) ? path.back() + "/" : "";
        path.push_back(p + objectName);
        fprintf(file, "[%s]\n", path.back().c_str());
        fprintf(file, "class=%s\n", className);
    }
    virtual void leaveObject(const char* className, const char* objectName)
    {
        fprintf(file, "; end of %s\n\n", objectName);
        path.pop_back();
        //fprintf(file, "--Leaving %s (%s)\n", objectName, className);
    }
    virtual void visit(const char* className,
                        const char* propertyName, QVariant::Type typ, QVariant& value)
    {
        //fprintf(file, "----Property:  %s %s::%s = %s\n", QVariant::typeToName(typ),
        //            className, propertyName, value.toString().toLocal8Bit().data());
        fprintf(file, "%s=%s\n", propertyName, value.toString().toLocal8Bit().data());
    }
    virtual bool isWriting()
    {
        return true;
    }
private:
    FILE* file;
    std::vector<std::string> path;
};

#include "qtpropertymanager.h"
#include "qtvariantproperty.h"
#include "qttreepropertybrowser.h"
#include "QtGroupBoxPropertyBrowser"
#include "ObjectTreeModel.h"


static QWidget *WrapWidgetInLayout(QWidget* wrapper, QWidget* w)
{
    QVBoxLayout *layout = new QVBoxLayout;
    wrapper->setLayout(layout);
    layout->addWidget(w);
    layout->setMargin(0);
    layout->setSpacing(0);
    layout->setContentsMargins(0,0,0,0);
    return wrapper;
}


void MdiWindow::updatePropertiesView(QObject *object)
{
    // Dynamically build the properties UI elements for the given object's properties
    QtVariantPropertyManager *variantManager = new QtVariantPropertyManager();
    QtVariantEditorFactory *variantFactory = new QtVariantEditorFactory();
    QtAbstractPropertyBrowser *groupEditor = new QtGroupBoxPropertyBrowser();
    groupEditor->setFactoryForManager(variantManager, variantFactory);
    QtTreePropertyBrowser *variantEditor = new QtTreePropertyBrowser();
    variantEditor->setFactoryForManager(variantManager, variantFactory);
    std::map<std::string, QtProperty*> pmap;
    for (int i = 0; i < object->metaObject()->propertyCount(); i++)
    {
        const QMetaProperty& property = object->metaObject()->property(i);
        std::string className = property.enclosingMetaObject()->className();
        QtProperty *parentItem = nullptr;
        if (pmap.find(className) == pmap.end()) {
            parentItem = variantManager->addProperty(QtVariantPropertyManager::groupTypeId(), className.c_str());
            pmap.insert(std::make_pair(className, parentItem));
            groupEditor->addProperty(parentItem);
            variantEditor->addProperty(parentItem);
        } else {
            parentItem = pmap[className];
        }
        QtVariantProperty *item = variantManager->addProperty(property.type(), property.name());
        if ( item ) {
            item->setValue(property.read(object));
            parentItem->addSubProperty(item);
        }
    }
    variantEditor->setIndentation(30);
    variantEditor->setPropertiesWithoutValueMarked(true);
    variantEditor->setRootIsDecorated(false);

    QScrollArea *scrollArea = new QScrollArea;
    scrollArea->setWidget(groupEditor);

    QTabWidget *tabs = new QTabWidget;
    tabs->addTab(WrapWidgetInLayout(new QWidget, variantEditor), "Property List");
    tabs->addTab(WrapWidgetInLayout(new QWidget, scrollArea), "Grouped");

    foreach (QObject* child, appWindow->propertiesView->children())
        if (child->isWidgetType())
            delete child;

    QLayout* lo = appWindow->propertiesView->layout();
    if (lo) {
        lo->addWidget(tabs);
    } else {
        WrapWidgetInLayout(appWindow->propertiesView, tabs);
    }
    //QObject::connect(variantManager, SIGNAL(propertyChanged(QtProperty*)), &blah, SLOT(updateProp(QtProperty*)));
}


void MdiWindow::changePropertiesObject(const QModelIndex &index)
{
    QObject* ptr = (QObject*)index.internalPointer();
    if (ptr)
        updatePropertiesView(ptr);
}


void MdiWindow::changeRootObject(const QModelIndex &index)
{
    QObject* ptr = (QObject*)index.internalPointer();
    if (ptr)
        updateObjectTree(ptr);
}


void MdiWindow::changeProjectTree(QObject *rootObject)
{
    QList<ObjPtr> list;
    list.append(ObjPtr(rootObject));

    if (appWindow->projectsView->model()) {
        ((ObjectTreeModel *)appWindow->projectsView->model())->setRootObjects(list);
    } else {
        ObjectTreeModel *objectTree = new ObjectTreeModel(appWindow->projectsView);
        objectTree->setRootObjects(list);
        appWindow->projectsView->setModel(objectTree);
    }

    appWindow->projectsView->header()->hide();
    QObject::connect(appWindow->projectsView, SIGNAL(clicked(const QModelIndex &)),
                     this, SLOT(changeRootObject(const QModelIndex &)));
}


void MdiWindow::updateObjectTree(QObject *rootObject)
{
    SerializeVisitor visitor("/tmp/object-dump.txt");
    Visit(visitor, rootObject);

    QList<ObjPtr> list;
    list.append(ObjPtr(rootObject));

    if (appWindow->objectsView->model()) {
        ((ObjectTreeModel *)appWindow->objectsView->model())->setRootObjects(list);
    } else {
        ObjectTreeModel *objectTree = new ObjectTreeModel(appWindow->objectsView);
        objectTree->setRootObjects(list);
        appWindow->objectsView->setModel(objectTree);
    }

    appWindow->objectsView->header()->hide();
    QObject::connect(appWindow->objectsView, SIGNAL(doubleClicked(const QModelIndex &)),
                     this, SLOT(changeRootObject(const QModelIndex &)));
    QObject::connect(appWindow->objectsView, SIGNAL(clicked(const QModelIndex &)),
                     this, SLOT(changePropertiesObject(const QModelIndex &)));
}
