var uniflash;
(function (uniflash) {
    var DSDefaultImpl = (function () {
        function DSDefaultImpl(ds, $q, $rootScope, $log, ticAlerts, ufSession, ufPrograms, ufPropertiesValue, ufAgentInstallDialog, ufPreferencesSrv, ufContext, ufTargetConfig, ufConsole, x2js) {
            this.ds = ds;
            this.$q = $q;
            this.$rootScope = $rootScope;
            this.$log = $log;
            this.ticAlerts = ticAlerts;
            this.ufSession = ufSession;
            this.ufPrograms = ufPrograms;
            this.ufPropertiesValue = ufPropertiesValue;
            this.ufAgentInstallDialog = ufAgentInstallDialog;
            this.ufPreferencesSrv = ufPreferencesSrv;
            this.ufContext = ufContext;
            this.ufTargetConfig = ufTargetConfig;
            this.ufConsole = ufConsole;
            this.x2js = x2js;
        }
        DSDefaultImpl.prototype.configureDS = function (ccxmlContents, fileName) {
            var _this = this;
            if (this.ds.cachedConfigure) {
                return this.ds.cachedConfigure.finally(function () {
                    _this.ds.unregisterEventsHandlers();
                    _this.$log.debug('returning cached configure');
                    _this.ds.callHandler(_this.ds.progressEventHandler, 'Initialization Complete...');
                    _this.ds.setupCleanUpTargetSupportProgressEventsHandler(_this.ds.agent);
                    _this.ds.setupCleanUpDSHandlers(_this.ds.agent);
                });
            }
            var ccxmlFilePath;
            return (function () {
                _this.ds.cachedConfigure = _this.ds.initWithModules(_this.ds.modules)
                    .then(function (newAgent) {
                    _this.ds.agent = newAgent;
                    _this.ds.callHandler(_this.ds.progressEventHandler, 'Initialization Complete...');
                    return _this.writeCCXML(ccxmlContents, fileName);
                })
                    .then(function (newCcxmlFilePath) {
                    ccxmlFilePath = newCcxmlFilePath;
                    _this.ds.setupCleanUpTargetSupportProgressEventsHandler(_this.ds.agent);
                    // todo : temporary solution, eventually this need to be fixed on the agenthost side
                    if (typeof process === 'undefined') {
                        return _this.ds.agent.TargetSupport.add(ccxmlFilePath);
                    }
                })
                    .then(function () {
                    return _this.ds.agent.getSubModule('DS');
                })
                    .then(function (newDS) {
                    _this.ds.agent.DS = newDS;
                    _this.ds.setupCleanUpDSHandlers(_this.ds.agent);
                    return newDS.configure(ccxmlFilePath);
                })
                    .then(function (data) {
                    _this.$log.debug('configured');
                    return {
                        ds: _this.ds.agent.DS,
                        ccxmlFilePath: ccxmlFilePath,
                        configData: data
                    };
                })
                    .catch(function (e) {
                    _this.ds.cachedConfigure = null;
                    if (e instanceof ti_common.CancelError) {
                        throw new Error(e.message);
                    }
                    else {
                        _this.$log.error('configure failed: ' + e.message);
                        if (_this.ds.agent.DS) {
                            _this.ds.agent.DS.close();
                        }
                        throw e;
                    }
                });
                _this.$log.debug('returning new configure');
                return _this.ds.cachedConfigure;
            })();
        };
        DSDefaultImpl.prototype.configureLogging = function (enable, filename) {
            var _this = this;
            this.$rootScope.$emit('ds.opStarted');
            var fullPath, configObj;
            return this.configureDS(this.ufSession.getCCXML(), 'uniflash_temp.ccxml')
                .then(function (configureDSRetObj) {
                configObj = configureDSRetObj;
                return (enable) ? _this.writeLocalFile(filename, '') : null;
            })
                .then(function (writeFileResObj) {
                fullPath = (writeFileResObj === null) ? null : writeFileResObj.path;
                return configObj.ds.logging.configure(enable, fullPath);
            })
                .then(function () {
                return fullPath;
            })
                .finally(function () {
                _this.$rootScope.$emit('ds.opFinished');
            });
        };
        DSDefaultImpl.prototype.disconnectAllCores = function () {
            var _this = this;
            var disconnectPromise = this.$q.when();
            if (Object.keys(this.ds.cachedConnectedCores).length > 0) {
                var disconnectPromises_1 = [];
                angular.forEach(this.ds.cachedConnectedCores, function (value, key) {
                    if (value) {
                        disconnectPromises_1.push(value.targetState.disconnect());
                    }
                });
                disconnectPromise = this.$q.all(disconnectPromises_1);
            }
            return disconnectPromise
                .finally(function () {
                _this.ds.cachedConnectedCores = {};
            });
        };
        DSDefaultImpl.prototype.deconfigureDS = function (dontCloseDS) {
            var _this = this;
            if (this.ds.cachedConfigure) {
                return this.disconnectAllCores()
                    .then(function () {
                    _this.$rootScope.$emit('ds.opStarted');
                    _this.ds.callHandler(_this.ds.progressEventHandler, 'Deconfiguring...');
                    _this.$log.debug('cores disconnected: ' + JSON.stringify(_this.ds.cachedConnectedCores));
                    if (_this.ds.agent && _this.ds.agent.DS) {
                        return _this.ds.agent.DS.deConfigure();
                    }
                })
                    .then(function (result) {
                    _this.$log.debug('deconfigured');
                    _this.ds.cachedConfigure = null;
                    _this.ds.unregisterEventsHandlers();
                    return result;
                })
                    .finally(function () {
                    if (!dontCloseDS && _this.ds.agent && _this.ds.agent.DS) {
                        _this.ds.agent.DS.close();
                    }
                    _this.$rootScope.$emit('ds.opFinished');
                });
            }
            else {
                return this.$q.when();
            }
        };
        DSDefaultImpl.prototype.findCorePath = function (dSConfigObj, coreName) {
            for (var i = 0; i < dSConfigObj.configData.cores.length; i++) {
                if (_.endsWith(dSConfigObj.configData.cores[i], coreName)) {
                    return dSConfigObj.configData.cores[i];
                }
            }
        };
        DSDefaultImpl.prototype.findNonDbgCorePath = function (dSConfigObj, coreName) {
            for (var i = 0; i < dSConfigObj.configData.nonDebugCores.length; i++) {
                if (_.endsWith(dSConfigObj.configData.nonDebugCores[i], coreName)) {
                    return dSConfigObj.configData.nonDebugCores[i];
                }
            }
        };
        DSDefaultImpl.prototype.getCore = function (coreName, dSConfigObj, isNonDebug) {
            var configObject;
            if (!dSConfigObj) {
                if (this.ds.cachedConfigure) {
                    configObject = this.ds.cachedConfigure;
                }
                else {
                    throw new Error('connectToCore: ds not configured.');
                }
            }
            else {
                configObject = dSConfigObj;
            }
            var corePath = isNonDebug ? this.findNonDbgCorePath(dSConfigObj, coreName) : this.findCorePath(dSConfigObj, coreName);
            return configObject.ds.getSubModule(corePath);
        };
        DSDefaultImpl.prototype.connectToCore = function (coreName, dSConfigObj, isNonDebug, options) {
            var _this = this;
            var coreInfo = this.ds.cachedConnectedCores[coreName];
            if (!coreInfo) {
                var coreRet_1;
                return this.getCore(coreName, dSConfigObj, isNonDebug)
                    .then(function (newCore) {
                    coreRet_1 = newCore;
                    // only need to set properties if the current context matches the connecting core
                    if (_.includes(coreName, _this.ds.getContext().getCurrentCore().name)) {
                        coreRet_1.settings.set(_this.ds.getUfPropertiesValue().getPropertiesValuesMap(_this.ds.getContext().getCurrentCore().name));
                    }
                    if (_this.ds.targetStateListeners[coreName]) {
                        angular.forEach(_this.ds.targetStateListeners[coreName], function (listenerToAdd) {
                            coreRet_1.targetState.addListener('changed', listenerToAdd);
                        });
                    }
                    if (options && (options.connect === false)) {
                        // don't need to connect if connect option is false
                        return;
                    }
                    _this.ds.cachedConnectedCores[coreName] = coreRet_1;
                    return coreRet_1.targetState.connect();
                })
                    .then(function () {
                    _this.$log.debug('connect to core ' + coreName);
                    return coreRet_1;
                })
                    .catch(function () {
                    _this.$log.debug('connect err to ' + coreName);
                    _this.ds.cachedConnectedCores[coreName] = null;
                });
            }
            else {
                return this.$q.when(coreInfo);
            }
        };
        DSDefaultImpl.prototype.writeFileToBeFlashed = function (file) {
            var _this = this;
            if (file.path !== file.name || file.isLocal) {
                return this.$q.resolve(file.path);
            }
            return file.getContents(ti_common.file.ContentType.Blob)
                .then(function (content) {
                return TICloudAgent.Util.encodeAsBase64(content);
            }).then(function (encodedAsBase64) {
                return _this.ds.agent.File.write(file.name, encodedAsBase64);
            }).then(function (obj) {
                return obj.path;
            }).then(function (programFileLocalPath) {
                return programFileLocalPath.replace(/\\/g, '/');
            });
        };
        DSDefaultImpl.prototype.writeCCXML = function (ccxmlContents, filename) {
            var _this = this;
            return TICloudAgent.Util.encodeAsBase64(ccxmlContents)
                .then(function (encodedAsBase64) {
                return _this.ds.agent.File.write(filename, encodedAsBase64);
            }).then(function (obj) {
                return obj.path;
            });
        };
        DSDefaultImpl.prototype.writeLocalFile = function (path, args) {
            return this.ds.agent.File.write(path, args);
        };
        // main operations are going through this block as it handles configure/connect/work/rest/disconnect etc with progress and console
        DSDefaultImpl.prototype.completeWorkflowAction = function (mainAction, coreName, optionObj) {
            var _this = this;
            this.$rootScope.$emit('ds.opStarted');
            var curCore;
            return this.configureDS(this.ufSession.getCCXML(), 'uniflash_temp.ccxml')
                .then(function (configObj) {
                return _this.connectToCore(coreName, configObj, undefined, optionObj);
            })
                .then(function (core) {
                if (optionObj && (optionObj.connect === false)) {
                    // don't need to halt the target if connect option is false
                    curCore = core;
                    return;
                }
                if (core && mainAction) {
                    curCore = core;
                    return core.targetState.halt()
                        .catch(function (e) {
                        if (e.message !== 'Target is not running') {
                            _this.$log.error('Halt target failed: ' + e.message);
                            throw e;
                        }
                    });
                }
            })
                .then(function () {
                if (curCore) {
                    return mainAction(curCore);
                }
            })
                .catch(function (error) {
                if (error !== 'backdrop click' && !(error instanceof ti_common.CancelError)) {
                    if (error.message === 'Unknown error') {
                        return _this.ticAlerts.showError('Error executing current operation. Please check the console for additional error information.');
                    }
                    else if (error.message.substring(0, 41) === 'Flash interface has already been created.') {
                        return _this.ticAlerts.showError(error.message.substring(0, 41) + ' Please restart the application (Desktop) or refresh your browser (Cloud) and try the operation again.');
                    }
                    else {
                        return _this.ticAlerts.showError(error.message);
                    }
                }
            })
                .finally(function () {
                return _this.$q(function (resolve) {
                    if (curCore) {
                        resolve(curCore.settings.get([])
                            .then(function (allSettings) {
                            _this.ufPropertiesValue.updateFromDS(allSettings.nameValueMap, _this.ufContext.getCurrentCore().name);
                        }));
                    }
                    else {
                        resolve();
                    }
                })
                    .then(function () {
                    if (optionObj && (optionObj.connect === false)) {
                        // don't need to run target if we are not connecting to the target (ie; NCOperation)
                        return;
                    }
                    if (curCore && optionObj && optionObj.runAfterOp) {
                        return curCore.targetState.run(1).catch(function (e) {
                            if (e) {
                                _this.$log.error('completeWorkflowAction curCore.targetState.run(1) ' + JSON.stringify(e));
                            }
                        });
                    }
                })
                    .then(function () {
                    if (optionObj && (optionObj.connect === false || optionObj.disconnect === false)) {
                        // don't need to disconnect if we did not connect (ie; NCOperation), or if we don't want to disconnect
                        return;
                    }
                    if (_this.ufPreferencesSrv.get('Auto Disconnect')) {
                        return _this.disconnectAllCores().catch(function (e) {
                            if (e) {
                                _this.$log.error('completeWorkflowAction this.disconnectAllCores() ' + JSON.stringify(e));
                            }
                        });
                    }
                })
                    .finally(function () {
                    _this.$rootScope.$emit('ds.opFinished');
                });
            });
        };
        return DSDefaultImpl;
    }());
    uniflash.DSDefaultImpl = DSDefaultImpl;
})(uniflash || (uniflash = {}));
