//
//  DrawerPlugin.swift
//  Astro
//
//  Created by Mark Sandstrom on 6/3/15.
//  Copyright (c) 2015 Mobify Research & Development Inc. All rights reserved.
//

import Foundation

public func ==(a: JASidePanelState, b: JASidePanelState) -> Bool {
    return a.rawValue == b.rawValue
}

class SidePanelController: JASidePanelController {

    @objc var frozenCenterPanel: UIView?
    @objc var hideStatusBar = false

    override func viewDidLoad() {
        super.viewDidLoad()

        // The shadow applied to the center panel by styleContainer:animate:duration: is
        // visible when the app launches because the centerPanelContainer is transparent.
        // See: https://s3.amazonaws.com/uploads.hipchat.com/15359/1252158/s3PouSAHlgDO8nG/Screen%20Shot%202015-06-08%20at%202.08.33%20PM.png
        // Set the background color to white so that there isn't a jarring flash of gray.
        self.centerPanelContainer.backgroundColor = UIColor.white
    }

    override func stylePanel(_ panel: UIView!) {
        // JASidePanelController adds rounded corners, which look bad, and there is no
        // way to control this behaviour via the public interface, so we override this
        // function to prevent the styling.
    }

    override func centerPanelAnchorStatusWillChange(_ willAnchor: Bool) {
        self.setStatusBarVisibility(visible: willAnchor)

        if willAnchor {
            // Cross fade the frozenCenterPanel with the current web view content. This
            // also prevents a status bar flicker when, in some (unpredictable) cases,
            // the status bar is not displayed until after the frozenCenterPanel is
            // removed.
            UIView.animate(
                withDuration: 0.2,
                animations: {
                    if let frozenCenterPanel = self.frozenCenterPanel {
                        frozenCenterPanel.layer.opacity = 0.0
                    }
                },
                completion: { _ in
                    self.frozenCenterPanel?.removeFromSuperview()
                    self.frozenCenterPanel = nil
                }
            )
        } else {
            frozenCenterPanel = UIView(frame: CGRect(x: 0, y: 0, width: centerPanel.view.frame.size.width, height: centerPanel.view.frame.size.height))
            frozenCenterPanel!.autoresizingMask = UIView.AutoresizingMask.flexibleWidth
            let snapshotView = UIScreen.main.snapshotView(afterScreenUpdates: false)
            frozenCenterPanel!.addSubview(snapshotView)
            frozenCenterPanel!.clipsToBounds = true

            centerPanel.view.addSubview(frozenCenterPanel!)
        }
    }

    @objc func setStatusBarVisibility(visible: Bool) {
        hideStatusBar = !visible
        self.setNeedsStatusBarAppearanceUpdate()
    }

    override var prefersStatusBarHidden: Bool {
        return hideStatusBar
    }
}

class DrawerPlugin: Plugin, ViewPlugin, LocaleChangedListener {
    @objc var viewController: UIViewController {
        return typedViewController
    }
    @objc var typedViewController = SidePanelController()

    @objc var isLeftToRight: Bool

    required init(address: MessageAddress, messageBus: MessageBus, pluginResolver: PluginResolver, options: JSONObject?) {
        isLeftToRight = Localization.isLeftToRight

        super.init(address: address, messageBus: messageBus, pluginResolver: pluginResolver, options: options)

        Localization.addLocaleChangedListener(self)

        // Resize the left and right panel views to be the width of the panels when open
        typedViewController.shouldResizeLeftPanel = true
        typedViewController.shouldResizeRightPanel = true

        // See JASidePanelController.h for a description of these flags
        typedViewController.bounceOnSidePanelOpen = false
        typedViewController.bounceOnCenterPanelChange = false
        typedViewController.allowLeftOverpan = false
        typedViewController.allowRightOverpan = false

        self.addRpcMethodShim("setContentView") { params, respond in
            ////////// This will be autogenerated at some point //////////
            if let address: MessageAddress = MethodShimUtils.getArg(params, key: "address", respond: respond) {
                self.setContentView(address, respond: respond)
            }
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("setLeftMenu") { params, respond in
            ////////// This will be autogenerated at some point //////////
            if let address: MessageAddress = MethodShimUtils.getArg(params, key: "address", respond: respond) {
                self.setLeftMenu(address, respond: respond)
            }
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("setRightMenu") { params, respond in
            ////////// This will be autogenerated at some point //////////
            if let address: MessageAddress = MethodShimUtils.getArg(params, key: "address", respond: respond) {
                self.setRightMenu(address, respond: respond)
            }
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("showLeftMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.showLeftMenu(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("showRightMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.showRightMenu(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("hideLeftMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.hideLeftMenu(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("hideRightMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.hideRightMenu(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("toggleLeftMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.toggleLeftMenu(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("toggleRightMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.toggleRightMenu(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("lockLeftMenuClosed") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.lockLeftMenuClosed(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("lockRightMenuClosed") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.lockRightMenuClosed(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("unlockLeftMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.unlockLeftMenu(respond)
            /////////////////////////////////////////////////////////////
        }

        self.addRpcMethodShim("unlockRightMenu") { _, respond in
            ////////// This will be autogenerated at some point //////////
            self.unlockRightMenu(respond)
            /////////////////////////////////////////////////////////////
        }
    }

    private func hideKeyboard() {
        viewController.view.endEditing(true)
    }

    private func toggleLeftMenu(open: Bool? = nil) {
        if Localization.isLeftToRight {
            toggleLeftMenuLocalized(open: open)
        } else {
            toggleRightMenuLocalized(open: open)
        }
    }

    private func toggleLeftMenuLocalized(open: Bool? = nil) {
        hideKeyboard()

        if open == true {
            typedViewController.showLeftPanel(animated: true)
        } else if open == false {
            typedViewController.showCenterPanel(animated: true)
        } else {
            let isMenuOpen = typedViewController.state == JASidePanelLeftVisible
            toggleLeftMenuLocalized(open: !isMenuOpen)
        }
    }

    private func toggleRightMenu(open: Bool? = nil) {
        if Localization.isLeftToRight {
            toggleRightMenuLocalized(open: open)
        } else {
            toggleLeftMenuLocalized(open: open)
        }
    }

    private func toggleRightMenuLocalized(open: Bool? = nil) {
        hideKeyboard()

        if open == true {
            typedViewController.showRightPanel(animated: true)
        } else if open == false {
            typedViewController.showCenterPanel(animated: true)
        } else {
            let isMenuOpen = typedViewController.state == JASidePanelRightVisible
            toggleRightMenuLocalized(open: !isMenuOpen)
        }
    }

    // @RpcMethod
    func setContentView(_ address: MessageAddress, respond: RPCMethodCallback) {
        if let plugin: ViewPlugin = pluginResolver.pluginInstanceByAddress(address, respond: respond) {
            typedViewController.centerPanel = plugin.viewController
        }
    }

    // @RpcMethod
    func setLeftMenu(_ address: MessageAddress, respond: RPCMethodCallback) {
        if let plugin: ViewPlugin = pluginResolver.pluginInstanceByAddress(address, respond: respond) {
            if Localization.isLeftToRight {
                typedViewController.leftPanel = plugin.viewController
            } else {
                typedViewController.rightPanel = plugin.viewController
            }
        }
    }

    // @RpcMethod
    func setRightMenu(_ address: MessageAddress, respond: RPCMethodCallback) {
        if let plugin: ViewPlugin = pluginResolver.pluginInstanceByAddress(address, respond: respond) {
            if Localization.isLeftToRight {
                typedViewController.rightPanel = plugin.viewController
            } else {
                typedViewController.leftPanel = plugin.viewController
            }
        }
    }

    // @RpcMethod
    func showLeftMenu(_ respond: RPCMethodCallback) {
        toggleLeftMenu(open: true)
    }

    // @RpcMethod
    func showRightMenu(_ respond: RPCMethodCallback) {
        toggleRightMenu(open: true)
    }

    // @RpcMethod
    func hideLeftMenu(_ respond: RPCMethodCallback) {
        toggleLeftMenu(open: false)
    }

    // @RpcMethod
    func hideRightMenu(_ respond: RPCMethodCallback) {
        toggleRightMenu(open: false)
    }

    // @RpcMethod
    func toggleLeftMenu(_ respond: RPCMethodCallback) {
        toggleLeftMenu()
    }

    // @RpcMethod
    func toggleRightMenu(_ respond: RPCMethodCallback) {
        toggleRightMenu()
    }

    // @RpcMethod
    func lockLeftMenuClosed(_ respond: RPCMethodCallback) {
        typedViewController.allowLeftSwipe = false
        toggleLeftMenu(open: false)
    }

    // @RpcMethod
    func lockRightMenuClosed(_ respond: RPCMethodCallback) {
        typedViewController.allowRightSwipe = false
        toggleRightMenu(open: false)
    }

    // @RpcMethod
    func unlockLeftMenu(_ respond: RPCMethodCallback) {
        typedViewController.allowLeftSwipe = true
    }

    // @RpcMethod
    func unlockRightMenu(_ respond: RPCMethodCallback) {
        typedViewController.allowRightSwipe = true
    }

    // Localization
    func localeDidChange(newLocale: Locale) {
        // If the direction changed, swap left and right panes
        if isLeftToRight != Localization.isLeftToRight {
            let leftViewController = typedViewController.leftPanel
            typedViewController.leftPanel = typedViewController.rightPanel
            typedViewController.rightPanel = leftViewController
        }

        isLeftToRight = Localization.isLeftToRight
    }
}
