/*jshint sub:true, eqnull:true, browser:true */
/*globals console */
//
// Core environment setup for our JS
//

// = require cookie

// strings to support closure compiler advanced mode
window['Twitch'] = window['Twitch'] || {};

(function (Twitch, undefined) {
  "use strict";
  // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
  Twitch.deployFlavor = SiteOptions.deploy_flavor;
  // jscs:enable requireCamelCaseOrUpperCaseIdentifiers

  // TODO: Kick this into a separate file when we have true modules instead of
  // sprockets.
  // Logger: Small wrapper for logging functions it automatically binds and eats
  // the console that was passed to it, allowing us to enable and disable
  // logging at runtime.
  var FUNCTION_NAMES = ["log", "debug", "info", "warn", "error"];
  var Logger = function (options) {
    options = options || {};
    this.enabled = !!options.enabled;
    this.console = options.console;
    if (!this.console) {
      console.error("Logger argument missing: console");
      return;
    }

    this.consoleFns = {};
    for (var i = 0; i < FUNCTION_NAMES.length; i++) {
      var name = FUNCTION_NAMES[i];
      this.consoleFns[name] = this.console[name] || function () {};
      this.console[name] = this[name].bind(this);
    }
  };

  Logger.prototype.enable = function () {
    this.enabled = true;
  };

  Logger.prototype.disable = function () {
    this.enabled = false;
  };

  // Lets one unbind this Logger from the console that it consumed.
  Logger.prototype.restoreConsole = function () {
    // window.console can be undefined in IE9, don't restore when it is
    if (!this.console) { return; }
    for (var i = 0; i < FUNCTION_NAMES.length; i++) {
      var name = FUNCTION_NAMES[i];
      this.console[name] = this.consoleFns[name];
    }
  };

  var bindFunction = function (functionName) {
    Logger.prototype[functionName] = function () {
      if (this.enabled || functionName === 'log') {
        var args = Array.prototype.slice.call(arguments, 0);
        // console methods in IE9 do not have .apply defined
        if (this.consoleFns[functionName].apply) {
          this.consoleFns[functionName].apply(this.console, args);
        }
      }
    };
  };

  // Bind the actual console functions to be enabled gated passthroughs
  for (var i = 0; i < FUNCTION_NAMES.length; i++) {
    var name = FUNCTION_NAMES[i];
    bindFunction(name);
  }


  cookie.defaults = {
    path: "/"
  };

  if (Twitch.deployFlavor === "production") {
    cookie.defaults["domain"] = ".twitch.tv";
  }

  // Stub console to avoid errors on older browsers
  if (!window['console']) {
    window['console'] = {};
  }

  Twitch.logging = new Logger({
    enabled: Twitch.deployFlavor !== "production",
    console: window['console']
  });

  // Mixins!
  // Can pass in one or many objects to add to Twitch
  // Twitch.mixin({cat: 'dog'}, {friend: 'foe'})
  Twitch.mixin = function (src) {
    var objects = Array.prototype.slice.call(arguments),
      source;

    for (var i = 0, len = objects.length; i < len; i++) {
      source = objects[i];
      for (var property in source) {
        if (source.hasOwnProperty(property)) {
          Twitch[property] = source[property];
        }
      }
    }

    return Twitch;
  };

  // Similar to .mixin, but does not assume base
  // object is Twitch.
  // As soon as the property is filled, further
  // defaults will have no effect.
  // Useful for merging object properties with
  // defaults. See underscore.js's defaults function
  // > Twitch.defaults({fast: true}, {fast: false, bar: 1})
  // {fast: true, bar: 1}
  Twitch.defaults = function (obj) {
    var objects = Array.prototype.slice.call(arguments, 1),
      source;

    for (var i = 0, len = objects.length; i < len; i++) {
      source = objects[i];
      for (var property in source) {
        if (source.hasOwnProperty(property) &&
            obj[property] == null) {
          obj[property] = source[property];
        }
      }
    }

    return obj;
  };

})(Twitch);
