/**
  * ******************************************************
  *                                                       *
  *   Copyright (C) Microsoft. All rights reserved.       *
  *                                                       *
  *******************************************************
  */
/// <reference path="./customTypings/vcremote-utils.d.ts" />
"use strict";
const utils = require("vcremote-utils");
const projects = require("./projectsystem/project-collection");
const project = require("./projectsystem/project");
const util = require("util");
const response = require("./response");
const iosDebug = require("./debugger/ios-debug");
const dd = require("./projectsystem/device-discovery");
const finder = require("./filesystem/finder");
const path = require("path");
const fs = require("fs");
const nconf = require("nconf");
var resources = utils.ResourcesManager;
var VCRemoteLib;
(function (VCRemoteLib) {
    // Will use /localization directory with translated strings if exists in npm installation, otherwise use default english strings.
    var pathToLocalizedStrings = path.join(__dirname + "../../../", "localization/app/localization/i18n");
    if (fs.existsSync(pathToLocalizedStrings)) {
        resources.init(nconf.get("lang"), pathToLocalizedStrings);
    }
    else {
        resources.init(nconf.get("lang"), path.join(__dirname, "./resources"));
    }
    var langSpecifics = null;
    function getLanguageSpecifics() {
        if (!langSpecifics) {
            langSpecifics = new VCLanguageSpecifics;
        }
        return langSpecifics;
    }
    VCRemoteLib.getLanguageSpecifics = getLanguageSpecifics;
    class VCLanguageSpecifics {
        constructor() {
            this._initialized = false;
        }
        get id() { return "63f68b50-3296-46a2-bb60-419cf4475d1e"; }
        get initialized() { return this._initialized; }
        init(conf) {
            this._conf = conf;
            this._projects = new projects.ProjectCollection(conf.baseDir());
            this._response = new response.VCLanguageSpecificsResponse(this._projects, this);
            console.info(resources.getStringForLanguage(nconf.get("lang"), "VCBuildLibraryInitialized"));
            iosDebug.init();
            this._initialized = true;
        }
        addProject(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            var self = this;
            this._projects.add(new project.RemoteSrcProject(req))
                .then(function (project) {
                self._response.renderProjectInfo(res, project);
            })
                .catch(function (err) {
                console.error(resources.getStringForLanguage(nconf.get("lang"), "AddingProjectToCollectionError"));
                res.status(500).send(resources.getStringForLanguage(nconf.get("lang"), "AddingProjectToCollectionError"));
            });
        }
        addProjectConfig(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var self = this;
                var prj = this._projects.getProjectById(req.params.id);
                prj.configs.addConfig(new project.RemoteCfgProject(req)).then(function (cfg) {
                    self._response.renderProjectCfg(res, cfg);
                });
            }
            else {
                var message = util.format(resources.getStringForLanguage(nconf.get("lang"), "ProjectNotFoundInCollection", req.params.id));
                console.error(message);
                res.status(404).send(message);
            }
        }
        updateProject(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            throw new Error("Not implemented!");
        }
        buildProject(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var prj = this._projects.getProjectById(req.params.id);
                var config;
                if (req.params.cfg != undefined) {
                    config = prj.configs.getCfgById(req.params.cfg);
                }
                else {
                    var context = {
                        arch: req.query.arch,
                        sdk: req.query.sdk,
                        config: req.query.cfg,
                        emulatorBuild: false,
                        outputDirectory: undefined,
                        provisioningProfile: "",
                        pbxProject: ""
                    };
                    config = new project.ProjectConfig(prj, context);
                }
                var bld;
                var buildAction = req.query.buildaction;
                if (buildAction == "clean") {
                    bld = prj.build.cleanConfig(config);
                }
                else if (buildAction == "rebuild") {
                    bld = prj.build.rebuildConfig(config);
                }
                else {
                    bld = prj.build.buildConfig(config);
                }
                this._response.renderBuildInfo(res, bld);
            }
            else {
                var message = util.format(resources.getStringForLanguage(nconf.get("lang"), "ProjectNotFoundInCollection", req.params.id));
                console.error(message);
                res.status(404).send(message);
            }
        }
        getProjects(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            this._response.renderProjects(res);
        }
        getDevices(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            this._response.renderDevices(res);
        }
        getProjectConfig(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var prj = this._projects.getProjectById(req.params.id);
                var bld = prj.build.getBuildByCfgId(req.params.cfg);
                this._response.renderProjectCfg(res, bld.config);
            }
            else {
                var message = util.format(resources.getStringForLanguage(nconf.get("lang"), "ProjectNotFoundInCollection", req.params.id));
                console.error(message);
                res.status(404).send(message);
            }
        }
        getProjectConfigs(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var project = this._projects.getProjectById(req.params.id);
                this._response.renderProjectCfgs(res, project);
            }
            else {
                var message = util.format(resources.getStringForLanguage(nconf.get("lang"), "ProjectNotFoundInCollection", req.params.id));
                console.error(message);
                res.status(404).send(message);
            }
        }
        retrieveBuild(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var project = this._projects.getProjectById(req.params.id);
                var bld = project.build.getBuildByCfgId(req.params.cfg);
                var self = this;
                bld.archive().then(function (archiveFileName) {
                    self._response.renderBuild(res, bld);
                });
            }
            else {
                var message = util.format(resources.getStringForLanguage(nconf.get("lang"), "ProjectNotFoundInCollection", req.params.id));
                console.error(message);
                res.status(404).send(message);
            }
        }
        installBuild(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var project = this._projects.getProjectById(req.params.id);
                var bld = project.build.getBuildByCfgId(req.params.cfg);
                var self = this;
                var appName = req.query.appName;
                var appPath = bld.outputDirectory + "/" + appName;
                var deviceUdid = req.query.deviceUdid;
                if (bld.config.arch === "i386" || bld.config.arch === "x86_64") {
                    dd.DeviceDiscovery.tryGetSimulatorByIdOrDefault(deviceUdid).then(function (simulator) {
                        // Install app on the first simulator, but do not bring it to the foreground.
                        // Then stop it.
                        simulator.installStartApp({
                            appPath: appPath,
                            hide: true,
                            focus: false,
                            killIfRunning: true,
                            timeout: 15,
                            autoExit: true
                        }).then(function () {
                            console.info(resources.getStringForLanguage(nconf.get("lang"), "SuccessfullyDeployedSimulator", simulator.name));
                            simulator.stop().then(function () {
                                console.info(resources.getStringForLanguage(nconf.get("lang"), "SuccessfullyStoppedSimulator", simulator.name));
                                self._response.renderBuildInfo(res, bld);
                            }).catch(function (reason) {
                                var message = resources.getStringForLanguage(nconf.get("lang"), "FailedToStopSimulator", simulator.name, reason.message);
                                console.info(message);
                                res.status(404).send(message);
                            });
                        }).catch(function (reason) {
                            var message = resources.getStringForLanguage(nconf.get("lang"), "FailedToDeploySimulator", simulator.name, reason.message);
                            console.info(message);
                            res.status(404).send(message);
                        });
                    }).catch(function (reason) {
                        var message = resources.getStringForLanguage(nconf.get("lang"), "FailedToFetchFirstDevice", reason.message);
                        console.info(message);
                        res.status(404).send(message);
                    });
                }
                else {
                    // ARM
                    dd.DeviceDiscovery.tryGetDeviceByIdOrDefault(deviceUdid).then(function (device) {
                        console.info(resources.getStringForLanguage(nconf.get("lang"), "InstallingAppOnDevice", device.name));
                        device.installApp(appPath).then(function () {
                            console.info(resources.getStringForLanguage(nconf.get("lang"), "InstalledAppOnDevice", device.name));
                            self._response.renderBuildInfo(res, bld);
                        }).catch(function (reason) {
                            var message = resources.getStringForLanguage(nconf.get("lang"), "FailedToInstallAppOnDevice", device.name, reason.message);
                            console.info(message);
                            res.status(404).send(message);
                        });
                    }).catch(function (reason) {
                        var message = resources.getStringForLanguage(nconf.get("lang"), "FailedToFetchFirstDevice", reason.message);
                        console.info(message);
                        res.status(404).send(message);
                    });
                }
            }
            else {
                var message = util.format(resources.getStringForLanguage(nconf.get("lang"), "ProjectNotFoundInCollection", req.params.id));
                console.error(message);
                res.status(404).send(message);
            }
        }
        getBuildLog(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var project = this._projects.getProjectById(req.params.id);
                var bld = project.build.getBuildByCfgId(req.params.cfg);
                var pos = parseInt(req.query.pos || "0"), l = parseInt(req.query.l || "0");
                this._response.renderBuildLog(res, bld, bld.log.read(pos, l), pos);
            }
            else {
                res.end();
            }
        }
        getBuildStatus(req, res) {
            if (!this.ensureCompatibleClient(req, res)) {
                return;
            }
            if (this._projects.contains(req.params.id)) {
                var project = this._projects.getProjectById(req.params.id);
                var bld = project.build.getBuildByCfgId(req.params.cfg);
                this._response.renderBuildStatus(res, project, bld);
            }
            else {
                res.end();
            }
        }
        execOpen(req, res) {
            finder.execOpen(req, res);
        }
        putFiles(req, res) {
            finder.putFiles(req, res);
        }
        deleteFiles(req, res) {
            finder.deleteFiles(req, res);
        }
        getFiles(req, res) {
            finder.getFiles(req, res);
        }
        setupForDebugging(req, res) {
            iosDebug.startDebugListenerServer(this._conf, req, res);
        }
        getAppRemotePath(req, res) {
            iosDebug.getAppRemotePath(req, res);
        }
        terminateDebugger() {
            iosDebug.terminate();
        }
        close() {
            this._projects.close();
        }
        // Check whether the client (Visual Studio) is supported by this version of vcremote (RTM).
        isCompatibleClient(req) {
            var clientVersion = parseFloat(req.query.ver);
            // If the client version is unspecified, we will support the client for compatibility purposes.
            if (isNaN(clientVersion))
                return true;
            var minVersion = parseFloat(this._projects.minimumSupportedClientVersion);
            var maxVersion = parseFloat(this._projects.maximumSupportedClientVersion);
            return (clientVersion >= minVersion && clientVersion <= maxVersion);
        }
        ensureCompatibleClient(req, res) {
            if (!this.isCompatibleClient(req)) {
                console.warn(resources.getStringForLanguage(nconf.get("lang"), "VisualStudioIncompatible"));
                this._response.renderIncompatibleClient(res);
                return false;
            }
            return true;
        }
    }
    VCRemoteLib.VCLanguageSpecifics = VCLanguageSpecifics;
})(VCRemoteLib || (VCRemoteLib = {}));
module.exports = VCRemoteLib;
