declare var TICloudAgent;

(function () {

    'use strict';
    /*global TICloudAgent*/

    class DsProgressDialog {
        static $inject = ['$q', '$window', 'ticAlerts', 'ufConsole', 'ufProgess', 'ufDialog', 'ufDS', 'ufContext'];

        private types = this.ufConsole.msgTypes;

        private actionContext = {
            configureDS: 'Configuring Debug Server',
            deconfigureDS: 'Deconfiguring Debug Server',
            disconnectAllCores: 'Disconnect all connected cores',
            program: 'Load Program',
            verify: 'Verify Program',
            flashOperation: 'Flash Operation',
            readMemory: 'Read Memory',
            exportMemoryAsCoff: 'Export Memory As Coff',
            exportMemoryAsBin: 'Export Memory As Coff',
            evaluate: 'Evaluate Expression',
            getTargetInfo: 'Query Target Information',
			getResets: 'Query Reset Information',
			performReset: 'Perform Reset Operation'
        };

        constructor(
            private $q,
            private $window,
            private ticAlerts,
            private ufConsole,
            private ufProgess,
            private ufDialog,
            private ufDS,
            private ufContext: uniflash.Context
        ) {
            // TI Cloud Agent relies on a global Q for promises
            // For compatability set that to the angular $q service instead of pulling it from ticloudagent
            $window.Q = $q;
        }

        createTargetSupportProgressHandler(targetSupport, progressDialog) {
            function progressHandler(event) {
                progressDialog.handleEvent(event);
            }

            targetSupport.addListener('progress', progressHandler); // progress dialog
            return () => {
                targetSupport.removeListener('progress', progressHandler); // progress dialog
            };
        }

        createConsoleHandler(type) {
            return (event) => {
                if (event.message) {
                    this.ufConsole.addMessage(event.type, event.message);
                }
            };
        }

        createDSEventHandlers(ds, progressDialog) {
            let statusConsoleHandler = this.createConsoleHandler(this.types.STATUS);
            let gelConsoleHandler = this.createConsoleHandler(this.types.GEL);

            function updateProgressHandler(event) {
               // console.log(JSON.stringify(event));
                progressDialog.handleEvent(event, ds.progress.cancel.bind(ds.progress));
            }

            let openDialogs = {};
            let currentUfDialog = this.ufDialog;

            function newDialogHandler(event) {

                function buttonClicked(button) {
                    return ds.dialogs.setButtonResponse(event.id, button);
                }

                function closeClicked() {
                    return ds.dialogs.dismiss(event.id);
                }

                currentUfDialog.createDialog(event, buttonClicked, closeClicked)
                    .then((newDialog) => {
                        openDialogs[event.id] = newDialog;
                    });
            }

            function dismissDialogHandler(event) {
                if (openDialogs[event.id]) {
                    openDialogs[event.id].close();
                    openDialogs[event.id] = null;
                }
			}

			function fileExportEventHandler(event) {
                if (event) {
                    let eventObj = event.event;
                    if (eventObj && eventObj.data) {
                        let byteArray = new Uint8Array(eventObj.data);
                        let blob = new Blob([byteArray], { type: 'application/octet-stream' });
                        let defaultName = 'temp_file';
                        if (eventObj.defaultName) {
                            defaultName = eventObj.defaultName;
                        }
                        saveAs(blob, defaultName);
                    }
                }
            }
            ds.addListener('fileExportEvent', fileExportEventHandler);
            ds.addListener('statusMessage', statusConsoleHandler);
            ds.addListener('gelOutput', gelConsoleHandler);
            ds.progress.addListener('update', updateProgressHandler); // progress dialog
            ds.dialogs.willHandleDialogs(true);
            ds.dialogs.addListener('new', newDialogHandler);
            ds.dialogs.addListener('dismissed', dismissDialogHandler);

            return () => {
				ds.removeListener('fileExportEvent', fileExportEventHandler);
                ds.removeListener('statusMessage', statusConsoleHandler);
                ds.removeListener('gelOutput', gelConsoleHandler);
                ds.progress.removeListener('update', updateProgressHandler);
                ds.dialogs.removeListener('new', newDialogHandler);
                ds.dialogs.removeListener('dismissed', dismissDialogHandler);
            };
        }

        createAgentInitProgressEvent(msg, isFirstUpdate, isComplete) {
            let name = 'Please Wait...';
            return {
                id: -1,
                name: name,
                subActivity: msg,
                isFirstUpdate: isFirstUpdate,
                isComplete: isComplete
            };
        }

        createDoneProgressEvent() {
            let name = 'Done';
            return {
                subActivity: name,
                percent: 100,
                isCancellable: false
            };
        }

        getProgressEventHandler(progressDialog) {
            return (input) => {
                let msg = input[0] ? input[0] : input;
                return progressDialog.handleEvent(this.createAgentInitProgressEvent(msg, true, false));
            };
        }

        getTargetSupportProgressEventsHandler(progressDialog) {
            return (agent) => {
                return this.createTargetSupportProgressHandler(agent.TargetSupport, progressDialog);
            };
        }

        getDSHandlers(progressDialog) {
            return (agent) => {
                return this.createDSEventHandlers(agent.DS, progressDialog);
            };
        }

        setupDialogHandlers(progressDialog) {
            this.ufDS.registerProgressEventHandler(this.getProgressEventHandler(progressDialog));
            this.ufDS.registerDSHandler(this.getDSHandlers(progressDialog));
            this.ufDS.registerTargetSupportHandler(this.getTargetSupportProgressEventsHandler(progressDialog));
        }

        initDSWithGUIHandlers() {
            let progressDialog;
            return this.ufProgess.createProgress('Initializing DS GUI Handlers')
                .then((newProgressDialog) => {
                    progressDialog = newProgressDialog;
                })
                .then(() => {
                    this.setupDialogHandlers(progressDialog);
                })
                .catch((error) => {
                    if (error.message) {
                        return this.ticAlerts.showError(error.message);
                    }
                })
                .finally(() => {
                    this.ufDS.unregisterEventsHandlers(); 
                    progressDialog.close();
                });
        }

        getDSCore(coreName: string) {
            return {
                run: (action: string, ...argsToActionFunc) => {
					let progressDialog;
					let dsCoreRet;
                    return this.ufProgess.createProgress(this.actionContext[action])
                        .then((newProgressDialog) => {
                            progressDialog = newProgressDialog;
                        })
                        .then(() => {
                            this.setupDialogHandlers(progressDialog);
                            let dsCore = this.ufDS.getDSCore(coreName);
                            if (action) {
                                return dsCore[action].apply(dsCore, argsToActionFunc);
                            }
                        })
                        .then((ret) => {
							dsCoreRet = ret;
                            return progressDialog.handleEvent(this.createDoneProgressEvent());
						})
						.then(() => {
							return dsCoreRet;
                        })
                        .finally(() => {
                            this.ufDS.unregisterEventsHandlers();
                            progressDialog.close();
                        });
                }
            };
        }

        getCurrentDSCore() {
            return this.getDSCore(this.ufContext.getCurrentCore().name);
        }

        runDSRootOp(action: string, ...argsToActionFunc) {
            let progressDialog;
            return this.ufProgess.createProgress(this.actionContext[action])
                .then((newProgressDialog) => {
                    progressDialog = newProgressDialog;
                })
                .then(() => {
                    this.setupDialogHandlers(progressDialog);
                    if (action && this.ufDS.dsImpl) {
                        return this.ufDS.dsImpl[action].apply(this.ufDS.dsImpl, argsToActionFunc);
                    }
                })
                .then(() => {
                    return progressDialog.handleEvent(this.createDoneProgressEvent());
                })
                .finally(() => {
                    this.ufDS.unregisterEventsHandlers();
                    progressDialog.close();
                });
        }

        configureDS() {
            return this.runDSRootOp('configureDS');
        }

        deconfigureDS() {
            return this.runDSRootOp('deconfigureDS');
        }

        disconnectAllCores() {
            return this.runDSRootOp('disconnectAllCores');
        }
    }

    angular.module('uniflash').service('ufDsProgressDialog', DsProgressDialog);
}
)();
