# Source: core/logger.js

    /**
     * @module montage/core/logger
     * @requires montage/core/core
     */
    var console = require('./extras/console').console;
    var Montage = require("./core").Montage;

    function getFunctionName(montageObject) {
        var aCaller = getFunctionName.caller.caller,
            aFunctionName;
        aFunctionName = aCaller.name;
        if (aFunctionName === "") {
            aFunctionName = "anonymous";
        }
        return aFunctionName;
    }

    function toTimeString(date) {
        if (date.getHours) {
            var hours = date.getHours(),
            mins = date.getMinutes(),
            secs = date.getSeconds();
            return (hours.length === 1 ? "0" + hours : hours) + ":" + (mins.length === 1 ? "0" + mins : mins) + ":" + (secs.length === 1 ? "0" + secs : secs) + "." + date.getMilliseconds();
        }
    }

    function consoleLog() {
        console.log(arguments);
    }

    var loggers = exports.loggers = {};

    var SOLARIZED_COLORS = {
        "base03":  "#002b36",
        "base02":  "#073642",
        "base01":  "#586e75",
        "base00":  "#657b83",
        "base0":   "#839496",
        "base1":   "#93a1a1",
        "base2":   "#eee8d5",
        "base3":   "#fdf6e3",
        "yellow":  "#b58900",
        "orange":  "#cb4b16",
        "red":     "#dc322f",
        "magenta": "#d33682",
        "violet":  "#6c71c4",
        "blue":    "#268bd2",
        "cyan":    "#2aa198",
        "green":   "#859900"
    };

    function addColorProperty (logger) {
        var _color = function (cssString) {
                this._color = cssString;
                return this;
            },
            _getColor = function (name) {
                return function () {
                    return logger.color(SOLARIZED_COLORS[name]);
                };
            };
        for (var name in SOLARIZED_COLORS) {
            if (SOLARIZED_COLORS.hasOwnProperty(name)) {
                _color[name] = _getColor(name);
            }
        }
        logger.color = _color;
    }

    /**
     * @class Logger
     * @extends Montage
     */
    var Logger = exports.Logger = Montage.specialize(/** @lends Logger# */ {

        constructor: {
            value: function Logger() {

                // Set Function.noop on construcot
                // to avoid issue with Object.create
                this.debug = Function.noop;
                this.error = Function.noop;

                addColorProperty(this);
            }
        },

        /**
         * @function
         * @param {string} name The name of the logger.
         * @param {State} [dontStoreState=false] If true, don't store the isDebug state of the logger in localStorage .
         * @returns itself
         */
        init: {
            value: function (name, onStateChange, dontStoreState) {
                var storedState;
                this.name = name;
                this._onStateChange = onStateChange;
                this._storeState = !dontStoreState;
                if (this._storeState && typeof localStorage !== "undefined") {
                    storedState = localStorage.getItem("_montage_logger_" + name);
                    if (storedState) {
                        this.isDebug = storedState === "true";
                    }
                }
                if (onStateChange) {
                    this._onStateChange(storedState === "true");
                }
                this.isError = true;
                return this;
            }
        },

        /**
         * @type {string}
         * @default {string} null
         */
        name: {
            value: null
        },

        /**
         * @private
         * @type {Array}
         * @default {Array} []
         */
        _buffer: {
            value: null
        },

        /**
         * @private
         * @type {Array}
         * @default {Array} []
         */
        buffer: {
            get: function() {
                return this._buffer || (this._buffer = []);
            }
        },

        /**
         * @type {Property}
         * @default {boolean} false
         */
        buffered: {
            value: false
        },

        /**
         * Log all the contents the logger's buffer.
         */
        flush: {
            value: function () {
                var buffer = this.buffer,
                    args,
                    i;
                for (i = 0; (args = buffer[i]); i++) {
                    this._formattedLog(args);
                }
                this.buffer.length = 0;
            }
        },

        /**
         * @type {boolean}
         */
        isDebug: {
            get: function () {
                return this.debug !== Function.noop;
            },
            set: function (value) {
                if (value) {
                    this.debug = this._consoleLogMontage;
                } else {
                    this.debug = Function.noop;
                }
            }

        },

        /**
         * @type {boolean}
         */
        isError: {
            get: function () {
                return this.error !== Function.noop;
            },
            set: function (value) {
                if (value) {
                    this.error = this._consoleLogMontage;
                } else {
                    this.error = Function.noop;
                }
            }
        },

        _consoleLogMontage: {
            value: function () {
                var firstArgument = arguments[0],
                    //jshint -W106
                    metadata = firstArgument._montage_metadata,
                    //jshint +W106
                    now = new Date();
                //[].unshift.call(arguments, toTimeString(now));
                // if the first argument is a Montage object, we replace it with the class and method's function name.
                if (metadata) {
                    Array.prototype.shift.call(arguments);
                    Array.prototype.unshift.call(arguments, metadata.objectName + "." + getFunctionName(firstArgument) + "()");
                    if (this.buffered) {
                        this.buffer.push(arguments);
                    } else {
                        this._formattedLog(arguments);
                    }
                } else {
                    if (this.buffered) {
                        this.buffer.push(arguments);
                    } else {
                        this._formattedLog(arguments);
                    }
                }
            }
        },

        _formattedLog: {
            value: function (args) {
                var firstArgument = args[0];
                if(exports.colors.isDebug && typeof firstArgument === "string") {
                    Array.prototype.splice.call(args, 0, 1, "%c"+firstArgument, this._logCss);
                }
                console.log.apply(console, args);
            }
        },

        __logCss: {
            value: null
        },

        _logCss: {
            get: function () {
                if(this.__logCss === null) {
                    this.__logCss = "";
                    if (this._color) {
                        this.__logCss += "color:" + this._color + ";";
                    } else {
                        this.__logCss += "color:black;";
                    }
                }
                return this.__logCss;
            }
        },

        /**
         * @function Logger#debug
         * @param {Function|String} object If the first argument is a function the logger with print its name
         * @param {string} [...]
         */
        debug: {
            value: null
        },

        /**
         * @function Logger#error
         * @param {Function|String} object If the first argument is a function the logger with print its name
         * @param {string} [...]
         */
        error: {
            value: null
        },

        /**
         * @function Logger#toTimeString
         * @description Prints the current time in format HH:MM:SS.000
         */
        toTimeString: {
            value: toTimeString
        },

        _storeState: {
            value: null
        },

        _onStateChange: {
            value: null
        }
    });

    /**
     * @function module:montage/core/logger#logger
     */
    exports.logger = function (loggerName, onStateChange, dontStoreState) {
        var logger;
        if (!(logger = loggers[loggerName])) {
            logger = new Logger().init(loggerName, onStateChange, dontStoreState);
            Montage.defineProperty(loggers, loggerName, {
                value: logger
            });
        }
        return logger;
    };

    exports.colors = exports.logger("colors");

    var LoggerUI = Montage.specialize( /** @lends LoggerUI# */{

        init: {
            value: function () {
                if (document.nativeAddEventListener) {
                    document.nativeAddEventListener("keyup", this, false);
                    document.nativeAddEventListener("keydown", this, false);
                } else {
                    document.addEventListener("keyup", this, false);
                    document.addEventListener("keydown", this, false);
                }
                return this;
            }
        },

        inspectorElement: {
            value: null
        },

        m_dontRemove: {
            value: null
        },

        titleHeader: {
            value: null
        },

        shown: {
            value: false
        },

        isCtrl: {
            value: false
        },

        isAlt: {
            value: false
        },

        keyup: {
            value: function (event) {
                if (event.which === 17) {
                    this.isCtrl = false;
                }
                if (event.which === 18) {
                    this.isAlt = false;
                }
            }
        },

        keydown: {
            value: function (event) {
                if (event.which === 17) {
                    this.isCtrl = true;
                }
                if (event.which === 18) {
                    this.isAlt = true;
                }
                if (event.which === 76 && this.isCtrl === true && this.isAlt === true) {
                    if (this.shown) {
                        this.hideInspector();
                    } else {
                        this.showInspector();
                    }
                    return false;
                }
            }
        },

        change: {
            value: function (event) {
                var value = event.target.checked,
                    name = event.target.value,
                    logger = loggers[name];
                logger.isDebug = value;
                if (logger._onStateChange) {
                    logger._onStateChange(value);
                }
                if (logger._storeState && typeof localStorage !== "undefined") {
                    localStorage.setItem("_montage_logger_" + name, value);
                }
            }
        },

        mouseup: {
            value: function (event) {
                this.hideInspector();
            }
        },

        showInspector: {
            value: function () {
                if (! this.inspectorElement) {
                    var i = 0,
                        iLogger,
                        div1,
                        h1,
                        div2,
                        label,
                        input,
                        storedValue,
                        storageKey,
                        loggerKeys,
                        style,
                        span;
                    this.m_dontRemove = document.getElementsByTagName("body")[0];
                    this.inspectorElement = document.createElement("div");
                    this.inspectorElement.id = "_montage_logger_inspector";
                    div1 = document.createElement("div");
                    this.inspectorElement.appendChild(div1);
                    div2 = document.createElement("div");
                    div1.appendChild(div2);
                    h1 = document.createElement("h1");
                    h1.className = "_montage_logger_inspector-title";
                    h1.textContent = "Logger Inspector";
                    this.titleHeader = h1;
                    div2.appendChild(h1);
                    loggerKeys = Object.keys(loggers);

                    for (i = 0; (iLogger = loggers[loggerKeys[i]]); i++) {
                        label = document.createElement("label");
                        input = document.createElement("input");
                        span = document.createElement("span");
                        label.className = "_montage_logger_inspector-content";
                        span.textContent = iLogger.name;
                        label.appendChild(input);
                        label.appendChild(span);
                        input.value = iLogger.name;
                        input.type = "checkbox";
                        input.checked = !!iLogger.isDebug;
                        storageKey = "_montage_logger_" + iLogger.name;
                        if (iLogger._storeState && typeof localStorage !== "undefined") {
                            storedValue = localStorage.getItem(storageKey);
                            if (!storedValue) {
                                localStorage.setItem(storageKey, iLogger.isDebug);
                            }
                        }
                        div2.appendChild(label);
                    }
                    style = document.createElement("style");
                    //YUCK!! I wish I could use a reel!!!
                    var styleTest = "#_montage_logger_inspector {";
                    styleTest += "    border: 1px solid rgba(15,15,15,0.4);";
                    styleTest += "    position: fixed;";
                    styleTest += "    right: 25px;";
                    styleTest += "    top: 25px;";
                    styleTest += "    -webkit-border-radius: 5px;";
                    styleTest += "    color: #dddddd;";
                    styleTest += '    font: 10px "Lucida Grande","Lucida Sans", sans;';
                    styleTest += "    background:-webkit-gradient(linear, left top, left bottom, from(rgba(15,15,15,0.75)), to(rgba(15,15,15,0.95)) );";
                    styleTest += "    -webkit-box-shadow: 0 0 15px rgba(0,0,0,.3);";
                    styleTest += "    width: 250px;";
                    styleTest += "}";
                    styleTest += "#_montage_logger_inspector div {";
                    styleTest += "    -webkit-border-radius: 5px;";
                    styleTest += "    background: -webkit-gradient(radial, 100 -60, 0, 125 -50, 125, from(rgba(255,255,255,0.00)), to(rgba(0,0,0,.2)), color-stop(1, rgba(0,0,0,.2)));";
                    styleTest += "}";
                    styleTest += "#_montage_logger_inspector div div {";
                    styleTest += "    background: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0.2)), to(rgba(0,0,0,.1)), color-stop(0.33, rgba(255,255,255,.01)), color-stop(0.33, rgba(50,50,50,1)) );";
                    styleTest += "    padding: 7px 10px;";
                    styleTest += "    -webkit-border-radius: 3px;";
                    styleTest += "    overflow-x: hidden;";
                    styleTest += "}";
                    styleTest += "._montage_logger_inspector-title {";
                    styleTest += "    color: rgba(255,255,255,0.9);";
                    styleTest += "    font-size: 13px;";
                    styleTest += "    margin: 0 0 11px 0;";
                    styleTest += "    padding: 0 0 0 5px;";
                    styleTest += "}";
                    styleTest += "._montage_logger_inspector-content {";
                    styleTest += "    padding: 0 0 0 20px;";
                    styleTest += "    margin: 0;";
                    styleTest += "    display: block;";
                    styleTest += "}";
                    style.textContent = styleTest;
                    document.head.appendChild(style);
                }
                this.shown = true;

                this.m_dontRemove.appendChild(this.inspectorElement);
                this.titleHeader.nativeAddEventListener("mouseup", this, false);
                this.inspectorElement.nativeAddEventListener("change", this, false);

            }
        },

        hideInspector: {
            value: function () {
                if (document.getElementById("_montage_logger_inspector")) {
                    this.shown = false;
                    this.m_dontRemove.removeChild(this.inspectorElement);
                    this.titleHeader.nativeRemoveEventListener("mouseup", this, false);
                    this.inspectorElement.nativeRemoveEventListener("change", this, false);
                }
            }
        },

        handleEvent: {
            enumerable: false,
            value: function (event) {
                if (this[event.type]) {
                    this[event.type](event);
                }
            }
        }
    });

    if (typeof window !== "undefined") {
        window.loggers = loggers;
        if (typeof localStorage !== "undefined") {
            new LoggerUI().init();
        }
    }