/**
 * Copyright 2013 vtt.js Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var autoKeyword = "auto";
var directionSetting = {
  "": true,
  "lr": true,
  "rl": true
};
var alignSetting = {
  "start": true,
  "middle": true,
  "end": true,
  "left": true,
  "right": true
};

function findDirectionSetting(value) {
  if (typeof value !== "string") {
    return false;
  }
  var dir = directionSetting[value.toLowerCase()];
  return dir ? value.toLowerCase() : false;
}

function findAlignSetting(value) {
  if (typeof value !== "string") {
    return false;
  }
  var align = alignSetting[value.toLowerCase()];
  return align ? value.toLowerCase() : false;
}

function extend(obj) {
  var i = 1;
  for (; i < arguments.length; i++) {
    var cobj = arguments[i];
    for (var p in cobj) {
      obj[p] = cobj[p];
    }
  }

  return obj;
}

function VTTCue(startTime, endTime, text) {
  var cue = this;
  var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
  var baseObj = {};

  if (isIE8) {
    cue = document.createElement('custom');
  } else {
    baseObj.enumerable = true;
  }

  /**
   * Shim implementation specific properties. These properties are not in
   * the spec.
   */

  // Lets us know when the VTTCue's data has changed in such a way that we need
  // to recompute its display state. This lets us compute its display state
  // lazily.
  cue.hasBeenReset = false;

  /**
   * VTTCue and TextTrackCue properties
   * http://dev.w3.org/html5/webvtt/#vttcue-interface
   */

  var _id = "";
  var _pauseOnExit = false;
  var _startTime = startTime;
  var _endTime = endTime;
  var _text = text;
  var _region = null;
  var _vertical = "";
  var _snapToLines = true;
  var _line = "auto";
  var _lineAlign = "start";
  var _position = 50;
  var _positionAlign = "middle";
  var _size = 50;
  var _align = "middle";

  Object.defineProperty(cue,
    "id", extend({}, baseObj, {
      get: function() {
        return _id;
      },
      set: function(value) {
        _id = "" + value;
      }
    }));

  Object.defineProperty(cue,
    "pauseOnExit", extend({}, baseObj, {
      get: function() {
        return _pauseOnExit;
      },
      set: function(value) {
        _pauseOnExit = !!value;
      }
    }));

  Object.defineProperty(cue,
    "startTime", extend({}, baseObj, {
      get: function() {
        return _startTime;
      },
      set: function(value) {
        if (typeof value !== "number") {
          throw new TypeError("Start time must be set to a number.");
        }
        _startTime = value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "endTime", extend({}, baseObj, {
      get: function() {
        return _endTime;
      },
      set: function(value) {
        if (typeof value !== "number") {
          throw new TypeError("End time must be set to a number.");
        }
        _endTime = value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "text", extend({}, baseObj, {
      get: function() {
        return _text;
      },
      set: function(value) {
        _text = "" + value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "region", extend({}, baseObj, {
      get: function() {
        return _region;
      },
      set: function(value) {
        _region = value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "vertical", extend({}, baseObj, {
      get: function() {
        return _vertical;
      },
      set: function(value) {
        var setting = findDirectionSetting(value);
        // Have to check for false because the setting an be an empty string.
        if (setting === false) {
          throw new SyntaxError("An invalid or illegal string was specified.");
        }
        _vertical = setting;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "snapToLines", extend({}, baseObj, {
      get: function() {
        return _snapToLines;
      },
      set: function(value) {
        _snapToLines = !!value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "line", extend({}, baseObj, {
      get: function() {
        return _line;
      },
      set: function(value) {
        if (typeof value !== "number" && value !== autoKeyword) {
          throw new SyntaxError("An invalid number or illegal string was specified.");
        }
        _line = value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "lineAlign", extend({}, baseObj, {
      get: function() {
        return _lineAlign;
      },
      set: function(value) {
        var setting = findAlignSetting(value);
        if (!setting) {
          throw new SyntaxError("An invalid or illegal string was specified.");
        }
        _lineAlign = setting;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "position", extend({}, baseObj, {
      get: function() {
        return _position;
      },
      set: function(value) {
        if (value < 0 || value > 100) {
          throw new Error("Position must be between 0 and 100.");
        }
        _position = value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "positionAlign", extend({}, baseObj, {
      get: function() {
        return _positionAlign;
      },
      set: function(value) {
        var setting = findAlignSetting(value);
        if (!setting) {
          throw new SyntaxError("An invalid or illegal string was specified.");
        }
        _positionAlign = setting;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "size", extend({}, baseObj, {
      get: function() {
        return _size;
      },
      set: function(value) {
        if (value < 0 || value > 100) {
          throw new Error("Size must be between 0 and 100.");
        }
        _size = value;
        this.hasBeenReset = true;
      }
    }));

  Object.defineProperty(cue,
    "align", extend({}, baseObj, {
      get: function() {
        return _align;
      },
      set: function(value) {
        var setting = findAlignSetting(value);
        if (!setting) {
          throw new SyntaxError("An invalid or illegal string was specified.");
        }
        _align = setting;
        this.hasBeenReset = true;
      }
    }));

  /**
   * Other <track> spec defined properties
   */

  // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state
  cue.displayState = undefined;

  if (isIE8) {
    return cue;
  }
}

/**
 * VTTCue methods
 */

VTTCue.prototype.getCueAsHTML = function() {
  // Assume WebVTT.convertCueToDOMTree is on the global.
  return WebVTT.convertCueToDOMTree(window, this.text);
};

module.exports = VTTCue;
