/*
 *    Project Name    : Visual Python
 *    Description     : GUI-based Python code generator
 *    File Name       : loadVisualpython.js
 *    Author          : Black Logic
 *    Note            : Load Visual Python
 *    License         : GPLv3 (GNU General Public License v3.0)
 *    Date            : 2021. 08. 14
 *    Change Date     :
 */

//============================================================================
// Load Visual Python
//============================================================================
(
    require.specified('base/js/namespace')
        ? define
        : function (deps, callback) {
            'use strict';
            // if here, the Jupyter namespace hasn't been specified to be loaded.
            // This means that we're probably embedded in a page,
            // so we need to make our definition with a specific module name
            return define('vp_base/js/loadVisualpython', deps, callback);
        }
)([
    'css!vp_base/css/root.css',
    'vp_base/js/com/com_Const',
    'vp_base/js/com/com_util',
    'vp_base/js/com/com_Config',
    'vp_base/js/com/com_Log',
    'vp_base/js/com/com_Kernel',
    'vp_base/js/com/com_interface',
    'vp_base/js/MainFrame'
], function (rootCss, com_Const, com_util, com_Config, com_Log, com_Kernel, com_interface, MainFrame) {
    'use strict';

    //========================================================================
    // Define variable
    //========================================================================
    var Jupyter;
    var events;
    var liveNotebook = false;

    var metadataSettings;
    var vpPosition;
    var vpFrame;
    
    //========================================================================
    // Require: Jupyter & events
    //========================================================================
    try {
        // namespace's specified checking. events exception can occur
        // this will work in a live notebook because nbextensions & custom.js are loaded
        // by/after notebook.js, which requires base/js/namespace
        Jupyter = require('base/js/namespace');
        events = require('base/js/events');
        liveNotebook = true;
    } catch (err) {
        // We *are* theoretically in a non-live notebook
        console.log('[vp] working in non-live notebook'); //, err);
        // in non-live notebook, there's no event structure, so we make our own
        if (window.events === undefined) {
            var Events = function () { };
            window.events = $([new Events()]);
        }
        events = window.events;
    }

    //========================================================================
    // Internal call function
    //========================================================================

    /**
     * Add toolbar button
     */
    var _addToolBarVpButton = function () {
        // Call notebookApp initialize event, if toolbar is not yet ready
        if (!Jupyter.toolbar) {
            events.on('app_initialized.NotebookApp', function (evt) {
                _addToolBarVpButton();
            });
            return;
        }
        
        // Add toolbar button, if it's not existing
        if ($('#' + com_Const.TOOLBAR_BTN_INFO.ID).length === 0) {
            $(Jupyter.toolbar.add_buttons_group([
                Jupyter.keyboard_manager.actions.register({
                    'help': com_Const.TOOLBAR_BTN_INFO.HELP
                    , 'icon': com_Const.TOOLBAR_BTN_INFO.ICON
                    , 'handler': function () {
                        // on clicking extension button
                        vpFrame.toggleVp();
                    }
                }, com_Const.TOOLBAR_BTN_INFO.NAME, com_Const.TOOLBAR_BTN_INFO.PREFIX)
            ])).find('.btn').attr('id', com_Const.TOOLBAR_BTN_INFO.ID).addClass(com_Const.TOOLBAR_BTN_INFO.ICON_CONTAINER);
        }
    };

    /**
     * Create vp
     * @param {Object} cfg configuration
     * @param {*} st 
     */
    var _loadVpResource = function (cfg, st) {
        if (!liveNotebook)
            cfg = $.extend(true, {}, vpConfig.defaultConfig, cfg);

        vpFrame = new MainFrame();
        vpFrame.loadMainFrame();

        // TODO: hotkey control -> Implement under InputComponent or Event class
        // input:text - hotkey control
        $(document).on('focus', com_util.wrapSelector('input'), function() {
            com_interface.disableOtherShortcut();
        });
        $(document).on('blur', com_util.wrapSelector('input'), function() {
            com_interface.enableOtherShortcut();
        });
        $(document).on('focus', '.vp-popup-frame input', function() {
            com_interface.disableOtherShortcut();
        });
        $(document).on('blur', '.vp-popup-frame input', function() {
            com_interface.enableOtherShortcut();
        });
        $(document).on('focus', '#vp_fileNavigation input', function() {
            com_interface.disableOtherShortcut();
        });
        $(document).on('blur', '#vp_fileNavigation input', function() {
            com_interface.enableOtherShortcut();
        });
        $(document).on('focus', '.vp-dataselector input', function() {
            com_interface.disableOtherShortcut();
        });
        $(document).on('blur', '.vp-dataselector input', function() {
            com_interface.enableOtherShortcut();
        });
        // textarea - hotkey control
        $(document).on('focus', com_util.wrapSelector('.vp-popup-frame textarea'), function() {
            com_interface.disableOtherShortcut();
        });
        $(document).on('blur', com_util.wrapSelector('.vp-popup-frame textarea'), function() {
            com_interface.enableOtherShortcut();
        });
    };

    var _setGlobalVariables = function() {
        /**
         * visualpython log util
         * - use it instead of console.log
         * ex) vpLog.display(VP_LOG_TYPE.LOG, 'log text');
         */
        window.vpLog = new com_Log();
        /**
         * visualpython log util types
         * DEVELOP, LOG, ERROR
         */
        window.VP_LOG_TYPE = com_Log.LOG_TYPE;
        /**
         * visualpython config util
         */
        window.vpConfig = new com_Config();
        window.VP_MODE_TYPE = com_Config.MODE_TYPE;
        /**
         * visualpython kernel
         */
        window.vpKernel = new com_Kernel();
    }

    var _checkVersion = function() {
        // check version timestamp
        let nowDate = new Date();
        vpConfig.getData('version_timestamp', 'vpcfg').then(function(data) {
            let doCheckVersion = false;
            if (data == undefined) {
                // no timestamp, check version
                doCheckVersion = true;
            } else if (data != '') {
                let lastCheck = new Date(parseInt(data));
                let diffCheck_now = new Date(nowDate.getFullYear(), nowDate.getMonth() + 1, nowDate.getDate());
                let diffCheck_last = new Date(lastCheck.getFullYear(), lastCheck.getMonth() + 1, lastCheck.getDate());

                let diff = Math.abs(diffCheck_now.getTime() - diffCheck_last.getTime());
                diff = Math.ceil(diff / (1000 * 3600 * 24));

                if (diff >= 1) {
                    // if More than 1 day passed, check version
                    doCheckVersion = true;
                }
            }

            // check version and update version_timestamp
            if (doCheckVersion == true) {
                vpConfig.checkVpVersion(true);
            }

        }).catch(function(err) {
            vpLog.display(VP_LOG_TYPE.ERROR, err);
        })
    }

    //========================================================================
    // External call function
    //========================================================================
    /**
     * Read our config from server config & notebook metadata
     * This function should only be called when both:
     * 1. the notebook (and its metadata) has fully loaded
     *  AND
     * 2. Jupyter.notebook.config.loaded has resolved
     */
    var readConfig = function () {
        var cfg = vpConfig.defaultConfig;

        if (!liveNotebook) {
            return cfg;
        }

        // config may be specified at system level or at document level. first, update
        // defaults with config loaded from server
        let defaultMetadata = JSON.parse(JSON.stringify(vpConfig.metadataSettings));
        let metadata = vpConfig.getMetadata();
        
        vpConfig.resetMetadata();

        if (metadata && defaultMetadata.vp_config_version == metadata.vp_config_version) {
            Object.keys(defaultMetadata).forEach(key => {
                let value = (metadata && metadata.hasOwnProperty(key) ? metadata : defaultMetadata)[key];
                vpConfig.setMetadata({ [key]: value });
                cfg[key] = value;
            });
        } else {
            // if config version is different, overwrite config
            vpConfig.setMetadata(defaultMetadata);
        }
        
        return cfg;
    };

    /**
     * Initialize Visual Python
     */
    var initVisualpython = function () {
        _setGlobalVariables();

        let cfg = readConfig();

        vpConfig.readKernelFunction();
        _addToolBarVpButton();
        _loadVpResource(cfg);
        _checkVersion();

        if (cfg.vp_section_display && vpFrame) {
            vpFrame.openVp();
        }

        // Operations on kernel restart
        events.on('kernel_ready.Kernel', function (evt, info) {
            vpLog.display(VP_LOG_TYPE.LOG, 'vp operations for kernel ready...');
            // read vp functions
            vpConfig.readKernelFunction();
        });
    }

    return { initVisualpython: initVisualpython, readConfig: readConfig };

}); /* function, define */

/* End of file */
