/// <reference path="PhantomOutput.js"/>

global.PhantomMeasurer = function PhantomMeasurer(console, stdin, pageFactory) {
    this._console = console;
    this._stdin = stdin;
    this._pageFactory = pageFactory;
}

PhantomMeasurer.prototype = {
    waitForInputThenMeasure: function () {
        if (!this._page) {
            var self = this;
            this._page = this._createPage();
            this._page.onError = function (error, trace) {
                self.onError(error, trace);
            };
            this._page.onMessage = function (message) {
                self.onMessage(message);
            };
            this._page.onConsoleMessage = function (message) {
                self.onMessage(message);
            };
        }

        var input = this._stdin.readLine();
        if (input.length > 0) {
            var htmlObj = JSON.parse(input);
            if(htmlObj.dataFile){ // used when Debug manually.
                var fs = require('fs');
                input = fs.read(htmlObj.dataFile)
                htmlObj = JSON.parse(input);
            }

            var html = htmlObj.Html;
            var timeout = htmlObj.Timeout;
            var measurementFunc = this[htmlObj.MeasurementFunctionName];
            this._output = new PhantomOutput(htmlObj.CoherenceId);
            this._startMeasuring(html, timeout, measurementFunc);
        }
    },

    onError: function (text, trace) {
        this._output.errors.push({ message: text, trace: trace });
    },

    onMessage: function (text) {
        this._output.messages.push(text);
    },

    _startMeasuring: function (html, timeout, measurementFunc) {
        var self = this;

        this._timeoutCheckId = setTimeout(function () {
            self._onMeasurementFailed();
        }, timeout);

        this._page.onCallback = function () {
            self._onPhantomCallback(measurementFunc);
        };
        this._page.setContent(html, "http://localhost");
    },

    _createPage: function () {
        var page = this._pageFactory();
        page.viewportSize = { width: 1920, height: 1080 };
        return page;
    },

    _onPhantomCallback: function (measurementFunc) {
        if (!this._timeoutCheckId)
            return;

        clearTimeout(this._timeoutCheckId);

        this._output.setResult(this._page.evaluate(measurementFunc));
        this._outputAndWaitForNewInput();
    },

    _onMeasurementFailed: function () {
        this._timeoutCheckId = null;

        this._output.errors.push({ message: "Page failed to load when measuring.", trace: [] });
        this._outputAndWaitForNewInput();
    },

    _outputAndWaitForNewInput: function () {
        this._console.log(JSON.stringify(this._output));
        this.waitForInputThenMeasure();
    },

    MeasureHeight: function () {
        return document.querySelector('.print-content-container').getBoundingClientRect().height;
    },

    MeasureHeaderFooter: function () {
        var headerHeight = document.querySelectorAll('.header')[0].offsetHeight;
        var footerHeight = document.querySelectorAll('.footer')[0].offsetHeight;
        return {
            HeaderHeight: headerHeight,
            FooterHeight: footerHeight
        };
    },

    MeasurePivotTable: function () {
        return new Zap.PhantomPivotTableDimensionsBuilder().buildFromPivotTable($('table.pt'));
    },

    MeasureScorecard: function () {
        var scorecardTable = document.querySelector('.scorecard-table');
        var scorecardTableStyle = window.getComputedStyle(scorecardTable);
        var borderLeft = parseInt(scorecardTableStyle.borderLeftWidth);
        var borderTop = parseInt(scorecardTableStyle.borderTopWidth);
        var borderRight = parseInt(scorecardTableStyle.borderRightWidth);
        var borderBottom = parseInt(scorecardTableStyle.borderBottomWidth);

        var headerRowHeight = document.querySelector('thead tr').offsetHeight;;
        var row = document.querySelector('tbody tr');
        var rowHeight = row ? row.offsetHeight : 0;

        var columnWidths = {};
        var headers = document.querySelectorAll('.scorecard-header');
        for (var i = 0; i < headers.length; i++) {
            var header = headers[i];
            var columnName = header.className.split(' ')[1];

            columnWidths[columnName] = header.offsetWidth;
        }

        return {
            HeaderRowHeight: headerRowHeight,
            RowHeight: rowHeight,
            ColumnWidths: columnWidths,
            TotalBorderWidth: borderLeft + borderRight,
            TotalBorderHeight: borderTop + borderBottom
        };
    }
};
