import { Http } from "@intelligentgraphics/ig.utilities";
import { Connector } from "./Connector";
import { EPageToHostCmd } from "./EPageToHostCmd";
import BaseLogger from "./Logger";
const AppLogger = BaseLogger.createSubLogger("App");
/**
 * Base class for all Pages.
 * A page in this context is a functionally complete step in an
 * interactive planning process AKA wizard step.
 * It should be created when a corresponend HTML page is loaded and it
 * needs an instance of IConnector as parameter.
 */
export class Page {
    /**
     * Constructor. Don't put your application's code in the constructor
     * of you derived Page class, as vital functions like HostInfo() are
     * not available here. Instead, override the protected function
     * initialize() and put your code there.
     */
    constructor() {
        this._connector = new Connector((hostInfo) => {
            this._hostInfo = hostInfo;
            if (!hostInfo.Debug) {
                console.log = () => { };
                console.info = () => { };
                console.debug = () => { };
            }
            this.initialize();
        });
    }
    /**
     * Override this method in your application's derived page class, doing
     * the stuff needed to be done first upon loading the page.
     */
    initialize() {
        //
    }
    /**
     * Returns the initialized Connector object.
     */
    get Connector() {
        return this._connector;
    }
    /**
     * Returns the OnBeforePageChange callback.
     */
    get OnBeforePageChange() {
        return this._onBeforePageChange;
    }
    /**
     * Sets the OnBeforePageChange callback.
     * @param param Callback method to be called when the
     *        OnBeforePageChange function finishes. Return false when the
     *        page is not allowed to change.
     */
    set OnBeforePageChange(param) {
        this._onBeforePageChange = param;
    }
    getHostParameters(callback) {
        const tConnHP = this._connector.getHostParameters();
        if (tConnHP == undefined) {
            throw new Error(Connector.NoHostException);
        }
        else {
            if (tConnHP["ready"] === true) {
                if (callback) {
                    callback(tConnHP["config"]);
                }
            }
            else {
                window.setTimeout(() => {
                    this.getHostParameters(callback);
                }, 20);
            }
        }
    }
    /**
     * Executes log() with the scope IGD_log.ELogScope.App
     * @param level Severity of the message
     * @param message The log message(s).
     */
    appLog(level, ...message) {
        AppLogger.log(level, "", ...message);
    }
    /**
     * Tells the Host the module wants to be finished and the data should be submitted.
     */
    submit() {
        this._connector.sendToHost(EPageToHostCmd.FinishModuleSubmitData, undefined, undefined);
    }
    /**
     * Tells the Host the module wants to be finished without submission of data.
     */
    cancel() {
        this._connector.sendToHost(EPageToHostCmd.CancelModule, undefined, undefined);
    }
    /**
     * Tells the Host to store the state of the current page.
     * @param state Any variable. Most certainly an object.
     * @param callback Callback function with boolean parameter, which is true when the command succeeded.
     */
    storePageState(state, callback) {
        this._connector.sendToHost(EPageToHostCmd.StorePageState, state, callback);
    }
    /**
     * Tells the Host to send back a previously stored state of the current page.
     * @param callback Callback function with the returned data as parameter.
     */
    restorePageState(callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestPageState, undefined, callback);
    }
    /**
     * Tells the Host to store the state of the whole dialog (accessible on any page).
     * @param state Any variable. Most certainly an object.
     * @param callback Callback function with boolean parameter, which is true when the command succeeded.
     */
    storeSessionState(state, callback) {
        this._connector.sendToHost(EPageToHostCmd.StoreSessionState, state, callback);
    }
    /**
     * Tells the Host to add the given state to the storage of the whole dialog (accessible on any page).
     * @param state Any variable. Most certainly an object.
     * @param callback Callback function with boolean parameter, which is true when the command succeeded.
     */
    addSessionState(state, callback) {
        this._connector.sendToHost(EPageToHostCmd.AddSessionState, state, callback);
    }
    /**
     * Tells the Host to send back a previously stored state of the whole dialog.
     * @param callback Callback function with the returned data as parameter.
     */
    restoreSessionState(callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestSessionState, undefined, callback);
    }
    /**
     * Tells the Host to store an object session-independend.
     * @param state A stringify-able object.
     * @param callback Callback function with boolean parameter, which is true when the command succeeded.
     */
    storeClientState(state, callback) {
        this._connector.sendToHost(EPageToHostCmd.StoreClientState, state, callback);
    }
    /**
     * Tells the Host to add the given state to the session-independend storage.
     * @param state A stringify-able object.
     * @param callback Callback function with boolean parameter, which is true when the command succeeded.
     */
    addClientState(state, callback) {
        this._connector.sendToHost(EPageToHostCmd.AddClientState, state, callback);
    }
    /**
     * Tells the Host to send back a previously stored state of the session-independend client.
     * @param callback Callback function with the returned data as parameter.
     */
    restoreClientState(callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestClientState, undefined, callback);
    }
    /**
     * Tells the Host the page to load, when the user clicks on the
     * "next" button. Submit an empty url to disable the "next" button.
     * @param path relative path to the next page.
     * @param callback Callback function with boolean parameter, which is
     *                 true when the "next"-button is enabled as
     *                 consequence of the call.
     */
    setNextPage(path, callback) {
        this._connector.sendToHost(EPageToHostCmd.NextPageUrl, path, callback);
    }
    jumpToPage(param, callback) {
        const tThis = this;
        if (this.OnBeforePageChange) {
            this.OnBeforePageChange(function (ok2change) {
                if (ok2change) {
                    tThis._connector.sendToHost(EPageToHostCmd.LoadPageUrl, param, callback);
                }
                else {
                    if (callback) {
                        callback(false);
                    }
                }
            });
        }
        else {
            this._connector.sendToHost(EPageToHostCmd.LoadPageUrl, param, callback);
        }
    }
    /**
     * Tells the Host to set a progress percentage. 100 means the Module can
     * be completed. This must be taken into account by the host.
     * @param newProgress progress percentage from 0 to 100.
     * @param callback Callback function with number parameter, which
     *                 contains the progress set by the Host (maybe the
     *                 value had to be corrected)
     */
    setProgress(newProgress, callback) {
        this._connector.sendToHost(EPageToHostCmd.SetProgress, newProgress, callback);
    }
    /**
     * Tells the Host to return the current progress percentage.
     * @param callback Callback function with number parameter, which
     *                 contains the progress.
     */
    getProgress(callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestProgress, undefined, callback);
    }
    /**
     * Returns the current page url.
     * @param callback Callback function with string parameter.
     */
    getCurrentPageUrl(callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestCurrentPageUrl, undefined, callback);
    }
    /**
     * Get the localized resources for this page.
     * @param callback Callback function with the returned data or null, as parameter.
     */
    getTextResources(callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestTextResources, undefined, callback);
    }
    getJsonFile(file, finishCallback, progressCallback) {
        if (typeof file === "string") {
            // request just 1 JSON
            this._connector.sendToHost(EPageToHostCmd.RequestJsonFile, file, f => {
                if (progressCallback) {
                    progressCallback(0);
                }
                finishCallback(f);
            });
        }
        else {
            // request multiple JSONs simultaneously
            let tCompletedCallbacks = 0;
            const tCallbackParams = new Array();
            const tValueList = file;
            const tThis = this;
            if (tValueList.length === 0) {
                if (progressCallback) {
                    progressCallback(0);
                }
                finishCallback.apply(tThis);
            }
            else {
                for (let tI = 0; tI < tValueList.length; tI++) {
                    tCallbackParams.push(undefined);
                }
                tValueList.forEach((val, idx, arr) => {
                    tThis._connector.sendToHost(EPageToHostCmd.RequestJsonFile, val, f => {
                        tCallbackParams[idx] = f;
                        tCompletedCallbacks++;
                        if (progressCallback) {
                            progressCallback(arr.length - tCompletedCallbacks);
                        }
                        if (tCompletedCallbacks === arr.length) {
                            finishCallback.apply(tThis, tCallbackParams);
                        }
                    });
                });
            }
        }
    }
    /**
     * Get the content of a localized JSON file.
     * @param file Path to file, relative to the Module root. Without language dependant parts. E.g. test.json
     * @param callback Callback function with the returned data or null, as parameter.
     */
    getJsonFileLocalized(file, callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestJsonFileLocalized, file, callback);
    }
    /**
     * Get an image file.
     * @param file Path to image file, relative to the Module root.
     * @param callback Callback function with the returned data or null, as parameter.
     */
    getImageFile(file, callback) {
        this._connector.sendToHost(EPageToHostCmd.RequestImageFile, file, callback);
    }
    getTextFile(file, finishCallback, progressCallback) {
        if (typeof file === "string") {
            // request just 1 file
            this._connector.sendToHost(EPageToHostCmd.RequestTextFile, file, f => {
                if (progressCallback) {
                    progressCallback(0);
                }
                finishCallback(f);
            });
        }
        else {
            // request multiple text files simultaneously
            let tCompletedCallbacks = 0;
            const tCallbackParams = new Array();
            const tValueList = file;
            const tThis = this;
            if (tValueList.length === 0) {
                if (progressCallback) {
                    progressCallback(0);
                }
                finishCallback.apply(tThis);
            }
            else {
                for (let tI = 0; tI < tValueList.length; tI++) {
                    tCallbackParams.push(undefined);
                }
                tValueList.forEach((val, idx, arr) => {
                    tThis._connector.sendToHost(EPageToHostCmd.RequestTextFile, val, f => {
                        tCallbackParams[idx] = f;
                        tCompletedCallbacks++;
                        if (progressCallback) {
                            progressCallback(arr.length - tCompletedCallbacks);
                        }
                        if (tCompletedCallbacks === arr.length) {
                            finishCallback.apply(tThis, tCallbackParams);
                        }
                    });
                });
            }
        }
    }
    /**
     * Requests the Host to validate the passed user credentials.
     * @param state Should contain string objects 'login' and 'password'.
     * @param callback Callback function with boolean parameter, which is true when the credentials are valid.
     */
    validateUserCredentials(state, callback) {
        this._connector.sendToHost(EPageToHostCmd.ValidateUserCredentials, state, callback);
    }
    /**
     * Shows a message box to the user.
     * @param text Message to be shown,
     * @param type Dialog type
     * @param callback Callback function with the dialog result as parameter.
     */
    showMessageBox(text, type, callback) {
        this._connector.sendToHost(EPageToHostCmd.ShowMessageBox, { text: text, type: type }, callback);
    }
    /**
     * The host should save the given state in some way. How exactly is
     * unspecified here.
     * @param state The object to be saved. If this parameter is undefined,
     * the current sessionstate will be saved.
     * @param callback Callback function with boolean parameter, which is true
     * when the host saved the state successfully.
     */
    saveModuleState(state, callback) {
        this._connector.sendToHost(EPageToHostCmd.SaveModuleState, state, callback);
    }
    /**
     * The host should load a formerly saved state in some way. How exactly is
     * unspecified here.
     * @param callback Callback function. On unsuccessful load, the callback
     * parameter will be false, otherwise the loaded object.
     */
    loadModuleState(callback) {
        this._connector.sendToHost(EPageToHostCmd.LoadModuleState, undefined, callback);
    }
    /**
     * Tells the Host to initiate outside import
     */
    initiateImportFromUniversal() {
        this._connector.sendToHost(EPageToHostCmd.InitiateImportFromJSBU, undefined, undefined);
    }
    /**
     * Tells the Host to initiate outside load
     */
    initiateLoadFromUniversal() {
        this._connector.sendToHost(EPageToHostCmd.InitiateLoadFromJSBU, undefined, undefined);
    }
    /**
     * Tells the Host to initiate outside save or export
     */
    initiateSaveToUniversal() {
        this._connector.sendToHost(EPageToHostCmd.InitiateSaveToJSBU, undefined, undefined);
    }
    /**
     * Tells the Host to initiate outside save or export
     */
    showSaveDialog(params, cb) {
        this._connector.sendToHost(EPageToHostCmd.ShowSaveDialog, params, cb);
    }
    /**
     * Change host properties like CurrentLocale. Support for this must be implemented in the host.
     * @param params Parameters to be changed.
     * @param cb Function to be called when command has finished.
     */
    setHostProperties(params, cb) {
        this._connector.sendToHost(EPageToHostCmd.SetHostProperties, params, cb);
    }
    static createPage(pageClassName) {
        if (Page.Page) {
            return Page.Page;
        }
        if (pageClassName) {
            const pcA = pageClassName.split(".");
            pcA.reverse();
            let instance = Object.create(window[pcA.pop()]);
            while (pcA.length > 0) {
                instance = instance[pcA.pop()];
            }
            instance = instance.prototype;
            instance.constructor.apply(instance);
            Page.Page = instance;
            console.log('IGD Page "' + pageClassName + '" initialized');
            return instance;
        }
    }
    /** Access current page instance */
    static get CurrentPage() {
        return this.Page;
    }
    /** Access host information */
    get HostInfo() {
        return this._hostInfo;
    }
    static getJSONFile(path) {
        return new Promise((resolve, reject) => {
            if (Page.CurrentPage) {
                Page.CurrentPage.getJsonFile(path, json => {
                    if (json) {
                        resolve(json);
                    }
                    else {
                        reject(new Error("Cannot load json: " + path));
                    }
                });
            }
            else {
                Http.getJSON(path)
                    .then(resolve)
                    .catch(() => reject(new Error("Cannot load json: " + path)));
            }
        });
    }
}
