/** LICENSE ********************************************************************
 **
 ** smolbote: yet another qute browser
 ** Copyright (C) 2017  Xian Nox
 **
 ** This program is free software: you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 ** the Free Software Foundation, either version 3 of the License, or
 ** (at your option) any later version.
 **
 ** This program is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 **
 ** You should have received a copy of the GNU General Public License
 ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **
 ******************************************************************************/

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include "browser.h"
#include <QInputDialog>
#include <QWebEngineDownloadItem>
#include <QStatusBar>
#include "forms/aboutdialog.h"

MainWindow::MainWindow(QUrl defaultUrl, QWidget *parent) :
    QMainWindow(parent),
    blocklistManager(new BlockerManager(this)),
    ui(new Ui::MainWindow),
    navigationToolBar(new QToolBar(tr("Navigation"), this)),
    tabToolBar(new QToolBar(tr("Tab bar"), this)),
    tabBar(new WebViewTabBar(this)),
    urlLineEdit(new UrlLineEdit(navigationToolBar)),
    progressBar(new LoadingBar(this))
{
    // set up UI
    ui->setupUi(this);
    setDockOptions(dockOptions() | AllowTabbedDocks | ForceTabbedDocks);
    setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::North);
    setTabPosition(Qt::RightDockWidgetArea, QTabWidget::North);

    QMenuBar *menuBar = new QMenuBar(this);
    menuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);

    // Browser menu
    QMenu *browserMenu = new QMenu(qApp->applicationName(), menuBar);
    menuBar->addMenu(browserMenu);
    browserMenu->addAction(tr("New Window"), this, SLOT(handleNewWindow()), QKeySequence::fromString(sSettings->value("window.shortcuts.windowNew").toString()));
    browserMenu->addAction(tr("New Tab"), this, SLOT(addNewTab()), QKeySequence::fromString(sSettings->value("window.shortcuts.tabNew").toString()));
    browserMenu->addSeparator();
    browserMenu->addAction(tr("About"), this, SLOT(about()), QKeySequence(tr("F1")));
    browserMenu->addAction(tr("About Qt"), qApp, SLOT(aboutQt()));
    browserMenu->addAction(tr("Quit"), qApp, SLOT(quit()), QKeySequence::fromString(sSettings->value("window.shortcuts.windowClose").toString()));

    // Tools menu
    QMenu *toolsMenu = new QMenu(tr("Tools"), menuBar);
    menuBar->addMenu(toolsMenu);
    QAction *downloadsAction = toolsMenu->addAction(tr("Downloads"), Browser::instance()->downloads(), SLOT(show()));
    downloadsAction->setParent(this);
    downloadsAction->setShortcut(QKeySequence::fromString(sSettings->value("downloads.dialogShortcut").toString()));
    QAction *bookmarksAction = toolsMenu->addAction(tr("Bookmarks"), Browser::instance()->bookmarks(), SLOT(show()));
    bookmarksAction->setParent(this);
    bookmarksAction->setShortcut(QKeySequence(sSettings->value("bookmarks.dialogShortcut").toString()));
    toolsMenu->addSeparator();
    toolsMenu->addAction(tr("Blocker"), blocklistManager, SLOT(show()), QKeySequence::fromString(sSettings->value("blocker.shortcut").toString()));

    // Profile menu
    QMenu *profileMenu = new QMenu(tr("Profile"), menuBar);
    menuBar->addMenu(profileMenu);
    profileMenu->addAction(tr("View profile"), this, SLOT(execProfileEditor()));
    profileMenu->addAction(tr("Load profile"), this, SLOT(loadProfileGUI()));
    //profileMenu->addAction(tr("Settings"));
    profileMenu->addAction(tr("Cookies"), this, SLOT(cookiesAction()));

    // Add the toolbars
    // tabToolBar: main menu and tab list
    tabToolBar->setMovable(sSettings->value("window.ui.tabtoolbarMovable", true).toBool());
    tabToolBar->addWidget(menuBar);
    tabToolBar->addWidget(tabBar);
    this->addToolBar(Qt::TopToolBarArea, tabToolBar);
    this->addToolBarBreak(Qt::TopToolBarArea);

    // navigationToolBar: address bar
    navigationToolBar->setMovable(sSettings->value("window.ui.navtoolbarMovable", true).toBool());
    navigationToolBar->addWidget(urlLineEdit);
    this->addToolBar(Qt::TopToolBarArea, navigationToolBar);

    // connect signals
    connect(urlLineEdit, SIGNAL(returnPressed()), this, SLOT(handleUrlChanged()));
    connect(tabBar, SIGNAL(currentTabChanged(WebView*)), this, SLOT(handleTabChanged(WebView*)));

    // Load profile
    loadProfile(sSettings->value("browser.profile.default").toString());

    // loading bar
    ui->statusBar->addPermanentWidget(progressBar);

    // shortcuts
    QAction *focusAddressAction = new QAction(this);
    focusAddressAction->setShortcut(QKeySequence::fromString(sSettings->value("window.shortcuts.focusAddress").toString()));
    connect(focusAddressAction, SIGNAL(triggered(bool)), this, SLOT(focusAddress()));
    addAction(focusAddressAction);

    if(!defaultUrl.isEmpty()) {
        addNewTab(defaultUrl);
    } else {
        addNewTab(sSettings->value("general.homepage", QUrl("about:blank")).toUrl());
    }

    resize(sSettings->value("window.width", 800).toInt(), sSettings->value("window.height", 600).toInt());
    if(sSettings->value("window.maximized", false).toBool()) {
        showMaximized();
    }
}

MainWindow::MainWindow(const QStringList urlList, QWidget *parent) :
    MainWindow(QUrl(""), parent)
{
    for(QString url : urlList) {
        addNewTab(QUrl::fromUserInput(url));
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::addTabbedDock(Qt::DockWidgetArea area, QDockWidget *widget)
{
    QList<QDockWidget*> allDockWidgets = findChildren<QDockWidget*>();
    QVector<QDockWidget*> areaDockWidgets;
    for(QDockWidget *w : allDockWidgets) {
        if(dockWidgetArea(w) == area) {
            areaDockWidgets.append(w);
        }
    }

    if(areaDockWidgets.empty()) {
        // no other widgets
        addDockWidget(area, widget);
    } else {
        tabifyDockWidget(areaDockWidgets.last(), widget);
    }
}

void MainWindow::addNewTab(const QUrl &url)
{
    if(!url.isEmpty()) {
        tabBar->addTab(m_profile, url);
    } else {
        tabBar->addTab(m_profile, sSettings->value("general.newtab").toUrl());
    }
}

void MainWindow::focusAddress()
{
    urlLineEdit->setFocus();
    urlLineEdit->selectAll();
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if(tabBar->count() > 1) {
        int ret = QMessageBox::warning(this, tr("Close window?"), tr("Close multiple tabs?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
        if(ret == QMessageBox::No) {
            event->ignore();
            return;
        }
    }
    QMainWindow::closeEvent(event);
}

void MainWindow::about()
{
    AboutDialog *dlg = new AboutDialog(this);
    dlg->exec();
}

void MainWindow::loadProfile(const QString &name)
{
    if(m_profile) {
        m_profile->deleteLater();
    }

    if(name.isEmpty()) {
        //profileName = tr("Off the record");
        m_profile = new WebEngineProfile(this);
        qDebug("Creating off-the-record profile");
    } else {
        //profileName = name;
        m_profile = new WebEngineProfile(name, this);
        qDebug("Using profile: %s", qUtf8Printable(m_profile->storageName()));
    }

    UrlRequestInterceptor *interceptor = new UrlRequestInterceptor(this);
    interceptor->setSubscription(blocklistManager);
    m_profile->setRequestInterceptor(interceptor);
    connect(m_profile, SIGNAL(downloadRequested(QWebEngineDownloadItem*)), Browser::instance()->downloads(), SLOT(addDownload(QWebEngineDownloadItem*)));
}

void MainWindow::loadProfileGUI()
{
    bool ok;
    QString name = QInputDialog::getText(this, tr("Load Profile"), tr("Enter Profile name"), QLineEdit::Normal, QString(""), &ok);
    if(ok) {
        loadProfile(name);
        tabBar->setProfile(m_profile);
    }
}

void MainWindow::handleNewWindow(const QUrl &url)
{
    Browser::instance()->addWindow(new MainWindow(url));
}

void MainWindow::handleTabChanged(WebView *view)
{
    Q_ASSERT(view);

    // clear the parent of the central widget so it doesn't get deleted
    centralWidget()->setParent(0);

    // disconnect signals
    disconnect(centralWidget());

    // set new central widget
    setCentralWidget(view);

    // connect signals
    connect(view, SIGNAL(urlChanged(QUrl)), urlLineEdit, SLOT(setUrl(QUrl)));
    connect(view, SIGNAL(titleChanged(QString)), this, SLOT(handleTitleUpdated(QString)));
    connect(view, SIGNAL(linkHovered(QString)), ui->statusBar, SLOT(showMessage(QString)));

    progressBar->connectWebView(view);

    // update UI
    urlLineEdit->setUrl(view->url());
    this->handleTitleUpdated(view->title());
    centralWidget()->setFocus();
}

void MainWindow::handleUrlChanged()
{
    tabBar->currentView()->load(urlLineEdit->url());
}

void MainWindow::handleTitleUpdated(const QString &title)
{
    setWindowTitle(sSettings->value("window.title").toString().replace("title", title).replace("profile", m_profile->storageName()));
}

void MainWindow::execProfileEditor()
{
    ProfileDialog *dialog = new ProfileDialog(m_profile, this);
    dialog->exec();
}

void MainWindow::cookiesAction()
{
    m_profile->cookieUI()->show();
}