/*******************************************************************************
 * Copyright (c) 2009, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IBM Corporation - initial API and implementation
 *******************************************************************************/ 
//
// Ad-hoc codes to bridge the gap between the HTML5 spec and browser implementations
//
if (typeof TextTrack == 'undefined') {
  (function () {
    TextTrack = function (kind, label, language) { // See: http://dev.w3.org/html5/spec/media-elements.html#texttrack
      this.kind = kind;
      this.label = label;
      this.language = language;
      this.mode = TextTrack.HIDDEN;
      this.cues = new TextTrackCueList();
      this.activeCues = new TextTrackCueList();
    };

    TextTrack.DISABLED = 0;
    TextTrack.HIDDEN = 1;
    TextTrack.SHOWING = 2;

    TextTrack.prototype.addCue = function (cue) {
      cue.track = this;
      this.cues.__addCue__(cue);
    };

    TextTrack.prototype.removeCue = function (cue) {
      cue.track = null;
      this.cues.__removeCue__(cue);
    };

    TextTrack.prototype.toString = function () {
      return 'TextTrack <' + this.kind + '> ' + this.label + ' (' + this.language + ') : ' + this.cues;
    };

    TextTrackList = function () { // See: http://dev.w3.org/html5/spec/media-elements.html#texttracklist
      var list = [];

      list.toString = function () {
        return 'TextTrackList [\n\t' + this.join(',\n\t') + '\n]';
      };

      return list;
    };

/*  TextTrackList = function () {}; // not working on IE

    TextTrackList.prototype = [];*/

    TextTrackCue = function (id, startTime, endTime, text, settings, pauseOnExit) { // See: http://dev.w3.org/html5/spec/media-elements.html#texttrackcue
      this.id = id;
      this.startTime = startTime;
      this.endTime = endTime;
      this.text = text;
      this.settings = settings || '';
      this.pauseOnExit = pauseOnExit || false;
    };

    TextTrackCue.prototype.toString = function () {
      return 'TextTrackCue <' + this.id + '> ' + this.startTime + ' -> ' + this.endTime + ' : ' + this.text + (this.pauseOnExit ? ' * pause-on-exit * ' : ' ');
    };

    TextTrackCueList = function () { // See: http://dev.w3.org/html5/spec/media-elements.html#texttrackcuelist
      var list = [];

      list.getCueById = function (id) {
        for (var i = 0; i < this.length; ++i) {
          var e = this[i];

          if (e.id == id) {
            return e;
          }
        }

        return null;
      };

      list.__addCue__ = function (cue) {
        this.push(cue);
      };

      list.__removeCue__ = function (cue) {
        for (var i = 0; i < this.length; ++i) {
          if (this[i] === cue) {
            this.splice(i--, 1);
          }
        }
      };

      list.toString = function () {
        return 'TextTrackCueList [\n\t' + this.join(',\n\t') + '\n]';
      };

      return list;
    };

/*  TextTrackCueList = function () {}; // not working on IE

    TextTrackCueList.prototype = [];

    TextTrackCueList.prototype.getCueById = function (id) {
      for (var i = 0; i < this.length; ++i) {
        var e = this[i];

        if (e.id == id) {
          return e;
        }
      }

      return null;
    };

    TextTrackCueList.prototype.__addCue__ = function (cue) {
      this.push(cue);
    };

    TextTrackCueList.prototype.__removeCue__ = function (cue) {
      for (var i = 0; i < this.length; ++i) {
        if (this[i] === cue) {
          this.splice(i--, 1);
        }
      }
    };

    TextTrackCueList.prototype.toString = function () {
      return 'TextTrackCueList [\n\t' + this.join(',\n\t') + '\n]';
    };*/

    var fixMediaElement = function (m) {
      m.textTracks = new TextTrackList();
      m.addTextTrack = addTextTrack;
      m.__lastTime__ = m.currentTime;
      m.addEventListener('timeupdate', updateCues, false);
      m.addEventListener('seeked', updateCues, false);
    };

    var fixTrackElement = function (t) {
      t.kind = t.getAttribute('kind');
      t.src = t.getAttribute('src');
      t.srclang = t.getAttribute('srclang');
      t.label = t.getAttribute('label');
      t['default'] = t.getAttribute('default') != null; // .default causes an error in IE

      if (!t.dataset) {
        var d = {};
        var a = t.attributes;
        
        for (var i = 0; i < a.length; ++i) {
          if (a[i].name.indexOf('data-') == 0) {
            d[a[i].name.substr(5)] = a[i].value;
          }
        }
        
        t.dataset = d;
      }
    };

    var addTextTrack = function (kind, label, language) { // HTMLMediaElement#addTextTrack
      var t = new TextTrack(kind, label, language);
      this.textTracks.push(t);
      return t;
    };

    var updateCues = function (e) { // http://dev.w3.org/html5/spec/media-elements.html#media-playback
      var video = e.target;

      var currentTime = video.currentTime;
      var lastTime = video.__lastTime__; video.__lastTime__ = currentTime;
      var isMonotonicIncrease = currentTime > lastTime && currentTime <= lastTime + .5; // major browsers fire timeupdate events every 250 ms

      var currentCues = [];
      var otherCues = [];
      var conflicted = false;

      var tracks = video.textTracks;

      for (var i = 0; i < tracks.length; ++i) {
        var t = tracks[i];

        if (t.mode != TextTrack.DISABLED) {
          var cues = t.cues;

          for (var j = 0; j < cues.length; ++j) {
            var c = cues[j];

            if (c.startTime <= currentTime && c.endTime > currentTime) {
              currentCues.push(c);
              c.__missed__ = false;
              conflicted = conflicted || !c.__active__;
            }
            else {
              otherCues.push(c);
              c.__missed__ = isMonotonicIncrease && c.startTime >= lastTime && c.endTime <= currentTime;
              conflicted = conflicted || c.__active__ || c.__missed__;
            }
          }
        }
      }

      if (!conflicted) {
        return;
      }

      var events = [];

      for (var i = 0; i < otherCues.length; ++i) {
        var c = otherCues[i];

        if (c.pauseOnExit && (c.__active__ || c.__missed__)) {
          video.pause();
        }

        if (c.__missed__) {
          events.push({ type: 'enter', timeStamp: c.startTime, target: c });
        }

        if (c.__active__ || c.__missed__) {
          events.push({ type: 'exit', timeStamp: c.endTime, target: c });
        }

        c.__active__ = false;
        c.track.activeCues.__removeCue__(c);
      }

      for (var i = 0; i < currentCues.length; ++i) {
        var c = currentCues[i];

        if (!c.__active__) {
          events.push({ type: 'enter', timeStamp: c.startTime, target: c });
        }

        c.__active__ = true;
        c.track.activeCues.__addCue__(c);
      }

      events.sort(function (a, b) { return a.timeStamp - b.timeStamp });

      for (var i = 0; i < events.length; ++i) {
        var e = events[i];
        var f = e.target['on' + e.type];

        if (f) {
          f.call(e.target, e);
        }
      }
    };

    var videoElems = document.getElementsByTagName('video');

    for (var i = 0; i < videoElems.length; ++i) {
      fixMediaElement(videoElems[i]);
    }

    var audioElems = document.getElementsByTagName('audio');

    for (var i = 0; i < audioElems.length; ++i) {
      fixMediaElement(audioElems[i]);
    }

    var trackElems = document.getElementsByTagName('track');

    for (var i = 0; i < trackElems.length; ++i) {
      var t = trackElems[i];
      fixTrackElement(t);
      t.track = t.parentNode.addTextTrack(t.kind, t.label, t.srclang);
    }
  })();
}

if (typeof MediaController == 'undefined') {
  (function () {
    MediaController = function () {}; // See: http://dev.w3.org/html5/spec/media-elements.html#mediacontroller

    MediaController.prototype.__syncTime__ = function (kicker) {
      if (kicker.__seekedForSync__) {
        kicker.__seekedForSync__ = false;
        return;
      }
      
      var slaveElems = getSlaveElementsOf(this);
      var currentTime = kicker.currentTime;
      
      for (var i = 0; i < slaveElems.length; ++i) {
        var s = slaveElems[i];
        
        if (s !== kicker) {
          s.__seekedForSync__ = true;
          s.currentTime = currentTime;
        }
      }
    };

    MediaController.prototype.__syncPlayback__ = function (kicker) {
      var slaveElems = getSlaveElementsOf(this);
      var readyState = 0;
      var paused = false;

      for (var i = 0; i < slaveElems.length; ++i) {
        var s = slaveElems[i];
        readyState = Math.max(readyState, s.readyState);
        paused = paused || s.ended || (s.paused && !s.__pausedForSync__);
      }

      this.readyState = readyState;
      this.paused = paused || readyState < 4; // < HAVE_ENOUGH_DATA

      for (var i = 0; i < slaveElems.length; ++i) {
        var s = slaveElems[i];

        if (this.paused) {
          if (!s.paused) {
            s.__pausedForSync__ = true;
            s.pause();
          }
          else {

          }
        }
        else {
          if (s.paused) {
            s.__pausedForSync__ = false;
            s.play();
          }
          else {
            s.__pausedForSync__ = false;
          }
        }
      }
    };

    var getSlaveElementsOf = function (controller) {
      var videoElems = document.getElementsByTagName('video');
      var audioElems = document.getElementsByTagName('audio');
      var slaveElems = [];

      for (var i = 0; i < videoElems.length; ++i) {
        var v = videoElems[i];

        if (v.controller === controller) {
          slaveElems.push(v);
        }
      }

      for (var i = 0; i < audioElems.length; ++i) {
        var a = audioElems[i];

        if (a.controller === controller) {
          slaveElems.push(a);
        }
      }

      return slaveElems;
    };

    var controllers = {};
    
    var fixMediaElement = function (m) {
      m.mediaGroup = m.getAttribute('mediagroup');
      
      if (!m.mediaGroup) {
        return;
      }
      
      m.controller = controllers[m.mediaGroup] || (controllers[m.mediaGroup] = new MediaController());
      m.addEventListener('seeked', syncTime, false);
      m.addEventListener('seeked', syncPlayback, false);
      m.addEventListener('playing', syncPlayback, false);
      m.addEventListener('waiting', syncPlayback, false);
      m.addEventListener('pause', syncPlayback, false);
      m.addEventListener('ended', syncPlayback, false);
      m.__pausedForSync__ = true;
    };

    var syncTime = function (e) {
      e.target.controller.__syncTime__(e.target);
    };
    
    var syncPlayback = function (e) {
      e.target.controller.__syncPlayback__(e.target);
    };
    
    var videoElems = document.getElementsByTagName('video');

    for (var i = 0; i < videoElems.length; ++i) {
      fixMediaElement(videoElems[i]);
    }

    var audioElems = document.getElementsByTagName('audio');

    for (var i = 0; i < audioElems.length; ++i) {
      fixMediaElement(audioElems[i]);
    }
  })();
}

