"use strict";
var path = require('path');
var browserSync = require('browser-sync');
var chalk = require('chalk');
var ncp = require('ncp');
var Table = require('cli-table');
var BShandler = require('./browser-sync-handler');
var ChromeTesterClient = require('./tester/chrome-tester-client');
var ChromeTesterServer = require('./tester/chrome-tester-server');
var LeenaConfiguration = require('./config');
var LeenaContext = require('./context/context');
var logger = require('./logger');
var utils = require('./utils');
var bsWatcher = browserSync.create('Watcher');
var bsWebServer = browserSync.create('Web Server');
function initialize(pathConfigFile, smtSolver) {
    var JSONcontent;
    var contentFile;
    var leenaConfig;
    var errors;
    var watcher;
    var webServer;
    var chromeServer;
    var leenaContext;
    contentFile = utils.readFile(pathConfigFile);
    if (contentFile === null) {
        throw new Error('Unable to read the config file "' + pathConfigFile + '"');
    }
    try {
        JSONcontent = JSON.parse(contentFile);
        leenaConfig = new LeenaConfiguration(JSONcontent);
        errors = leenaConfig.parseJSONObject(smtSolver);
        if (errors.length > 0) {
            for (var k = 0, lengthE = errors.length; k < lengthE; k++) {
                logger.error(errors[k]);
            }
            process.exit();
        }
    }
    catch (e) {
        logger.error('Unable to parse config file: ' + e.message);
        process.exit();
    }
    chromeServer = new ChromeTesterServer({
        hostname: leenaConfig.chromeTester.debuggingProtocol.hostname,
        port: leenaConfig.chromeTester.debuggingProtocol.port
    });
    chromeServer.updateConfiguration(leenaConfig);
    chromeServer.listen({
        hostname: leenaConfig.chromeTester.testerServer.hostname,
        port: leenaConfig.chromeTester.testerServer.port
    }, function (err) {
        if (err) {
            logger.error('Unable to connect to the Chrome instance');
            process.exit();
        }
        var source = leenaConfig.browserSync.watcher.server;
        var destination = leenaConfig.browserSync.webServer.server;
        ncp.ncp(source, destination, function (error) {
            if (error) {
                var errorMessage = 'Unable to copy application from "' +
                    leenaConfig.browserSync.watcher.server + '" to "' +
                    leenaConfig.browserSync.webServer.server + '"';
                logger.error(errorMessage);
                process.exit();
            }
            try {
                instrumentFileToTest(leenaConfig);
            }
            catch (e) {
                logger.error(e.message);
                process.exit();
            }
            try {
                var chromeClient = new ChromeTesterClient({
                    hostname: leenaConfig.chromeTester.testerServer.hostname,
                    port: leenaConfig.chromeTester.testerServer.port
                });
                logLeenaConfiguration(leenaConfig);
                logger.info('Application copied successfully');
                logger.info('SMT solver: ' + leenaConfig.solver.name);
                var url = leenaConfig.browserSync.webServer.server;
                chromeClient.setUrl(url, function (err, res) {
                    if (err) {
                        logger.error('Unable to set the url on the Chrome instance (url = "' + url + '")');
                    }
                    else {
                        try {
                            leenaContext = initContext(leenaConfig);
                            leenaContext.setChromeServer(chromeServer);
                            initWatcher(leenaConfig, leenaContext, chromeServer);
                        }
                        catch (e) {
                            logger.error(e.message);
                        }
                    }
                });
            }
            catch (e) {
                logger.error(e.message);
                process.exit();
            }
        });
    });
}
exports.initialize = initialize;
function instrumentFileToTest(leenaConfig) {
    for (var k = 0; k < leenaConfig.files.length; k++) {
        var file_ = leenaConfig.files[k].tempPath;
        var instrumentedCode = utils.getInstrumentedSource(file_);
        if (instrumentedCode === null) {
            throw new Error('Unable to instrument "' + file_ + '"');
        }
        if (!utils.writeOnFile(file_, instrumentedCode)) {
            throw new Error('Unable to write instrumented code in "' + file_ + '"');
        }
    }
}
function initContext(leenaConfig) {
    var leenaContext = new LeenaContext(leenaConfig);
    for (var k = 0; k < leenaConfig.files.length; k++) {
        try {
            leenaContext.handleProperty('add', {
                pathFile: path.normalize(leenaConfig.files[k].originalPath),
                pathTempFile: path.normalize(leenaConfig.files[k].tempPath),
                fileToTest: true
            });
        }
        catch (e) {
            throw e;
        }
    }
    return leenaContext;
}
function initWatcher(leenaConfig, leenaContext, chromeServer) {
    try {
        bsWatcher.init({
            port: leenaConfig.browserSync.watcher.port,
            ui: {
                port: leenaConfig.browserSync.watcher.uiPort
            },
            logLevel: 'silent',
            files: [
                {
                    match: [
                        [
                            leenaConfig.browserSync.watcher.server,
                            '**',
                            '*'
                        ].join(path.sep)
                    ],
                    fn: function (event, file) {
                        var retValue;
                        try {
                            retValue = BShandler.handleEvent(event, file, leenaConfig);
                            leenaContext.handleProperty(event, retValue);
                        }
                        catch (e) {
                            logger.error(e.message);
                        }
                    },
                    options: {
                        ignoreInitial: true
                    }
                }
            ]
        });
    }
    catch (e) {
        throw new Error('Unable to initialize the watcher');
    }
}
function logLeenaConfiguration(leenaConfiguration) {
    var table = new Table({});
    table.push([
        chalk.bold.green('Service'),
        chalk.bold.green('IP/Path'),
        chalk.bold.green('Port')
    ], [
        'Watcher',
        leenaConfiguration.browserSync.watcher.server,
        [
            '{',
            leenaConfiguration.browserSync.watcher.port,
            ', ',
            leenaConfiguration.browserSync.watcher.uiPort,
            '}'
        ].join('')
    ], [
        'Web Server',
        leenaConfiguration.browserSync.webServer.server,
        [
            '{',
            leenaConfiguration.browserSync.webServer.port,
            ', ',
            leenaConfiguration.browserSync.webServer.uiPort,
            '}'
        ].join('')
    ], [
        'Chrome Tester Server',
        leenaConfiguration.chromeTester.testerServer.hostname,
        leenaConfiguration.chromeTester.testerServer.port
    ], [
        'Chrome Remote Protocol',
        leenaConfiguration.chromeTester.debuggingProtocol.hostname,
        leenaConfiguration.chromeTester.debuggingProtocol.port
    ]);
    console.log(table.toString());
}
