"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var yok_1 = require("../../../yok");
var chai_1 = require("chai");
var stubs_1 = require("../stubs");
var Future = require("fibers/future");
var events_1 = require("events");
var project_constants_1 = require("../../../appbuilder/project-constants");
var device_emitter_1 = require("../../../appbuilder/device-emitter");
var AndroidDeviceDiscoveryMock = (function (_super) {
    __extends(AndroidDeviceDiscoveryMock, _super);
    function AndroidDeviceDiscoveryMock() {
        _super.apply(this, arguments);
    }
    AndroidDeviceDiscoveryMock.prototype.ensureAdbServerStarted = function () {
        return Future.fromResult();
    };
    return AndroidDeviceDiscoveryMock;
}(events_1.EventEmitter));
var companionAppIdentifiers = {
    "cordova": {
        "android": "cordova-android",
        "ios": "cordova-ios",
        "wp8": "cordova-wp8"
    },
    "nativescript": {
        "android": "nativescript-android",
        "ios": "nativescript-ios"
    }
};
function createTestInjector() {
    var testInjector = new yok_1.Yok();
    testInjector.register("androidDeviceDiscovery", AndroidDeviceDiscoveryMock);
    testInjector.register("iOSDeviceDiscovery", events_1.EventEmitter);
    testInjector.register("iOSSimulatorDiscovery", events_1.EventEmitter);
    testInjector.register("devicesService", {
        initialize: function (opts) { return Future.fromResult(); }
    });
    testInjector.register("deviceLogProvider", events_1.EventEmitter);
    testInjector.register("companionAppsService", {
        getAllCompanionAppIdentifiers: function () { return companionAppIdentifiers; }
    });
    testInjector.register("projectConstants", project_constants_1.ProjectConstants);
    testInjector.register("logger", stubs_1.CommonLoggerStub);
    testInjector.register("deviceEmitter", device_emitter_1.DeviceEmitter);
    return testInjector;
}
describe("deviceEmitter", function () {
    var testInjector, deviceEmitter, isOpenDeviceLogStreamCalled = false;
    beforeEach(function () {
        testInjector = createTestInjector();
        deviceEmitter = testInjector.resolve("deviceEmitter");
        isOpenDeviceLogStreamCalled = false;
    });
    describe("initialize", function () {
        it("does not throw when ensureAdbServerStarted throws", function () {
            var androidDeviceDiscovery = testInjector.resolve("androidDeviceDiscovery"), logger = testInjector.resolve("logger");
            androidDeviceDiscovery.ensureAdbServerStarted = function () {
                return (function () {
                    throw new Error("error1");
                }).future()();
            };
            var warnOutput = "";
            logger.warn = function (warnMsg) { warnOutput += warnMsg; };
            deviceEmitter.initialize().wait();
            chai_1.assert.isTrue(warnOutput.indexOf("Unable to start adb server") !== -1, "When ensureAdbServerStarted throws, the string 'Unable to start adb server' must be shown as warning.");
            chai_1.assert.isTrue(warnOutput.indexOf("error1") !== -1, "When ensureAdbServerStarted throws, the error message must be shown as warning.");
        });
    });
    describe("raises correct events after initialize is called:", function () {
        var androidDeviceDiscovery, iOSDeviceDiscovery, iOSSimulatorDiscovery, androidDevice, iOSDevice, iOSSimulator;
        beforeEach(function () {
            deviceEmitter.initialize().wait();
            androidDeviceDiscovery = testInjector.resolve("androidDeviceDiscovery");
            iOSDeviceDiscovery = testInjector.resolve("iOSDeviceDiscovery");
            iOSSimulatorDiscovery = testInjector.resolve("iOSSimulatorDiscovery");
            androidDevice = {
                deviceInfo: {
                    "identifier": "androidDeviceId",
                    "platform": "android"
                },
                applicationManager: new events_1.EventEmitter(),
                openDeviceLogStream: function () { return isOpenDeviceLogStreamCalled = true; }
            };
            iOSDevice = {
                deviceInfo: {
                    "identifier": "iOSDeviceId",
                    "platform": "iOS"
                },
                applicationManager: new events_1.EventEmitter(),
                openDeviceLogStream: function () { return isOpenDeviceLogStreamCalled = true; }
            };
            iOSSimulator = {
                deviceInfo: {
                    "identifier": "iOSSimulatorDeviceId",
                    "platform": "iOS"
                },
                applicationManager: new events_1.EventEmitter(),
                openDeviceLogStream: function () { return isOpenDeviceLogStreamCalled = true; }
            };
        });
        _.each(["deviceFound", "deviceLost"], function (deviceEvent) {
            describe(deviceEvent, function () {
                var attachDeviceEventVerificationHandler = function (expectedDeviceInfo, done) {
                    deviceEmitter.on(deviceEvent, function (deviceInfo) {
                        chai_1.assert.deepEqual(deviceInfo, expectedDeviceInfo);
                        setTimeout(function () { return done(); }, 0);
                    });
                };
                it("is raised when working with android device", function (done) {
                    attachDeviceEventVerificationHandler(androidDevice.deviceInfo, done);
                    androidDeviceDiscovery.emit(deviceEvent, androidDevice);
                });
                it("is raised when working with iOS device", function (done) {
                    attachDeviceEventVerificationHandler(iOSDevice.deviceInfo, done);
                    iOSDeviceDiscovery.emit(deviceEvent, iOSDevice);
                });
                it("is raised when working with iOS simulator", function (done) {
                    attachDeviceEventVerificationHandler(iOSSimulator.deviceInfo, done);
                    iOSSimulatorDiscovery.emit(deviceEvent, iOSSimulator);
                });
            });
        });
        describe("openDeviceLogStream", function () {
            var attachDeviceEventVerificationHandler = function (expectedDeviceInfo, done) {
                deviceEmitter.on("deviceFound", function (deviceInfo) {
                    chai_1.assert.deepEqual(deviceInfo, expectedDeviceInfo);
                    setTimeout(function () {
                        chai_1.assert.isTrue(isOpenDeviceLogStreamCalled, "When device is found, openDeviceLogStream must be called immediately.");
                        done();
                    }, 0);
                });
            };
            it("is called when working with android device", function (done) {
                attachDeviceEventVerificationHandler(androidDevice.deviceInfo, done);
                androidDeviceDiscovery.emit("deviceFound", androidDevice);
            });
            it("is called when working with iOS device", function (done) {
                attachDeviceEventVerificationHandler(iOSDevice.deviceInfo, done);
                iOSDeviceDiscovery.emit("deviceFound", iOSDevice);
            });
            it("is called when working with iOS simulator", function (done) {
                attachDeviceEventVerificationHandler(iOSSimulator.deviceInfo, done);
                iOSSimulatorDiscovery.emit("deviceFound", iOSSimulator);
            });
        });
        describe("deviceLogProvider on data", function () {
            var deviceLogProvider;
            beforeEach(function () {
                deviceLogProvider = testInjector.resolve("deviceLogProvider");
            });
            describe("raises deviceLogData with correct identifier and data", function () {
                var expectedDeviceLogData = "This is some log data from device.";
                var attachDeviceLogDataVerificationHandler = function (expectedDeviceIdentifier, done) {
                    deviceEmitter.on("deviceLogData", function (identifier, data) {
                        chai_1.assert.deepEqual(identifier, expectedDeviceIdentifier);
                        chai_1.assert.deepEqual(data, expectedDeviceLogData);
                        setTimeout(function () { return done(); }, 0);
                    });
                };
                it("is called when android device reports data", function (done) {
                    attachDeviceLogDataVerificationHandler(androidDevice.deviceInfo.identifier, done);
                    androidDeviceDiscovery.emit("deviceFound", androidDevice);
                    deviceLogProvider.emit("data", androidDevice.deviceInfo.identifier, expectedDeviceLogData);
                });
                it("is called when iOS device reports data", function (done) {
                    attachDeviceLogDataVerificationHandler(iOSDevice.deviceInfo.identifier, done);
                    iOSDeviceDiscovery.emit("deviceFound", iOSDevice);
                    deviceLogProvider.emit("data", iOSDevice.deviceInfo.identifier, expectedDeviceLogData);
                });
                it("is called when iOS simulator reports data", function (done) {
                    attachDeviceLogDataVerificationHandler(iOSSimulator.deviceInfo.identifier, done);
                    iOSSimulatorDiscovery.emit("deviceFound", iOSSimulator);
                    deviceLogProvider.emit("data", iOSSimulator.deviceInfo.identifier, expectedDeviceLogData);
                });
            });
        });
        _.each(["applicationInstalled", "applicationUninstalled"], function (applicationEvent) {
            describe(applicationEvent, function () {
                var expectedApplicationIdentifier = "application identifier";
                var attachApplicationEventVerificationHandler = function (expectedDeviceIdentifier, done) {
                    deviceEmitter.on(applicationEvent, function (deviceIdentifier, appIdentifier) {
                        chai_1.assert.deepEqual(deviceIdentifier, expectedDeviceIdentifier);
                        chai_1.assert.deepEqual(appIdentifier, expectedApplicationIdentifier);
                        setTimeout(function () { return done(); }, 0);
                    });
                };
                it("is raised when working with android device", function (done) {
                    attachApplicationEventVerificationHandler(androidDevice.deviceInfo.identifier, done);
                    androidDeviceDiscovery.emit("deviceFound", androidDevice);
                    androidDevice.applicationManager.emit(applicationEvent, expectedApplicationIdentifier);
                });
                it("is raised when working with iOS device", function (done) {
                    attachApplicationEventVerificationHandler(iOSDevice.deviceInfo.identifier, done);
                    iOSDeviceDiscovery.emit("deviceFound", iOSDevice);
                    iOSDevice.applicationManager.emit(applicationEvent, expectedApplicationIdentifier);
                });
                it("is raised when working with iOS simulator", function (done) {
                    attachApplicationEventVerificationHandler(iOSSimulator.deviceInfo.identifier, done);
                    iOSSimulatorDiscovery.emit("deviceFound", iOSSimulator);
                    iOSSimulator.applicationManager.emit(applicationEvent, expectedApplicationIdentifier);
                });
            });
        });
        _.each(["debuggableAppFound", "debuggableAppLost"], function (applicationEvent) {
            describe(applicationEvent, function () {
                var attachDebuggableEventVerificationHandler = function (expectedDebuggableAppInfo, done) {
                    deviceEmitter.on(applicationEvent, function (debuggableAppInfo) {
                        chai_1.assert.deepEqual(debuggableAppInfo, expectedDebuggableAppInfo);
                        setTimeout(function () { return done(); }, 0);
                    });
                };
                it("is raised when working with android device", function (done) {
                    var debuggableAppInfo = {
                        appIdentifier: "app identifier",
                        deviceIdentifier: androidDevice.deviceInfo.identifier,
                        framework: "cordova"
                    };
                    attachDebuggableEventVerificationHandler(debuggableAppInfo, done);
                    androidDeviceDiscovery.emit("deviceFound", androidDevice);
                    androidDevice.applicationManager.emit(applicationEvent, debuggableAppInfo);
                });
                it("is raised when working with iOS device", function (done) {
                    var debuggableAppInfo = {
                        appIdentifier: "app identifier",
                        deviceIdentifier: iOSDevice.deviceInfo.identifier,
                        framework: "cordova"
                    };
                    attachDebuggableEventVerificationHandler(debuggableAppInfo, done);
                    iOSDeviceDiscovery.emit("deviceFound", iOSDevice);
                    iOSDevice.applicationManager.emit(applicationEvent, debuggableAppInfo);
                });
                it("is raised when working with iOS simulator", function (done) {
                    var debuggableAppInfo = {
                        appIdentifier: "app identifier",
                        deviceIdentifier: iOSSimulator.deviceInfo.identifier,
                        framework: "cordova"
                    };
                    attachDebuggableEventVerificationHandler(debuggableAppInfo, done);
                    iOSSimulatorDiscovery.emit("deviceFound", iOSSimulator);
                    iOSSimulator.applicationManager.emit(applicationEvent, debuggableAppInfo);
                });
            });
        });
        _.each(["debuggableViewFound", "debuggableViewLost", "debuggableViewChanged"], function (applicationEvent) {
            describe(applicationEvent, function () {
                var createDebuggableWebView = function (uniqueId) {
                    return {
                        description: "description_" + uniqueId,
                        devtoolsFrontendUrl: "devtoolsFrontendUrl_" + uniqueId,
                        id: "" + uniqueId,
                        title: "title_" + uniqueId,
                        type: "type_" + uniqueId,
                        url: "url_" + uniqueId,
                        webSocketDebuggerUrl: "webSocketDebuggerUrl_" + uniqueId,
                    };
                };
                var appId = "appId";
                var attachDebuggableEventVerificationHandler = function (expectedDeviceIdentifier, expectedAppIdentifier, expectedDebuggableViewInfo, done) {
                    deviceEmitter.on(applicationEvent, function (deviceIdentifier, appIdentifier, debuggableViewInfo) {
                        chai_1.assert.deepEqual(deviceIdentifier, expectedDeviceIdentifier);
                        chai_1.assert.deepEqual(appIdentifier, expectedAppIdentifier);
                        chai_1.assert.deepEqual(debuggableViewInfo, expectedDebuggableViewInfo);
                        setTimeout(done, 0);
                    });
                };
                it("is raised when working with android device", function (done) {
                    var expectedDebuggableViewInfo = createDebuggableWebView("test1");
                    attachDebuggableEventVerificationHandler(androidDevice.deviceInfo.identifier, appId, expectedDebuggableViewInfo, done);
                    androidDeviceDiscovery.emit("deviceFound", androidDevice);
                    androidDevice.applicationManager.emit(applicationEvent, appId, expectedDebuggableViewInfo);
                });
                it("is raised when working with iOS device", function (done) {
                    var expectedDebuggableViewInfo = createDebuggableWebView("test1");
                    attachDebuggableEventVerificationHandler(iOSDevice.deviceInfo.identifier, appId, expectedDebuggableViewInfo, done);
                    iOSDeviceDiscovery.emit("deviceFound", iOSDevice);
                    iOSDevice.applicationManager.emit(applicationEvent, appId, expectedDebuggableViewInfo);
                });
                it("is raised when working with iOS simulator", function (done) {
                    var expectedDebuggableViewInfo = createDebuggableWebView("test1");
                    attachDebuggableEventVerificationHandler(iOSSimulator.deviceInfo.identifier, appId, expectedDebuggableViewInfo, done);
                    iOSSimulatorDiscovery.emit("deviceFound", iOSSimulator);
                    iOSSimulator.applicationManager.emit(applicationEvent, appId, expectedDebuggableViewInfo);
                });
            });
        });
        _.each(["companionAppInstalled", "companionAppUninstalled"], function (applicationEvent) {
            describe(applicationEvent, function () {
                _.each(companionAppIdentifiers, function (companionAppIdentifersForPlatform, applicationFramework) {
                    describe("is raised for " + applicationFramework, function () {
                        var attachCompanionEventVerificationHandler = function (expectedDeviceIdentifier, done) {
                            deviceEmitter.on(applicationEvent, function (deviceIdentifier, framework) {
                                chai_1.assert.deepEqual(deviceIdentifier, expectedDeviceIdentifier);
                                chai_1.assert.deepEqual(framework, applicationFramework);
                                setTimeout(function () { return done(); }, 0);
                            });
                        };
                        it("when working with android device", function (done) {
                            attachCompanionEventVerificationHandler(androidDevice.deviceInfo.identifier, done);
                            androidDeviceDiscovery.emit("deviceFound", androidDevice);
                            androidDevice.applicationManager.emit("applicationInstalled", companionAppIdentifersForPlatform["android"]);
                            if (applicationEvent === "companionAppUninstalled") {
                                androidDevice.applicationManager.emit("applicationUninstalled", companionAppIdentifersForPlatform["android"]);
                            }
                        });
                        it("when working with iOS device", function (done) {
                            attachCompanionEventVerificationHandler(iOSDevice.deviceInfo.identifier, done);
                            iOSDeviceDiscovery.emit("deviceFound", iOSDevice);
                            iOSDevice.applicationManager.emit("applicationInstalled", companionAppIdentifersForPlatform["ios"]);
                            if (applicationEvent === "companionAppUninstalled") {
                                iOSDevice.applicationManager.emit("applicationUninstalled", companionAppIdentifersForPlatform["ios"]);
                            }
                        });
                        it("when working with iOS simulator", function (done) {
                            attachCompanionEventVerificationHandler(iOSSimulator.deviceInfo.identifier, done);
                            iOSSimulatorDiscovery.emit("deviceFound", iOSSimulator);
                            iOSSimulator.applicationManager.emit("applicationInstalled", companionAppIdentifersForPlatform["ios"]);
                            if (applicationEvent === "companionAppUninstalled") {
                                iOSSimulator.applicationManager.emit("applicationUninstalled", companionAppIdentifersForPlatform["ios"]);
                            }
                        });
                    });
                });
            });
        });
    });
});
