/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

import QtQuick 2.1
import QtWebEngine 1.2

import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.0
import QtQuick.Layouts 1.0
import QtQuick.Window 2.1
import QtQuick.Controls.Private 1.0
import Qt.labs.settings 1.0
import QtQuick.Dialogs 1.2

ApplicationWindow {
    id: browserWindow
    property QtObject applicationRoot
    property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item.webView : null
    property int previousVisibility: Window.Windowed

    property bool isFullScreen: visibility == Window.FullScreen
    onIsFullScreenChanged: {
        // This is for the case where the system forces us to leave fullscreen.
        if (currentWebView && !isFullScreen) {
            currentWebView.state = ""
            if (currentWebView.isFullScreen) {
                currentWebView.fullScreenCancelled()
                fullScreenNotification.hide()
            }
        }
    }

    height: 600
    width: 800
    visible: true
    title: currentWebView && currentWebView.title

    Settings {
        id : appSettings
        property alias autoLoadImages: loadImages.checked;
        property alias javaScriptEnabled: javaScriptEnabled.checked;
        property alias errorPageEnabled: errorPageEnabled.checked;
        property alias pluginsEnabled: pluginsEnabled.checked;
        property alias thirdPartyCookiesEnabled: thirdPartyCookiesEnabled.checked;
    }

    // Make sure the Qt.WindowFullscreenButtonHint is set on OS X.
    Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint

    // Create a styleItem to determine the platform.
    // When using style "mac", ToolButtons are not supposed to accept focus.
    StyleItem { id: styleItem }
    property bool platformIsMac: styleItem.style == "mac"

    Action {
        shortcut: "Ctrl+D"
        onTriggered: {
            downloadView.visible = !downloadView.visible
        }
    }

    Action {
        id: focus
        shortcut: "Ctrl+L"
        onTriggered: {
            addressBar.forceActiveFocus();
            addressBar.selectAll();
        }
    }
    Action {
        shortcut: "Ctrl+R"
        onTriggered: {
            if (currentWebView)
                currentWebView.reload()
        }
    }
    Action {
        shortcut: "Ctrl+T"
        onTriggered: {
            tabs.createEmptyTab(currentWebView.profile)
            tabs.currentIndex = tabs.count - 1
            addressBar.forceActiveFocus();
            addressBar.selectAll();
        }
    }
    Action {
        shortcut: "Ctrl+W"
        onTriggered: {
            if (tabs.count == 1)
                browserWindow.close()
            else
                tabs.removeTab(tabs.currentIndex)
        }
    }

    Action {
        shortcut: "Escape"
        onTriggered: {
            if (browserWindow.isFullScreen)
                browserWindow.visibility = browserWindow.previousVisibility
        }
    }
    Action {
        shortcut: "Ctrl+0"
        onTriggered: zoomController.reset()
    }
    Action {
        shortcut: "Ctrl+-"
        onTriggered: zoomController.zoomOut()
    }
    Action {
        shortcut: "Ctrl+="
        onTriggered: zoomController.zoomIn()
    }

    Menu {
        id: backHistoryMenu

        Instantiator {
            model: currentWebView && currentWebView.navigationHistory.backItems
            MenuItem {
                text: model.title
                onTriggered: currentWebView.goBackOrForward(model.offset)
            }

            onObjectAdded: backHistoryMenu.insertItem(index, object)
            onObjectRemoved: backHistoryMenu.removeItem(object)
        }
    }

    Menu {
        id: forwardHistoryMenu

        Instantiator {
            model: currentWebView && currentWebView.navigationHistory.forwardItems
            MenuItem {
                text: model.title
                onTriggered: currentWebView.goBackOrForward(model.offset)
            }

            onObjectAdded: forwardHistoryMenu.insertItem(index, object)
            onObjectRemoved: forwardHistoryMenu.removeItem(object)
        }
    }

    toolBar: ToolBar {
        id: navigationBar
            RowLayout {
                anchors.fill: parent;
                ButtonWithMenu {
                    id: backButton
                    iconSource: "icons/go-previous.png"
                    enabled: currentWebView && currentWebView.canGoBack
                    activeFocusOnTab: !browserWindow.platformIsMac
                    onClicked: currentWebView.goBack()
                    longPressMenu: backHistoryMenu
                }
                ButtonWithMenu {
                    id: forwardButton
                    iconSource: "icons/go-next.png"
                    enabled: currentWebView && currentWebView.canGoForward
                    activeFocusOnTab: !browserWindow.platformIsMac
                    onClicked: currentWebView.goForward()
                    longPressMenu: forwardHistoryMenu
                }
                ToolButton {
                    id: reloadButton
                    iconSource: currentWebView && currentWebView.loading ? "icons/process-stop.png" : "icons/view-refresh.png"
                    onClicked: currentWebView && currentWebView.loading ? currentWebView.stop() : currentWebView.reload()
                    activeFocusOnTab: !browserWindow.platformIsMac
                }
                TextField {
                    id: addressBar
                    Image {
                        anchors.verticalCenter: addressBar.verticalCenter;
                        x: 5
                        z: 2
                        id: faviconImage
                        width: 16; height: 16
                        source: currentWebView && currentWebView.icon
                    }
                    style: TextFieldStyle {
                        padding {
                            left: 26;
                        }
                    }
                    focus: true
                    Layout.fillWidth: true
                    text: currentWebView && currentWebView.url
                    onAccepted: currentWebView.url = utils.fromUserInput(text)
                }
                ToolButton {
                    id: settingsMenuButton
                    menu: Menu {
                        MenuItem {
                            id: loadImages
                            text: "Autoload images"
                            checkable: true
                            checked: true
                        }
                        MenuItem {
                            id: javaScriptEnabled
                            text: "JavaScript On"
                            checkable: true
                            checked: true
                        }
                        MenuItem {
                            id: errorPageEnabled
                            text: "ErrorPage On"
                            checkable: true
                            checked: true
                        }
                        MenuItem {
                            id: pluginsEnabled
                            text: "Plugins On"
                            checkable: true
                            checked: true
                        }
                        MenuItem {
                            id: thirdPartyCookiesEnabled
                            text: "Third party cookies enabled"
                            checkable: true
                            checked: true
                            onToggled: applicationRoot.thirdPartyCookiesEnabled = checked
                        }
                        MenuItem {
                            id: offTheRecordEnabled
                            text: "Off The Record"
                            checkable: true
                            checked: currentWebView.profile.offTheRecord
                            onToggled: currentWebView.profile = checked ? otrProfile : testProfile;
                        }
                        MenuItem {
                            id: httpDiskCacheEnabled
                            text: "HTTP Disk Cache"
                            checkable: !currentWebView.profile.offTheRecord
                            checked: (currentWebView.profile.httpCacheType == WebEngineProfile.DiskHttpCache)
                            onToggled: currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache;
                        }
                    }
                }
            }
            ProgressBar {
                id: progressBar
                height: 3
                anchors {
                    left: parent.left
                    top: parent.bottom
                    right: parent.right
                    leftMargin: -parent.leftMargin
                    rightMargin: -parent.rightMargin
                }
                style: ProgressBarStyle {
                    background: Item {}
                }
                z: -2;
                minimumValue: 0
                maximumValue: 100
                value: (currentWebView && currentWebView.loadProgress < 100) ? currentWebView.loadProgress : 0
            }
    }

    TabView {
        id: tabs
        function createEmptyTab(profile) {
            var tab = addTab("", tabComponent)
            // We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately.
            tab.active = true
            tab.title = Qt.binding(function() { return tab.item.title })
            tab.item.webView.profile = profile
            return tab
        }

        anchors.fill: parent
        Component.onCompleted: createEmptyTab(testProfile)

        Component {
            id: tabComponent
            Item {
                property alias webView: webEngineView
                property alias title: webEngineView.title
                Action {
                    shortcut: "Ctrl+F"
                    onTriggered: {
                        findBar.visible = !findBar.visible
                        if (findBar.visible) {
                            findTextField.forceActiveFocus()
                        }
                    }
                }
                FeaturePermissionBar {
                    id: permBar
                    view: webEngineView
                    anchors {
                        left: parent.left
                        right: parent.right
                        top: parent.top
                    }
                    z: 3
                }

                WebEngineView {
                    id: webEngineView

                    anchors {
                        fill: parent
                        top: permBar.bottom
                    }

                    focus: true

                    states: [
                        State {
                            name: "FullScreen"
                            PropertyChanges {
                                target: tabs
                                frameVisible: false
                                tabsVisible: false
                            }
                            PropertyChanges {
                                target: navigationBar
                                visible: false
                            }
                        }
                    ]
                    settings.autoLoadImages: appSettings.autoLoadImages
                    settings.javascriptEnabled: appSettings.javaScriptEnabled
                    settings.errorPageEnabled: appSettings.errorPageEnabled
                    settings.pluginsEnabled: appSettings.pluginsEnabled

                    onCertificateError: {
                        if (!acceptedCertificates.shouldAutoAccept(error)){
                            error.defer()
                            sslDialog.enqueue(error)
                        } else{
                            error.ignoreCertificateError()
                        }
                    }

                    onNewViewRequested: {
                        if (!request.userInitiated)
                            print("Warning: Blocked a popup window.")
                        else if (request.destination == WebEngineView.NewViewInTab) {
                            var tab = tabs.createEmptyTab(currentWebView.profile)
                            tabs.currentIndex = tabs.count - 1
                            request.openIn(tab.item.webView)
                        } else if (request.destination == WebEngineView.NewViewInBackgroundTab) {
                            var tab = tabs.createEmptyTab(currentWebView.profile)
                            request.openIn(tab.item.webView)
                        } else if (request.destination == WebEngineView.NewViewInDialog) {
                            var dialog = applicationRoot.createDialog(currentWebView.profile)
                            request.openIn(dialog.currentWebView)
                        } else {
                            var window = applicationRoot.createWindow(currentWebView.profile)
                            request.openIn(window.currentWebView)
                        }
                    }

                    onFullScreenRequested: {
                        if (request.toggleOn) {
                            webEngineView.state = "FullScreen"
                            browserWindow.previousVisibility = browserWindow.visibility
                            browserWindow.showFullScreen()
                            fullScreenNotification.show()
                        } else {
                            webEngineView.state = ""
                            browserWindow.visibility = browserWindow.previousVisibility
                            fullScreenNotification.hide()
                        }
                        request.accept()
                    }

                    onFeaturePermissionRequested: {
                        permBar.securityOrigin = securityOrigin;
                        permBar.requestedFeature = feature;
                        permBar.visible = true;
                    }
                }

                Rectangle {
                    id: findBar
                    anchors.top: webEngineView.top
                    anchors.right: webEngineView.right
                    width: 240
                    height: 35
                    border.color: "lightgray"
                    border.width: 1
                    radius: 5
                    visible: false
                    color: browserWindow.color

                    RowLayout {
                        anchors.centerIn: findBar
                        TextField {
                            id: findTextField
                            onAccepted: {
                                webEngineView.findText(text)
                            }
                        }
                        ToolButton {
                            id: findBackwardButton
                            iconSource: "icons/go-previous.png"
                            onClicked: webEngineView.findText(findTextField.text, WebEngineView.FindBackward)
                        }
                        ToolButton {
                            id: findForwardButton
                            iconSource: "icons/go-next.png"
                            onClicked: webEngineView.findText(findTextField.text)
                        }
                        ToolButton {
                            id: findCancelButton
                            iconSource: "icons/process-stop.png"
                            onClicked: findBar.visible = false
                        }
                    }
                }
            }
        }
    }

    QtObject{
        id:acceptedCertificates

        property var acceptedUrls : []

        function shouldAutoAccept(certificateError){
            var domain = utils.domainFromString(certificateError.url)
            return acceptedUrls.indexOf(domain) >= 0
        }
    }

    MessageDialog {
        id: sslDialog

        property var certErrors: []
        icon: StandardIcon.Warning
        standardButtons: StandardButton.No | StandardButton.Yes
        title: "Server's certificate not trusted"
        text: "Do you wish to continue?"
        detailedText: "If you wish so, you may continue with an unverified certificate. " +
                      "Accepting an unverified certificate means " +
                      "you may not be connected with the host you tried to connect to.\n" +
                      "Do you wish to override the security check and continue?"
        onYes: {
            var cert = certErrors.shift()
            var domain = utils.domainFromString(cert.url)
            acceptedCertificates.acceptedUrls.push(domain)
            cert.ignoreCertificateError()
            presentError()
        }
        onNo: reject()
        onRejected: reject()

        function reject(){
            certErrors.shift().rejectCertificate()
            presentError()
        }
        function enqueue(error){
            certErrors.push(error)
            presentError()
        }
        function presentError(){
            visible = certErrors.length > 0
        }
    }

    FullScreenNotification {
        id: fullScreenNotification
    }

    DownloadView {
        id: downloadView
        visible: false
        anchors.fill: parent
    }

    function onDownloadRequested(download) {
        downloadView.visible = true
        downloadView.append(download)
        download.accept()
    }

    MessageDialog {
        id: notificationDialog
        width: 200
        standardButtons: StandardButton.Ok
    }

    function onPresentNotification(notification) {
        notificationDialog.title = notification.title
        notificationDialog.text = notification.origin.toString() + '\n' + notification.message
        notificationDialog.open()
    }

    ZoomController {
      id: zoomController
      y: parent.mapFromItem(currentWebView, 0 , 0).y - 4
      anchors.right: parent.right
      width: (parent.width > 800) ? parent.width * 0.25 : 220
      anchors.rightMargin: (parent.width > 400) ? 100 : 0
    }
    Binding {
        target: currentWebView
        property: "zoomFactor"
        value: zoomController.zoomFactor
    }
}
