/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QGuiApplication>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QMenu>
#include <QMenuBar>
#include <QScreen>
#include <QToolBar>

#include "MvQMainWindow.h"
#include "MvQMethods.h"
#include "MvQTheme.h"

MvQMainWindow::MvQMainWindow(QWidget* parent) :
    QMainWindow(parent),
    movableToolBars_(true)
{
#ifdef METVIEW
    QApplication::setWindowIcon(QIcon(MvQTheme::logo()));
#elif defined ECCODES_UI
    QApplication::setWindowIcon(QIcon(QPixmap(":/codes_ui/codes_ui.svg")));
#endif

    //#ifdef __APPLE__
    //    // Set this to false if you want non-native menus on Mac OS X (i.e. menus are the same as under Linux)
    //    menuBar()->setNativeMenuBar(false);
    //#endif

    menuName_[FileMenu] = "&File";
    menuName_[ShareMenu] = "Sha&re";
    menuName_[ViewMenu] = "&View";
    menuName_[NavigateMenu] = "&Go";
    menuName_[BookmarksMenu] = "&Bookmarks";
    menuName_[HistoryMenu] = "&History";
    menuName_[SettingsMenu] = "&Settings";
    menuName_[ToolsMenu] = "&Tools";
    menuName_[AnimationMenu] = "&Animation";
    menuName_[ZoomMenu] = "&Zoom";
    menuName_[ProfilesMenu] = "&Profiles";
    menuName_[SelectionMenu] = "&Selection";
    menuName_[HelpMenu] = "&Help";
    menuName_[EditMenu] = "&Edit";
    menuName_[StepMenu] = "&Steps";
    menuName_[FilterMenu] = "Fi&lter";
    menuName_[EditorMenu] = "&Editors";

    menuOrder_ << FileMenu << ShareMenu << EditMenu << ViewMenu << NavigateMenu << BookmarksMenu << HistoryMenu << EditorMenu << ProfilesMenu << FilterMenu << AnimationMenu << StepMenu << ZoomMenu << SelectionMenu << ToolsMenu << SettingsMenu << HelpMenu << ProgressBarMenu;

    // setIconSize(QSize(20,20));
}

void MvQMainWindow::setupMenus(MenuItemMap items, MenuOption option)
{
    QMap<MenuType, QToolBar*> toolBars;
    QMap<MenuType, QMenu*> menus;

    foreach (MenuType type, menuOrder_) {
        QMenu* menu = 0;
        QToolBar* toolBar = nullptr;

        QString menuName = menuName_[type];
        QString menuObjName = menuName;
        menuObjName.remove("&");
        menuObjName += " Menu";

        QString toolBarName = menuName_[type];
        toolBarName.remove("&");
        toolBarName += tr(" ToolBar");
        QString toolBarObjName = toolBarName;

        if (items.contains(type)) {
            if (option != ToolBarOnlyOption) {
                menu = createMenu(menuName, menuObjName, items[type]);
            }
            toolBar = createToolBar(toolBarName, toolBarObjName, items[type]);
        }
        else if (type == FileMenu || type == HelpMenu) {
            if (option != ToolBarOnlyOption) {
                menu = createMenu(menuName, menuObjName);
            }
        }

        populate(menu, toolBar, items[type]);
        if (menu)
            menus[type] = menu;
        if (toolBar)
            toolBars[type] = toolBar;

        // Add further actions
        if (type == FileMenu && menu &&
            isActionPresent(items[type], "actionQuit") == false) {
            // Quit
            auto* actionQuit = new QAction(this);
            actionQuit->setObjectName(QString::fromUtf8("actionQuit"));
            actionQuit->setText(tr("&Quit"));
            actionQuit->setShortcut(tr("Ctrl+Q"));

            menu->addSeparator();
            menu->addAction(actionQuit);

            // Exit slot
            connect(actionQuit, SIGNAL(triggered()),
                    this, SLOT(close()));
        }
        else if (type == HelpMenu && menu) {
            // About Qt
            /*QAction* actionQt = new QAction(this);
                actionQt->setObjectName(QString::fromUtf8("About Qt"));
            actionQt->setText(tr("About &Qt"));

            menu->addAction(actionQt);

            connect(actionQt,SIGNAL(triggered()),qApp,SLOT(aboutQt()));*/
        }
    }

    // toolBarViewActions

    if (menus.contains(ViewMenu)) {
        QMenu* vm = menus[ViewMenu];
        if (toolBars.count() > 0) {
            vm->addSeparator();

            auto* subMenu = new QMenu(tr("ToolBars"), this);
            vm->addMenu(subMenu);

            foreach (QToolBar* tb, toolBars) {
                subMenu->addAction(tb->toggleViewAction());
            }
        }
    }
}


QMenu* MvQMainWindow::createMenu(QString name, QString objectName, QList<MvQMenuItem*> items)
{
    if (isMenuNeeded(items) == false)
        return nullptr;

    return createMenu(name, objectName);
}

QMenu* MvQMainWindow::createMenu(QString name, QString objectName)
{
    auto* menu = new QMenu(name, this);
    menu->setObjectName(objectName);
    menuBar()->addMenu(menu);
    return menu;
}

QToolBar* MvQMainWindow::createToolBar(QString name, QString objectName, QList<MvQMenuItem*> items,
                                       Qt::ToolBarAreas allowedAreas)
{
    if (isToolBarNeeded(items) == false)
        return nullptr;

    return createToolBar(name, objectName, allowedAreas);
}

QToolBar* MvQMainWindow::createToolBar(QString name, QString objectName, Qt::ToolBarAreas allowedAreas)
{
    auto* toolBar = new QToolBar(name, this);
    toolBar->setObjectName(objectName);
    toolBar->setAllowedAreas(allowedAreas);

    if (movableToolBars_ == false)
        toolBar->setMovable(false);

    if (toolBar->allowedAreas() == Qt::AllToolBarAreas) {
        addToolBar(Qt::TopToolBarArea, toolBar);
    }
    else if (toolBar->allowedAreas() & Qt::TopToolBarArea) {
        addToolBar(Qt::TopToolBarArea, toolBar);
    }
    else if (toolBar->allowedAreas() & Qt::BottomToolBarArea) {
        addToolBar(Qt::BottomToolBarArea, toolBar);
    }
    else if (toolBar->allowedAreas() & Qt::LeftToolBarArea) {
        addToolBar(Qt::LeftToolBarArea, toolBar);
    }
    else if (toolBar->allowedAreas() & Qt::RightToolBarArea) {
        addToolBar(Qt::RightToolBarArea, toolBar);
    }

    return toolBar;
}

void MvQMainWindow::populate(QMenu* menu, QToolBar* toolBar, QList<MvQMenuItem*> items)
{
    if (!menu && !toolBar)
        return;

    QMenu* subMenu = nullptr;

    foreach (MvQMenuItem* item, items) {
        if (!item->object())
            continue;

        const char* type_char = item->object()->metaObject()->className();
        QString type(type_char);
        if (type == "QAction" || type == "QUndoAction") {
            if (item->targets().testFlag(MvQMenuItem::SubMenuTarget)) {
                auto* action = static_cast<QAction*>(item->object());
                if (subMenu)
                    subMenu->addAction(action);
            }
            else if (item->targets().testFlag(MvQMenuItem::MenuTarget)) {
                subMenu = nullptr;
                auto* action = static_cast<QAction*>(item->object());
                if (menu)
                    menu->addAction(action);
            }
            else {
                subMenu = nullptr;
            }

            if (item->targets().testFlag(MvQMenuItem::ToolBarTarget)) {
                auto* action = static_cast<QAction*>(item->object());
                if (toolBar)
                    toolBar->addAction(action);
            }
        }
        else if (type == "QMenu") {
            subMenu = static_cast<QMenu*>(item->object());
            menu->addMenu(subMenu);
        }
        else if (toolBar && item->targets().testFlag(MvQMenuItem::ToolBarTarget)) {
            auto* w = static_cast<QWidget*>(item->object());
            if (w)
                toolBar->addWidget(w);
        }
        /*else if(type == "QWidget" || type == "QPushButton" ||  type == "QToolButton" ||
            type == "MvQZoomStackWidget" || type == "QComboBox" ||
            type == "QLabel" || type == "QLineEdit" || type == "MvQSceneComboBox")
        {
            if(item->targets().testFlag(MvQMenuItem::ToolBarTarget))
            {
                QWidget* w=static_cast<QWidget*>(item->object());
                if(toolBar) toolBar->addWidget(w);
            }
        }*/
    }
}
bool MvQMainWindow::isToolBarItemPresent(QList<MvQMenuItem*> items)
{
    foreach (MvQMenuItem* item, items) {
        if (item->targets().testFlag(MvQMenuItem::ToolBarTarget)) {
            return true;
        }
    }
    return false;
}

QAction* MvQMainWindow::findAction(QList<QAction*> actions, QString name)
{
    foreach (QAction* item, actions) {
        if (item->objectName() == name) {
            return item;
        }
    }
    return nullptr;
}

bool MvQMainWindow::isActionPresent(QList<MvQMenuItem*> items, QString name)
{
    foreach (MvQMenuItem* item, items) {
        const char* type_char = item->object()->metaObject()->className();
        QString type(type_char);
        if (type == "QAction") {
            auto* action = static_cast<QAction*>(item->object());
            if (action->objectName() == name) {
                return true;
            }
        }
    }

    return false;
}

bool MvQMainWindow::isMenuNeeded(QList<MvQMenuItem*> items)
{
    foreach (MvQMenuItem* item, items) {
        if (item->targets().testFlag(MvQMenuItem::MenuTarget) ||
            item->targets().testFlag(MvQMenuItem::SubMenuTarget)) {
            return true;
        }
    }
    return false;
}

QMenu* MvQMainWindow::findMenu(MvQMainWindow::MenuType menuType)
{
    QString name = menuName_[menuType];
    name.remove("&");
    name += tr(" Menu");

    foreach (QMenu* m, findChildren<QMenu*>()) {
        if (m->objectName() == name) {
            return m;
        }
    }

    return nullptr;
}

bool MvQMainWindow::isToolBarNeeded(QList<MvQMenuItem*> items)
{
    foreach (MvQMenuItem* item, items) {
        if (item->targets().testFlag(MvQMenuItem::ToolBarTarget)) {
            return true;
        }
    }
    return false;
}

QToolBar* MvQMainWindow::findToolBar(MvQMainWindow::MenuType menuType)
{
    QString name = menuName_[menuType];
    name.remove("&");
    name += tr(" ToolBar");

    foreach (QToolBar* tb, findChildren<QToolBar*>()) {
        if (tb->objectName() == name) {
            return tb;
        }
    }

    return nullptr;
}

QRect MvQMainWindow::screenGeometry()
{
    auto sc = QGuiApplication::primaryScreen();
    if (sc) {
        return sc->geometry();
    }
    return {};
}

void MvQMainWindow::setInitialSize(int w, int h)
{
    QRect scg = screenGeometry();

    int wr = (scg.width() > w) ? w : scg.width() - 50;
    int hr = (scg.height() > h) ? h : scg.height() - 50;

    resize(QSize(wr, hr));
}

QAction* MvQMainWindow::createAction(ActionType type, QObject* parent)
{
    auto* action = new QAction(parent);
    QIcon icon;

    switch (type) {
        case AboutAction:
            action->setObjectName(QString::fromUtf8("actionAbout"));
            icon.addPixmap(MvQTheme::logo(), QIcon::Normal, QIcon::Off);
            break;
        case CloseAction:
            action->setObjectName(QString::fromUtf8("actionClose"));
            icon.addPixmap(QPixmap(QString::fromUtf8(":/window/close.svg")), QIcon::Normal, QIcon::Off);
            action->setText("&Close");
            action->setShortcut(tr("Ctrl+W"));
            break;
        case LogAction:
            action->setObjectName(QString::fromUtf8("actionLog"));
            icon.addPixmap(QPixmap(QString::fromUtf8(":/examiner/log.svg")), QIcon::Normal, QIcon::Off);
            action->setCheckable(true);
            action->setChecked(false);
            action->setText("&Log");
            action->setToolTip(tr("View log"));
            break;
        case ConfigureAction:
            action->setObjectName(QString::fromUtf8("actionConfigure"));
            icon.addPixmap(QPixmap(QString::fromUtf8(":/window/configure.svg")), QIcon::Normal, QIcon::Off);
            action->setText("&Configure");
            action->setToolTip(tr("Configure"));
            break;
        case FindAction:
            action->setObjectName(QString::fromUtf8("actionFind"));
            icon.addPixmap(QPixmap(QString::fromUtf8(":/find/search.svg")), QIcon::Normal, QIcon::Off);
            action->setText("&Find");
            action->setToolTip(tr("Find"));
            action->setShortcut(tr("Ctrl+F"));
            break;
        case FindNextAction:
            action->setObjectName(QString::fromUtf8("actionFindNext"));
            icon.addPixmap(QPixmap(QString::fromUtf8(":/find/next.svg")), QIcon::Normal, QIcon::Off);
            action->setText("Find &Next");
            action->setToolTip(tr("Find next"));
            action->setShortcut(tr("F3"));
            break;
        case FindPreviousAction:
            action->setObjectName(QString::fromUtf8("actionFindPrevious"));
            icon.addPixmap(QPixmap(QString::fromUtf8(":/find/prev.svg")), QIcon::Normal, QIcon::Off);
            action->setText("Find &Previous");
            action->setToolTip(tr("Find previous"));
            action->setShortcut(tr("Shift+F3"));
            break;
        case QuitAction:
            action->setObjectName(QString::fromUtf8("actionQuit"));
            // icon.addPixmap(QPixmap(QString::fromUtf8(":/window/exit.svg")), QIcon::Normal, QIcon::Off);
            action->setText("&Quit");
            action->setShortcut(tr("Ctrl+Q"));
            break;

        default:
            break;
    }

    action->setIcon(icon);

    return action;
}

QAction* MvQMainWindow::createAction(QString text, QString shortcut, QString data, QObject* parent)
{
    auto* ac = new QAction(parent);
    ac->setText(text);
    ac->setShortcut(shortcut);
    ac->setData(data);
    return ac;
}

QAction* MvQMainWindow::createSeparator(QObject* parent)
{
    auto* ac = new QAction(parent);
    ac->setSeparator(true);
    return ac;
}

void MvQMainWindow::setAppIcon(QString name)
{
    QPixmap winPix(MvQ::iconPixmapPath(name));
    if (!winPix.isNull())
        QApplication::setWindowIcon(QIcon(winPix));
}
