/*******************************************************************************
 **
 ** 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 "widgets/mainwindowmenubar.h"
#include <QMessageBox>
#include "browser.h"
#include <QWebEngineDownloadItem>
#include <QStatusBar>
#include "forms/aboutdialog.h"

#include <QToolButton>
#include <QStyle>

MainWindow::MainWindow(QUrl defaultUrl, QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    navigationToolBar(new QToolBar(tr("Navigation"), this)),
    tabToolBar(new QToolBar(tr("Tab bar"), this)),
    tabBar(new WebViewTabBar(nullptr, this)),
    urlLineEdit(new UrlLineEdit(navigationToolBar)),
    m_progressBar(new LoadingBar(this))
{
    // set up UI
    ui->setupUi(this);
    QAction *fullscreenAction = new QAction(this);
    fullscreenAction->setShortcut(QKeySequence::fromString(sSettings->value("window.shortcuts.fullscreen").toString()));
    connect(fullscreenAction, SIGNAL(triggered(bool)), this, SLOT(toggleFullscreen()));
    addAction(fullscreenAction);

    // Dockable widget styling
    setDockOptions(dockOptions() | AllowTabbedDocks | ForceTabbedDocks);
    setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::North);
    setTabPosition(Qt::RightDockWidgetArea, QTabWidget::North);

    // Main menu
    MainWindowMenuBar *menuBar = new MainWindowMenuBar(this);
    menuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);

    // Add the toolbars
    // tabToolBar: main menu and tab list
    tabToolBar->setMovable(sSettings->value("window.ui.tabtoolbarMovable").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").toBool());

    // page actions
    QToolButton *backButton = new QToolButton(this);
    backButton->setIcon(style()->standardIcon(QStyle::SP_ArrowBack));
    connect(backButton, SIGNAL(clicked()), tabBar->signalMapper(), SLOT(map()));
    tabBar->signalMapper()->setMapping(backButton, WebViewTabBar::Back);
    QToolButton *forwardButton = new QToolButton(this);
    forwardButton->setIcon(style()->standardIcon(QStyle::SP_ArrowForward));
    connect(forwardButton, SIGNAL(clicked()), tabBar->signalMapper(), SLOT(map()));
    tabBar->signalMapper()->setMapping(forwardButton, WebViewTabBar::Forward);
    QToolButton *reloadButton = new QToolButton(this);
    reloadButton->setIcon(style()->standardIcon(QStyle::SP_BrowserReload));
    connect(reloadButton, SIGNAL(clicked()), tabBar->signalMapper(), SLOT(map()));
    tabBar->signalMapper()->setMapping(reloadButton, WebViewTabBar::Reload);
    QToolButton *homepageButton = new QToolButton(this);
    homepageButton->setIcon(style()->standardIcon(QStyle::SP_DirHomeIcon));
    connect(homepageButton, SIGNAL(clicked()), tabBar->signalMapper(), SLOT(map()));
    tabBar->signalMapper()->setMapping(homepageButton, WebViewTabBar::Homepage);
    navigationToolBar->addWidget(backButton);
    navigationToolBar->addWidget(forwardButton);
    navigationToolBar->addWidget(reloadButton);
    navigationToolBar->addWidget(homepageButton);
    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
    tabBar->setProfile(qApp->profile(sSettings->value("browser.profile.default").toString()));

    // loading bar
    ui->statusBar->addPermanentWidget(m_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()) {
        newTab(defaultUrl);
    } else {
        newTab(tabBar->profile()->homepage());
    }

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

MainWindow::MainWindow(const QStringList urlList, QWidget *parent) :
    MainWindow(QUrl(""), parent)
{
    QStringList::const_iterator i;
    for(i = urlList.constBegin(); i != urlList.constEnd(); ++i) {
        newTab(QUrl::fromUserInput(*i));
    }
}

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::newTab(const QUrl &url)
{
    if(!url.isEmpty()) {
        tabBar->addTab(url);
    } else {
        tabBar->addTab(tabBar->profile()->newtab());
    }
}

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::setProfile(WebEngineProfile *profile)
{
    Q_ASSERT(profile != nullptr);
    tabBar->setProfile(profile);
}

void MainWindow::toggleFullscreen()
{
    if(isFullScreen()) {
        setWindowState(Qt::WindowMaximized | Qt::WindowActive);
    } else {
        setWindowState(Qt::WindowFullScreen | Qt::WindowActive);
    }
}

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

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

    // centralWidget can be a nullptr
    if(centralWidget()) {
        // 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)));

    m_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", tabBar->profile()->name()));
}