/**
 * Class: MN.Player
 * Main controller class for interaction with the player and player controls
 */
MN.Player = MN.Class(MN.EventSource);
_player = MN.Player.prototype;

/**
  * Function: initialize
  * Initializes the Player object and calls into the JSDK to create the Move Player plugin on the page
  *
  * Parameter:
  * playerId:String - div id for where the plugin should be placed
  * maxbitrate:String - the maximum bit rate that the player will play content at, set to 0 to use autostreamselect
  */
_player.initialize = function(playerId, maxbitrate){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.p = null; // JSDK player wrapper
	this.posIntvl = 0; // Position interval for tracking the position update
	this.currentUrl = ""; // Url of the currently playing clip
	this.maxbitrate = maxbitrate;
	
	// Setup the Move Player plugin
	MN.QVT.CreatePlayer(playerId, this.onPlayerLoaded, "100%", "100%");
}

/**
  * Function: onPlayerLoaded
  * Callback function for when the Move Player plugin finishes loading
  *
  * Parameter:
  * p:Object - player wrapper object from the SDK
  */
_player.onPlayerLoaded = function(p){
	// Assign the player wrapper to a class property
	this.p = p;
	
	// Set the player to cap the bit rate of the player based on player stage size
	if(this.maxbitrate == 0){
		this.p.autoSelectByStageSize(true);
	}else{
		this.p.Set("MaxBitrate",this.maxbitrate);
	}
	this.p.Set("Commit","");
	
	// Set mouse pointer to disappear after a certain amount of time of inactivity
	this.p.setUIInactivityDelay(5000);
	
	// Set the default player volume
	this.p.Volume(80);
	
	// Set substage styles if they exist
	// The substage is the window that is the actual video inside of the "stage" or plugin space.
	// It can be positioned anywhere in the stage and resized.
	// Note: It is always underneath all other overlays and not affected by z-index
	this.substage = this.p.OverlayManager.getOverlay("substage");
	if(typeof(MN.PlayerStyles.substage) != "undefined"){
		this.substage.update(MN.PlayerStyles.substage);
	}
	
	// Poll the position and duration
	this.posIntvl = setInterval(this.updatePosition,500);
	
	// Play default clip 
	this.play('http://aljazeera.cdn.cms.movenetworks.com/cms/publish3/source/qvt/1.qvt');	
	
	// Create controls object to allow the user to control the playback of the plugin
	this.controls = new MN.Player.Controls(this);
	this.controls.createControls();
	
	// Create and start timer for inactivity
	this.timer = new MN.Timer(this);
	this.timer.start();
	
	// Observe activity on the stage, reset timer
	this.stage = this.p.OverlayManager.getOverlay("stage");
	MN.Event.Observe(this.stage,"mousemove",this.resetTimer);
	
	// Create inactive overlay
	this.inactive = this.p.OverlayManager.createOverlay("Image", new Array(MN.PlayerStyles.inactive, {visibility:"hidden"}));
	this.p.OverlayManager.addOverlay("inactive", this.inactive);
	MN.Event.Observe(this.inactive,"click",this.resumePlayback);
}

/**
  * Function: resetTimer
  * When the mouse moves on the stage, the inactivity timer is reset
  */
_player.resetTimer = function(){
	this.timer.reset();
}

/**
  * Function: endPlayback
  * The user has been inactive for a set amount of time.
  * Pause the player and display a restart overlay
  */
_player.endPlayback = function(){
	this.p.Paused(true);
	this.inactive.update({visibility:"visible"});
}

/**
  * Function: resumePlayback
  * Resume playback from inactivity
  */
_player.resumePlayback = function(){
	this.CurrentPosition(-1);
	this.inactive.update({visibility:"hidden"});
	this.timer.start();
}

/**
  * Function: play
  * Plays a QMX/QVT file in the player
  *
  * Parameter:
  * url:String - QMX/QVT url to play
  * start:Number - start time
  * stop:Number - stop time
  */
_player.play = function(url, start, stop){
	// Store current url
	this.currentUrl = url;
	
	// Allow components to know of the new clip
	this.FireEvent("NewClip", url);
	
	// Call into the JSDK to player
	this.p.Play(url, start, stop);
}

/**
  * Function: updatePosition
  * Polls the current position and duration of the player and broadcasts that information
  */
_player.updatePosition = function(){
	if(this.p.qvt){
		this.FireEvent("CurrentPositionChanged", this.CurrentPosition(), this.Duration());
	}
}

/**
  * Function: Duration
  * Override the default p.Duration to account for live and show based timeline
  */
_player.Duration = function()
{
	// Check that player exists
	if (this.p)
	{
		var qvt = this.p.CurrentQVT();
		
		// Check that current QVT is or was live
		if (qvt.IsAnchored())
		{
			// Get current show
			var curShow = this.p.CurrentShow();
			var dur = this.p.Duration();
			var curShowStop = qvt.StopTime(curShow);
			var showStart = qvt.StartTime(curShow);
		
			// Calculate show duration
			// This case is when the current show is live
			if (curShowStop > dur)
			{
				var clipDur = dur - showStart;
			}
			else
			{
				var clipDur = curShowStop - showStart;
			}

			return clipDur;
		
		}
		else
		{
			// Normal VOD, use player duration
			return this.p.Duration();
		}
	}
}

/**
  * Function: CurrentPosition
  * Override the default p.CurrentPosition to account for live and show based timeline
  */
_player.CurrentPosition = function(value)
{
	// Check that player exists
	if (this.p)
	{
		var qvt = this.p.CurrentQVT();
		
		// Setting
		if (!isNaN(value))
		{
			// Check that current QVT is or was live
			if (qvt.IsAnchored() && value > -1)
			{
				var curShow = this.p.CurrentShow();
				var clipStart = qvt.StartTime(curShow);
				this.p.Set("OptimizeStartTime","1"); // 7.17 feature, allows for very fast scrub time, always used before setting CurrentPosition on the player
				this.p.CurrentPosition(clipStart + value);
				
			}
			else
			{
				// VOD or value is for live (-1)
				this.p.Set("OptimizeStartTime","1");
				this.p.CurrentPosition(value);
			}
		}
		else
		{	// Getting
			// Check that current QVT is or was live
			if (qvt.IsAnchored())
			{
				var curShow = this.p.CurrentShow();
				var pos = this.p.CurrentPosition();
				var clipStart = qvt.StartTime(curShow);
				var clipPos = pos - clipStart;
				return clipPos;
			}
			else
			{
				return this.p.CurrentPosition();
			}
		}
	}
}

/**
 * Class: MN.Player.Controls
 * Player controls class
 */
MN.Player.Controls = MN.Class(MN.EventSource);
_controls = MN.Player.Controls.prototype;

/**
  * Function: initialize
  * Initializes the Controls object and sets up the controls container
  *
  * Parameter:
  * player:Object - Move Player controller
  */
_controls.initialize = function(player){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	
	// Create Controls Container Overlay - this will contain all of the control overlay objects
	this.container = this.player.p.OverlayManager.createOverlay("", MN.PlayerStyles.controls);
	this.player.p.OverlayManager.addOverlay("controls", this.container);
}

/**
  * Function: createControls
  * Creates all available controls as determined by the Styles object
  */
_controls.createControls = function(){
	// Controls backgrounds
	this.controlsDark = this.player.p.OverlayManager.createOverlay("Image", MN.PlayerStyles.controlsDarkBack);
	this.container.addOverlay("controlsDark", this.controlsDark);
	this.controlsLight = this.player.p.OverlayManager.createOverlay("Image", MN.PlayerStyles.controlsLightBack);
	this.container.addOverlay("controlsLight", this.controlsLight);
	
	// PlayPause Object
	this.playPause = new MN.Player.PlayPause(this.player, this.container);
	
	// FFRW Object
	//this.ffRw = new MN.Player.FFRw(this.player, this.container);
	
	// prevNext Object
	//this.prevNext = new MN.Player.PrevNext(this.player, this.container);
	
	// Video info (time, status, bitrate)
	this.vidinfo = new MN.Player.VideoInfo(this.player, this.container);
	
	// FullScreen Object
	if(this.player.p.fullScreenSupported()){
		this.fullScreen = new MN.Player.FullScreen(this.player, this.container);
	}
	
	// Timeline Object
	//this.timeline = new MN.Player.TimelineSlider(this.player, this.container);
	
	// Volume Object
	this.volume = new MN.Player.VolumeSlider(this.player, this.container);
	
	// Go Live
	this.golive = new MN.Player.GoLive(this.player, this.container);
}

/**
 * Class: MN.Player.Button
 * General button component for Move Overlays
 */
MN.Player.Button = MN.Class(MN.EventSource);
_button= MN.Player.Button.prototype;

/**
  * Function: initialize
  * Initializes a basic button component with styles for four different states; default, hover, down and disabled.
  * The button has a main container that is used for positioning and sizing. 
  * It also provides a mask for cropping if a sprite is used for the states
  * If a null value is passed for any state, that state is not used for the button
  * The default state is required to have a style
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  * name:String - name of the new button overlay
  * clickCallback:Function - function to call when the button is clicked
  * buttonConfig:Array - config for the button
  * defaultConfig:Array - config for normal or default state of the image, required
  * hoverConfig:Array - config for hover state of the image, null or "undefined" = state is not used
  * downConfig:Array - config for down state of the image, null or "undefined" = state is not used
  * disabledConfig:Array - config for disabled state of the image, null or "undefined" = state is not used
  */
_button.initialize = function(player, parentContainer, name, clickCallback, buttonConfig, defaultConfig, hoverConfig, downConfig, disabledConfig){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	this.hoverState = false; // Flag if the state is active or not
	this.downState = false; // Flag if the state is active or not
	this.disabledState = false; // Flag if the state is active or not
	this.clickFunc = clickCallback; // Store the click callback
	
	// Set style configurations for the states
	this.defaultStyle = defaultConfig;
	this.hoverStyle = hoverConfig;
	if(typeof(this.hoverStyle) == "undefined"){
		this.hoverStyle = null;	
	}
	this.downStyle = downConfig;
	if(typeof(this.downStyle) == "undefined"){
		this.downStyle = null;	
	}
	this.disabledStyle = disabledConfig;
	if(typeof(this.disabledStyle) == "undefined"){
		this.disabledStyle = null;	
	}
	
	// Overlays
	this.button = this.player.p.OverlayManager.createOverlay("", buttonConfig);
	parentContainer.addOverlay(name, this.button);
	
	if(this.button != null){ // Overlay was added successfully
		// Image overlay that will change states based on the passed styles
		this.buttonImage = this.player.p.OverlayManager.createOverlay("Image", defaultConfig);
		this.button.addOverlay("background", this.buttonImage);
	
		// Events
		MN.Event.Observe(this.button,"rollover",this.rollOver);
		MN.Event.Observe(this.button,"rollout",this.rollOut);
		
		// Down
		MN.Event.Observe(this.button,"mousedown",this.mouseDown);
		MN.Event.Observe(this.button,"click",this.mouseClick);
	}
}

/**
  * Function: disableButton
  * Disable the button, sets the disabled state if available and prevents rollovers and clicks
  */
_button.disableButton = function(){
	this.disabledState = true;
	this.hoverState = false;
	this.downState = false;
	if(this.disabledStyle != null){
		this.buttonImage.set(new Array(this.defaultStyle, this.disabledStyle));
	}
}

/**
  * Function: enableButton
  * Enable the button, allows rollovers and clicks
  */
_button.enableButton = function(){
	this.disabledState = false;
	this.buttonImage.set(this.defaultStyle);
}

/**
  * Function: rollOver
  * Change to hover state if available
  */
_button.rollOver = function(){
	if(!this.disabledState && this.hoverStyle != null){
		this.hoverState = true;
		this.buttonImage.set(new Array(this.defaultStyle, this.hoverStyle));
	}
}

/**
  * Function: rollOut
  * Change to normal state if available and not disabled
  */
_button.rollOut = function(){
	if(!this.disabledState && this.hoverState){
		this.hoverState = false;
		this.downState = false;
		this.buttonImage.set(this.defaultStyle);
	}
}

/**
  * Function: mouseDown
  * Change to down state if available
  */
_button.mouseDown = function(){
	if(!this.disabledState && this.downStyle != null){
		this.downState = true;
		this.hoverState = false;
		this.buttonImage.set(new Array(this.defaultStyle, this.downStyle));
	}
}

/**
  * Function: mouseClick
  * Call click callback and change back to hover if available or normal if not
  */
_button.mouseClick = function(){
	if(!this.disabledState){
		this.downState = false;
		if(this.hoverStyle != null){
			this.hoverState = true;
			this.buttonImage.set(new Array(this.defaultStyle, this.hoverStyle));
		}else{
			this.buttonImage.set(this.defaultStyle);
		}
		if(this.clickFunc != null){
			this.clickFunc();
		}
	}
}

/**
  * Function: update
  * Updates the button container overlay
  *
  * Parameter:
  * configs:Array|Object - config attributes
  */
_button.update = function(configs){
	this.button.update(configs);
}

/**
 * Class: MN.Player.Slider
 * General horizontal slider component for Move Overlays
 */
MN.Player.Slider = MN.Class(MN.EventSource);
_slider= MN.Player.Slider.prototype;

/**
  * Function: initialize
  * Initializes a basic button component with styles for four different states; default, hover, down and disabled.
  * The button has a main container that is used for positioning and sizing. 
  * It also provides a mask for cropping if a sprite is used for the states
  * If a null value is passed for any state, that state is not used for the button
  * The default state is required to have a style
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  * name:String - name of the new slider overlay
  * areaConfig:Array - config for slider overlay
  * leadConfig:Array - config for the lead overlay (normally the background)
  * trailConfig:Array - config for the trail overlay (follows the scrubber)
  * leftEdgeConfig:Array - config for the left edge of the timeline
  * rightEdgeConfig:Array - config for the right edge of the timeline
  * scrubberConfig:Array - config for the scrubber box
  * scrubberNormalConfig:Array - config for the normal state of the scrubber
  * scrubberHoverConfig:Array - config for the hover state of the scrubber
  * scrubberDownConfig:Array - config for the down state of the scrubber
  */
_slider.initialize = function(player, parentContainer, name, areaConfig, leadConfig, trailConfig, leftEdgeConfig, rightEdgeConfig, scrubberConfig, scrubberNormalConfig, scrubberHoverConfig, scrubberDownConfig){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	this.scrubbing = false;
	
	// Overlays
	this.hitArea = this.player.p.OverlayManager.createOverlay("", areaConfig);
	parentContainer.addOverlay(name, this.hitArea);
	
	if(this.hitArea != null){ // Overlay was added successfully
		this.lead = this.player.p.OverlayManager.createOverlay("Image", leadConfig);
		this.hitArea.addOverlay("lead", this.lead);
		
		this.trail = this.player.p.OverlayManager.createOverlay("Image", trailConfig);
		this.hitArea.addOverlay("trail", this.trail);
		
		// Edges
		this.leftEdge = this.player.p.OverlayManager.createOverlay("Image", new Array(leftEdgeConfig, {visibility:"hidden"}));
		this.hitArea.addOverlay("ledge", this.leftEdge);
		this.rightEdge = this.player.p.OverlayManager.createOverlay("Image", new Array(rightEdgeConfig, {visibility:"hidden"}));
		this.hitArea.addOverlay("redge", this.rightEdge);
		
		this.scrubber = new MN.Player.Button(this.player, this.hitArea, "scrubber", null, scrubberConfig, scrubberNormalConfig, scrubberHoverConfig, scrubberDownConfig, null);
				
		// Reference to stage
		this.stage = this.player.p.OverlayManager.getOverlay("stage");
			
		// Drag-n-drop
		MN.Event.Observe(this.scrubber.button,"mousedown",this.startDrag);
		
		// Slider Click
		MN.Event.Observe(this.hitArea,"click",this.sliderClick);
		
		// Updates
		MN.Event.Observe(this.hitArea, "update", this.updateSliderUI);
		MN.Event.Observe(this.scrubber.button, "update", this.updateSliderUI);
		MN.Event.Observe(this.lead, "update", this.updateLeadUI);
	}
}

/**
  * Function: updateSliderUI
  * Updates the slider UI when a dependent overlay changes size or position
  */
_slider.updateSliderUI = function(){
	// Update slider lead width if slider width changes
	// Second condition avoids a jumping of the button when the overlays are first initialized
	if(this.hitArea.width - this.scrubber.button.width != this.lead.width && this.scrubber.button.width != 0){
		this.lead.update({width: (this.hitArea.width - this.scrubber.button.width) + "px"});
		// Show edges
		this.leftEdge.update({visibility:"visible"});
		this.rightEdge.update({visibility:"visible"});
	}	
	// Update lead and trail position if scrubber width changes
	if(Math.floor(this.scrubber.button.width/2) != this.lead.left){
		this.lead.update({left: Math.floor(this.scrubber.button.width/2) + "px"});
		this.trail.update({left: Math.floor(this.scrubber.button.width/2) + "px"});
	}
}

/**
  * Function: updateLeadUI
  * Fires event when lead changes
  */
_slider.updateLeadUI = function(){
	this.FireEvent("SliderLeadUIChanged");
}

/**
  * Function: startDrag
  * Called when the user begins dragging the slider's scrubber
  *
  * Parameter:
  * overlay:Object - scrubber object
  * j:Number - j relative position
  * k:Number - k relative position
  * x:Number - x absolute position
  * y:Number - y absolute position
  */
_slider.startDrag = function(overlay, j, k, x, y){
	this.scrubbing = true;
	this.FireEvent("ScrubbingChanged", this.scrubbing);
	MN.Event.Observe(this.stage,"mousemove",this.overlayMouseMove);
	MN.Event.Observe(this.stage,"mouseup",this.overlayMouseUp);
	MN.Event.Observe(this.stage,"rollout",this.overlayMouseUp);
	// Update the scrubber to the position of the mouse
	// This fixes an issue where the user mouses down and mouses up on the scrubber without moving. 
	// It doesn't register the click on the timeline because it believed the user was scrubbing
	this.overlayMouseMove(this.player.p.OverlayManager.getOverlay("stage"), x, y);
}

/**
  * Function: overlayMouseMove
  * Handler for mouse move event during dragging. Updates the scrubber and trail positions.
  *
  * Parameter:
  * overlay:Object - stage overlay object
  * x:Number - x relative position
  * y:Number - y relative position
  */
_slider.overlayMouseMove = function(overlay, x, y){
	var value = Math.floor(x) - this.lead.absoluteLeft; // Use abs here since x is based on stage
	if(value < 0){
		value = 0;	
	}
	if(value > this.lead.width){
		value = this.lead.width;	
	}
	
	this.trail.update({width: value + "px"});
	this.scrubber.update({left: value + "px"});
	this.FireEvent("ScrubberValue", value, "move");
}

/**
  * Function: overlayMouseUp
  * Called when the user is done dragging the scrubber
  */
_slider.overlayMouseUp = function(){
	this.scrubbing = false;
	this.FireEvent("ScrubbingChanged", this.scrubbing);
	MN.Event.StopObserving(this.stage,"mousemove",this.overlayMouseMove);
	MN.Event.StopObserving(this.stage,"mouseup",this.overlayMouseUp);
}

/**
  * Function: sliderClick
  * Called when the user clicks on the slider
  *
  * Parameter:
  * overlay:Object - overlay where the click occured
  * x:Number - x relative position of the click
  */
_slider.sliderClick = function(overlay, x){
	var value = Math.floor(x) - this.lead.left;
	if(value < 0){
		value = 0;	
	}
	if(value > this.lead.width){
		value = this.lead.width;	
	}
	this.trail.update({width: value + "px"});
	this.scrubber.update({left: value + "px"});
	this.FireEvent("ScrubberValue", value, "click");
}

/**
  * Function: getValue
  * Returns current value of trail width
  */
_slider.getValue = function(){
	return this.trail.width;
}

/**
  * Function: setValue
  * Updates the trail and scrubber to new value
  */
_slider.setValue = function(value){
	this.trail.update({width: value + "px"});
	this.scrubber.update({left: value + "px"});
	this.FireEvent("ScrubberValue", value, "set");
}

/**
 * Class: MN.Player.GoLive
 * Creates a button that allows the user to go to the "live" point in a live feed.
 */
MN.Player.GoLive= MN.Class(MN.EventSource);
_glive = MN.Player.GoLive.prototype;

/**
  * Function: initialize
  * Initializes a go live button
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_glive.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	
	// Overlays
	this.full = new MN.Player.Button(this.player, parentContainer, "golive", this.onClickGoLive, MN.PlayerStyles.goLive, MN.PlayerStyles.goLiveDefault, MN.PlayerStyles.goLiveHover, null, null);
}

// Click to go to full screen
_glive.onClickGoLive = function(){
	this.player.CurrentPosition(-1);
}

/**
 * Class: MN.Player.FullScreen
 * Creates fullscreen and normal screen overlay buttons to allow the user to toggle between the two screen modes
 */
MN.Player.FullScreen= MN.Class(MN.EventSource);
_fs = MN.Player.FullScreen.prototype;

/**
  * Function: initialize
  * Initializes a fullscreen/normalscreen toggle button
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_fs.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	
	// Overlays
	this.full = new MN.Player.Button(this.player, parentContainer, "fullscreen", this.onClickFullScreen, MN.PlayerStyles.full, MN.PlayerStyles.fullDefault, MN.PlayerStyles.fullHover, null, null);
	this.normal = new MN.Player.Button(this.player, parentContainer, "normalscreen", this.onClickNormalScreen, MN.PlayerStyles.normal, MN.PlayerStyles.normalDefault, MN.PlayerStyles.normalHover, null, null);
}

// Click to go to full screen
_fs.onClickFullScreen = function(){
	this.player.p.fullScreen(true);
}

// Click to go to normal screen
_fs.onClickNormalScreen = function(){
	this.player.p.fullScreen(false);
}

/**
 * Class: MN.Player.PlayPause
 * Button to play and pause the playback of the video. Reflects the current paused/un-paused state of the player.
 */
MN.Player.PlayPause = MN.Class(MN.EventSource);
_playPause= MN.Player.PlayPause.prototype;

/**
  * Function: initialize
  * Initializes a play/pause toggle button
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_playPause.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	this.playState = 0; // Current play state of the player
	this.curPos = 0; // Last known current position
	this.playPauseHover = false; // Flag if the user is currently hovering over the button
	this.seeking = false; // Flag if the player is seeking (ff/rw)
	
	// Overlays
	this.play = new MN.Player.Button(this.player, parentContainer, "play", this.onClick, MN.PlayerStyles.playPause, MN.PlayerStyles.playDefault, MN.PlayerStyles.playHover, null, null);
	this.pause = new MN.Player.Button(this.player, parentContainer, "pause", this.onClick, new Array(MN.PlayerStyles.playPause, {visibility:"hidden"}), MN.PlayerStyles.pauseDefault, MN.PlayerStyles.pauseHover, null, null);
	
	// Events Handlers
	MN.Event.Observe(this.player.p,"PlayStateChanged", this.onPlayStateChanged);
	MN.Event.Observe(this.player.p,"PausedChanged", this.checkPlayPause);
	MN.Event.Observe(this.player, "CurrentPositionChanged", this.updateCurrentPosition);
	MN.Event.Observe(this.player, "SeekingChanged", this.onSeekingChanged);
	
	// Setup handlers in the player for events fired in this component
	MN.Event.Observe(this, "stopSeeking", MN.MakeBound(this.player, function(){
		this.FireEvent("stopSeeking");
	}));
}

/**
  * Function: onPlayStateChanged
  * Save the new play state and check overlays to match it
  *
  * Parameter:
  * oldS:Number - Old play state
  * newS:Number - New play state
  */
_playPause.onPlayStateChanged = function(oldS, newS){
	this.playState = newS;
	this.checkPlayPause();
}

/**
  * Function: updateCurrentPosition
  * Save the latest current position
  *
  * Parameter:
  * newPos:Number - Current position
  */
_playPause.updateCurrentPosition = function(newPos){
	this.curPos = newPos;
}

/**
  * Function: onSeekingChanged
  * Verify the play state based on the seeking status of the player
  *
  * Parameter:
  * seek:Boolean - flag for seeking
  */
_playPause.onSeekingChanged = function(seek){
	this.seeking = seek;
	this.checkPlayPause(this.seeking);
}

/**
  * Function: onClick
  * Toggles the video between playing and paused
  */
_playPause.onClick = function(){
	// Video is currently in the PLAYING state
	if (this.playState == MN.QMP.PS.PLAYING)
	{
		// Video is seeking (ff/rw)
		if (this.seeking)
		{
			// Stop seeking if the user clicks "Play"
			this.FireEvent("stopSeeking");
			return;
		}
		this.togglePlayPause();
	}
	else if(this.playState == MN.QMP.PS.MediaEnded){
		// Video is ended, so restart
		this.player.CurrentPosition(-1);
	}
	else
	{
		//Not playing, setting the current position to the last known position will cause the player to play
		this.player.CurrentPosition(this.curPos);
	}
}

/**
  * Function: checkPlayPause
  * Called when the play state has changed or the video has change from/to a paused state.
  * This function will check the states and show the correct buttons
  *
  * Parameter:
  * paused:Boolean - flag if the player is paused or not
  */
_playPause.checkPlayPause = function(paused){
	
	// Set paused value if not already set
	if(typeof(paused) == "undefined" || paused == null){
		paused = this.player.p.Paused();
	}

	// Set the value of the button. Remember that if the video is paused, the user should see "Play" as an option and vice versa.
	if(this.playState == MN.QMP.PS.MediaEnded)
	{
		// Display the Play button if the user is at the end
		this.play.update({visibility:"visible"});
		this.pause.update({visibility:"hidden"});
	}else{
		if(paused){
			// Video is paused, display the play button
			this.play.update({visibility:"visible"});
			this.pause.update({visibility:"hidden"});
		}
		else{
			// Video is playing, display the pause button
			this.pause.update({visibility:"visible"});
			this.play.update({visibility:"hidden"});
		}
	}
}

/**
  * Function: togglePlayPause
  * Toggle the play/paused state of the player
  *
  * Parameter:
  * flag:Boolean - If not null, sets the Paused value to flag
  */
_playPause.togglePlayPause = function(flag){
	if (this.playState == MN.QMP.PS.PLAYING)
	{
		var paused = (flag) ? !flag : this.player.p.Paused();
		this.player.p.Paused(!paused);
	}
}

/**
 * Class: MN.Player.Status
 * Video playback status display
 */
MN.Player.Status = MN.Class(MN.EventSource);
_status = MN.Player.Status.prototype;

/**
  * Function: initialize
  * Initializes the video status display field
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_status.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	this.playState = 0; // Current play state of the player
	
	// Overlays
	this.txtField = this.player.p.OverlayManager.createOverlay("Text", new Array(MN.PlayerStyles.txt, MN.PlayerStyles.txtstatus));
	parentContainer.addOverlay("status", this.txtField);

	// Events
	MN.Event.Observe(this.player.p,"PlayStateChanged", this.onPlayStateChanged); 
	MN.Event.Observe(this.player.p,"PausedChanged", this.checkPlayPause); 
	MN.Event.Observe(this.player,"SeekingChanged", this.onSeekingChanged);
}

/**
  * Function: onPlayStateChanged
  * Called when the player changes play states
  *
  * Parameter:
  * oldS:Number - Old play state
  * newS:Number - New play state
  */
_status.onPlayStateChanged = function(oldS, newS){
	this.playState = newS;
	var stateStr = MN.QMP.PS[this.playState];
	var displayTxt = "video " + stateStr;
	this.txtField.setText(displayTxt.toLowerCase());
}

/**
  * Function: checkPlayPause
  * Called when the paused stated has changed
  *
  * Parameter:
  * paused:Boolean - flag if the player is paused or not
  */
_status.checkPlayPause = function(paused){
	
	// Set paused value
	if(paused == null){
		paused = this.player.p.Paused();
	}

	if (this.playState==MN.QMP.PS.PLAYING)
	{
		if(!paused){
			this.txtField.setText("video playing");
		}
		else{
			this.txtField.setText("video paused");
		}
	}
}

/**
  * Function: onSeekingChanged
  * Update seeking text based on seek status
  *
  * Parameter:
  * seek:Boolean - Flag for seeking
  * seekType:String - Rewind or Fast Forward
  * scrubSpeed:Number - 2,4,8,16 - speed of the scrub
  */
_status.onSeekingChanged = function (seek, seekType, scrubSpeed){
	if(!seek){
		var stateStr = MN.QMP.PS[this.playState];
		var displayTxt = "video " + stateStr;
		this.txtField.setText(displayTxt.toLowerCase());
	}
	else{
		var displayTxt = "video " + seekType + Math.abs(scrubSpeed) + "x";
		this.txtField.setText(displayTxt.toLowerCase());
	}
}


/**
 * Class: MN.Player.BitRate
 * Video bitrate display
 */
MN.Player.BitRate = MN.Class(MN.EventSource);
_bitrate = MN.Player.BitRate.prototype;

/**
  * Function: initialize
  * Initializes the video bitrate display field
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_bitrate.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	this.bitrate = 0; // Current bit rate of the player

	// Overlay
	this.txtField = this.player.p.OverlayManager.createOverlay("Text", new Array(MN.PlayerStyles.txt, MN.PlayerStyles.txtbitrate));
	parentContainer.addOverlay("bitrate", this.txtField);
	
	// Event Handler
	MN.Event.Observe(this.player.p,"BitRateChanged", this.onBitRateChanged);
}

/**
  * Function: onBitRateChanged
  * Called when the player changes bit rate
  *
  * Parameter:
  * newBR:Number - New bit rate
  */
_bitrate.onBitRateChanged = function(newBR){
	this.bitrate = newBR;
	if (!isNaN(this.bitrate)){
		this.txtField.setText(this.bitrate + " kbps");
	}
}

/**
 * Class: MN.Player.TimeDisplay
 * Video bitrate display
 */
MN.Player.TimeDisplay = MN.Class(MN.EventSource);
_timedisplay = MN.Player.TimeDisplay.prototype;

/**
  * Function: initialize
  * Video time display for current position out of duration
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_timedisplay.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;

	// Overlays
	this.txtField = this.player.p.OverlayManager.createOverlay("Text", new Array(MN.PlayerStyles.txt, MN.PlayerStyles.txttimedisplay));
	parentContainer.addOverlay("timedisplay", this.txtField);
	
	// Event Handlers
	MN.Event.Observe(this.player, "CurrentPositionChanged", this.update);
}

/**
  * Function: update
  * Updates the time display to reflect the position of the video out of the total duration
  *
  * Parameter:
  * pos:Number - current position in video playback
  * total:Number - total time in video playback
  */
_timedisplay.update = function (pos, total){
	var val = MN.ConvertToTimestamp(pos) + " / " + MN.ConvertToTimestamp(total);
	if(this.txtField.getText() != val){
		this.txtField.setText(val);
	}
}


/**
 * Class: MN.Player.VideoInfo
 * Information regarding video playback, time display and bitrate all in one text field
 */
MN.Player.VideoInfo = MN.Class(MN.EventSource);
_vidinfo = MN.Player.VideoInfo.prototype;

/**
  * Function: initialize
  * Initializes the video status display field
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_vidinfo.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	this.playState = 0; // Current play state of the player
	this.bitrate = ""; // Current bit rate of the player
	this.status = ""; // Current status 
	this.time = ""; // Current time
	
	// Overlays
	this.txtField = this.player.p.OverlayManager.createOverlay("Text", new Array(MN.PlayerStyles.txt, MN.PlayerStyles.txtvideoinfo));
	parentContainer.addOverlay("vidinfo", this.txtField);

	// Events
	MN.Event.Observe(this.player.p,"PlayStateChanged", this.onPlayStateChanged); 
	MN.Event.Observe(this.player.p,"PausedChanged", this.checkPlayPause); 
	MN.Event.Observe(this.player,"SeekingChanged", this.onSeekingChanged);
	MN.Event.Observe(this.player.p,"BitRateChanged", this.onBitRateChanged);
	//MN.Event.Observe(this.player, "CurrentPositionChanged", this.update);
}

/**
  * Function: onPlayStateChanged
  * Called when the player changes play states
  *
  * Parameter:
  * oldS:Number - Old play state
  * newS:Number - New play state
  */
_vidinfo.onPlayStateChanged = function(oldS, newS){
	this.playState = newS;
	var stateStr = MN.QMP.PS[this.playState];
	this.status = stateStr.toLowerCase();
	this.createString(this.time, this.status, this.bitrate);
}

/**
  * Function: checkPlayPause
  * Called when the paused stated has changed
  *
  * Parameter:
  * paused:Boolean - flag if the player is paused or not
  */
_vidinfo.checkPlayPause = function(paused){
	
	// Set paused value
	if(paused == null){
		paused = this.player.p.Paused();
	}

	if (this.playState==MN.QMP.PS.PLAYING)
	{
		if(!paused){
			this.status = "playing";
		}
		else{
			this.status = "paused";
		}
		this.createString(this.time, this.status, this.bitrate);
	}
}

/**
  * Function: onSeekingChanged
  * Update seeking text based on seek status
  *
  * Parameter:
  * seek:Boolean - Flag for seeking
  * seekType:String - Rewind or Fast Forward
  * scrubSpeed:Number - 2,4,8,16 - speed of the scrub
  */
_vidinfo.onSeekingChanged = function (seek, seekType, scrubSpeed){
	if(!seek){
		var stateStr = MN.QMP.PS[this.playState];
		this.status = stateStr.toLowerCase();
		this.createString(this.time, this.status, this.bitrate);
	}
	else{
		var displayTxt = seekType + Math.abs(scrubSpeed) + "x";
		this.status = displayTxt.toLowerCase();
		this.createString(this.time, this.status, this.bitrate);
	}
}

/**
  * Function: onBitRateChanged
  * Called when the player changes bit rate
  *
  * Parameter:
  * newBR:Number - New bit rate
  */
_vidinfo.onBitRateChanged = function(newBR){
	if (!isNaN(newBR)){
		this.bitrate = newBR + " kbps";
		this.createString(this.time, this.status, this.bitrate);
	}
}

/**
  * Function: update
  * Updates the time display to reflect the position of the video out of the total duration
  *
  * Parameter:
  * pos:Number - current position in video playback
  * total:Number - total time in video playback
  */
_vidinfo.update = function (pos, total){
	var val = MN.ConvertToTimestamp(pos) + " / " + MN.ConvertToTimestamp(total);
	if(this.time != val){
		this.time = val;
		this.createString(this.time, this.status, this.bitrate);
	}
}

/**
  * Function: createString
  * Build new video info string based on the current time, status and bitrate
  *
  * Parameter:
  * time:String - current position out of duration in video playback
  * status:String - current status of the player
  * bitrate:String - current bitrate of the player
  */
_vidinfo.createString = function(time, status, bitrate){
	var val = status + "     " + bitrate;
	this.txtField.setText(val);
}

/**
 * Class: MN.Player.VolumeSlider
 * Volume slider component for native overlays.
 */
MN.Player.VolumeSlider = MN.Class(MN.EventSource);
_vSlider= MN.Player.VolumeSlider.prototype;

/**
  * Function: initialize
  * Initializes a volume slider
  *
  * Parameter:
  * player:Object - Move Player controller
  * parentContainer:Object - parent Overlay Object
  */
_vSlider.initialize = function(player, parentContainer){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player;
	this.scrubbing = false; // Flag when user is scrubbing
	this.curVol = this.player.p.Volume(); // Current volume
	this.muteVol = 0; // Saved volume when the mute is pressed
	
	// Configuration parameters for the native slider
	var area = MN.PlayerStyles.volume;
	var lead = MN.PlayerStyles.volumeLead;
	var trail = MN.PlayerStyles.volumeTrail;
	var leftEdge = MN.PlayerStyles.volumeLeftEdge;
	var rightEdge = MN.PlayerStyles.volumeRightEdge;
	var scrubber = MN.PlayerStyles.volumeScrubber;
	var scrubberNormal = MN.PlayerStyles.volumeScrubberDefault;
	var scrubberHover = MN.PlayerStyles.volumeScrubberHover;
	
	// Native slider
	this.slider = new MN.Player.Slider(player, parentContainer, "volume", area, lead, trail, leftEdge, rightEdge, scrubber, scrubberNormal, scrubberHover);
	
	// Set volume
	this.setVolume();
	
	// Event handlers
	MN.Event.Observe(this.slider,"ScrubbingChanged", this.onScrubberChanged);
	MN.Event.Observe(this.slider,"ScrubberValue", this.onScrubberValue);
	MN.Event.Observe(this.slider,"SliderLeadUIChanged", this.onSliderLeadUIChanged);
}

/**
  * Function: setVolume
  * Sets the volume of the Move player, scale is 0 to 100 (percent), based on watching the volume slider
  *
  * Parameter:
  * newVol:Number - new volume setting
  */
_vSlider.setVolume = function(newVol){
	// Determine actual new volume
	if(newVol == 0){
		this.player.p.Muted(true);
	}
	else if(newVol > 0 && newVol <= 100){
		this.player.p.Muted(false);
	}
	else{
		newVol = this.curVol;	
	}
	
	// Save new volume
	this.player.p.Volume(newVol);
	this.curVol = newVol;
	
	//Update scrubber
	if(!this.scrubbing){
		var value = Math.floor(this.curVol*(this.slider.lead.width/100));
		if(value >= 0 && value <= this.slider.lead.width){
			this.slider.setValue(value);
		}
	}
}

/**
  * Function: onScrubberValue
  * Slider value updated
  *
  * Parameter:
  * value:Number -  New value of slider (trail width)
  * type:String - type of scrubber value change
  */
_vSlider.onScrubberValue = function(value, type){
	if(type != "set"){ 
		value = Math.floor(value * (100/this.slider.lead.width));
		this.setVolume(value);
	}
}

/**
  * Function: onScrubberChanged
  * Toggle scrubbing
  *
  * Parameter:
  * scrub:Boolean - Scrubbing or not
  */
_vSlider.onScrubberChanged = function(scrub){
	this.scrubbing = scrub;
}

/**
  * Function: onSliderLeadUIChanged
  * Update scrubber position for the current position
  */
_vSlider.onSliderLeadUIChanged = function(){
	this.setVolume();
}

/**
  * Function: muteToggle
  * Volume toggle function - not used currently
  */
_vSlider.muteToggle = function(){
	if(this.player.p.Volume() != 0){
		this.muteVol = this.player.p.Volume();
		this.setVolume(0);
	}
	else{
		if(this.muteVol != null){
			this.setVolume(this.muteVol);
		}
	}
}


/**
 * Class: MN.Timer
 * Inactivity timer that stops playback after x time
 */
MN.Timer = MN.Class(MN.EventSource);
_timer= MN.Timer.prototype;

/**
  * Function: initialize
  * Initializes a timer object
  *
  * Parameter:
  * player:Object - Move Player controller
  */
_timer.initialize = function(player){
	MN.EventSource.prototype.initialize.apply(this);
	
	// Properties
	this.player = player; // Player controller
	this.inactiveTime = 1800; // Amount of time in seconds before player is considered inactive - 30 mins
	this.interval = 0; // Tracker
	this.current = 0; // Number of seconds left before playback is stopped
}

_timer.start = function(){
    this.reset();
}

_timer.reset = function(){
    clearInterval(this.interval);
    this.current = this.inactiveTime;
    this.interval = setInterval(this.dec, 1000);
}

_timer.stop = function(){
	clearInterval(this.interval);
}

_timer.dec = function(){
	this.current--;
	if(this.current <= 0){
		this.done();
	}
}

_timer.done = function(){
	this.stop();
	this.player.endPlayback();
}


/*
	styles.js
	Styles for Move Overlay controls
*/
var _filePath = String(location.href).split("?")[0];
_filePath = _filePath.substring(0, _filePath.lastIndexOf('/')+1);
var imgPath = _filePath + "images/"; // Path for all images

if(!MN){
	MN = {};
}

MN.PlayerStyles = {

	// Substage (required)
	"substage" : {
		"top" : "0px",
		"left" : "0px",
		"width" : "100%",
		"height" : "100%"
	},
	
	// Inactive
	"inactive" : {
		"width" : "100%",
		"height" : "100%",
		"top" : "0px",
		"left" : "0px",
		"z-index" : 10,
		"url" : imgPath + "controls/playInactive.png"
	},
	

	// Controls
	"controls" : {
		//"width" : "800px",
		"width" : "392px",
		"height" : "59px",
		"bottom" : "0px",
		"left" : "auto",
		"timeout" : 5000,
		"fade" : 500,
		"z-index" : 3
	},
	
	"controlsDarkBack" : {
		"left" : "0px",
		"bottom" : "0px",
		"width" : "100%",
		"height" : "21px",
		"url" : imgPath + "controls/controlsDark.png",
		"z-index" : 0
	},
	
	"controlsLightBack" : {
		"left" : "0px",
		"bottom" : "21px",
		"width" : "100%",
		"height" : "38px",
		"url" : imgPath + "controls/controlsLight.png",
		"z-index" : 0
	},
	
	// Logo
	
	"logo" : {
		"right" : "7px",
		"bottom" : "7px",
		"width" : "71px",
		"height" : "14px",
		"url" : imgPath + "controls/moveLogo.png",
		"z-index" : 1
	},
	
	// Play/Pause buttons
	"playPause" : {
		"left" : "7px",
		"bottom" : "26px",
		"width" : "29px",
		"height" : "29px",
		"z-index" : 1
	},
	
	"playDefault" : {
		"top" : "0px",
		"left" : "-149px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"playHover" : {
		"top" : "-39px",
		"left" : "-149px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"pauseDefault" : {
		"top" : "0px",
		"left" : "-112px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"pauseHover" : {
		"top" : "-39px",
		"left" : "-112px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	// Fast Forward Button
	
	"ff" : {
		"left" : "90px",
		"width" : "13px",
		"height" : "13px",
		"bottom" : "34px",
		"z-index" : 1
	},
	
	"ffDefault" : {
		"top" : "0px",
		"left" : "-86px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"ffHover" : {
		"top" : "-40px",
		"left" : "-86px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"ffDisabled" : {
		"top" : "-76px",
		"left" : "-86px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	// Rewind Button
	
	"rw" : {
		"left" : "37px",
		"width" : "13px",
		"height" : "13px",
		"bottom" : "34px",
		"z-index" : 1
	},
	
	"rwDefault" : {
		"top" : "0px",
		"left" : "-63px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"rwHover" : {
		"top" : "-40px",
		"left" : "-63px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"rwDisabled" : {
		"top" : "-76px",
		"left" : "-63px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	// Next Button
	
	"next" : {
		"left" : "107px",
		"bottom" : "28px",
		"width" : "25px",
		"height" : "25px",
		"z-index" : 1
	},
	
	"nextDefault" : {
		"top" : "0px",
		"left" : "-30px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"nextHover" : {
		"top" : "-40px",
		"left" : "-30px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"nextDisabled" : {
		"top" : "-77px",
		"left" : "-30px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	// Previous Button
	
	"prev" : {
		"left" : "7px",
		"bottom" : "28px",
		"width" : "25px",
		"height" : "25px",
		"z-index" : 1
	},
	
	"prevDefault" : {
		"top" : "0px",
		"left" : "0px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"prevHover" : {
		"top" : "-40px",
		"left" : "0px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"prevDisabled" : {
		"top" : "-77px",
		"left" : "0px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	
	// General Text settings
	
	"txt" : {
		"font" : "Arial",
		"size" : "11px",
		"color" : "0xE5E6E2",
		"z-index" : 1
	},
	
	// Video Info - combines all three (time, status, bitrate)
	
	"txtvideoinfo" : {
		"width" : "300px",
		"height" : "18px",
		"bottom" : "-2px",
		"left" : "7px"
	},
	
	// Time Display
	
	"txttimedisplay" : {
		"width" : "200px",
		"height" : "18px",
		"bottom" : "-3px",
		"right" : "50px"
	},
	
	// Playback Status
	
	"txtstatus" : {
		"width" : "200px",
		"height" : "18px",
		"bottom" : "-3px",
		"left" : "360px"
	},
	
	// Bitrate
	
	"txtbitrate" : {
		"width" : "150px",
		"height" : "18px",
		"bottom" : "-3px",
		"left" : "156px"
	},
	
	
	// Fullscreen/Normalscreen Buttons
	
	"full" : {
		"right" : "11px",
		"bottom" : "28px",
		"width" : "32px",
		"height" : "23px",
		"z-index" : 1,
		"display" : "window"
	},
	
	"fullDefault" : {
		"top" : "0px",
		"left" : "-276px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"fullHover" : {
		"top" : "-39px",
		"left" : "-276px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"normal" : {
		"right" : "11px",
		"bottom" : "28px",
		"width" : "32px",
		"height" : "23px",
		"z-index" : 1,
		"display" : "fullscreen"
	},
	
	"normalDefault" : {
		"top" : "0px",
		"left" : "-316px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"normalHover" : {
		"top" : "-39px",
		"left" : "-316px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	
	// Timeline
	
	"timeline" : { // Dynamic width timeline, scales to match the left and right values
		"left" : "140px",
		"right" : "164px",
		"height" : "38px",
		"bottom" : "21px",
		"z-index" : 1
	},
	
	"timelineLead" : {
		"top" : "15px",
		"height" : "10px",
		"left" : "0px", // Will be replaced to give scrubber padding
		"width" : "0px", //Will be replaced when timeline width is calculated
		"url" : imgPath + "controls/sliderLead.png",
		"z-index" : 1
	},
	
	"timelineTrail" : {
		"top" : "17px",
		"height" : "6px",
		"left" : "0px", // Will be replaced to match lead
		"width" : "0px", //Will be replaced to match the slider x position
		"url" : imgPath + "controls/sliderTrail.png",
		"z-index" : 2
	},
	
	"timelineLeftEdge" : {
		"height" : "10px",
		"width" : "4px",
		"top" : "15px",
		"left" : "12px", //scrubber width/2 - width
		"url" : imgPath + "controls/leftEdge.png",
		"z-index" : 1
	},
	
	"timelineRightEdge" : {
		"height" : "10px",
		"width" : "4px",
		"top" : "15px",
		"right" : "12px", //scrubber width/2 - width
		"url" : imgPath + "controls/rightEdge.png",
		"z-index" : 1
	},
	
	"timelineScrubber" : {
		"height" : "23px",
		"width" : "32px",
		"top" : "8px",
		"left" : "0px",
		"z-index" : 3
	},
	
	"timelineScrubberDefault" : {
		"top" : "0px",
		"left" : "-196px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"timelineScrubberHover" : {
		"top" : "-39px",
		"left" : "-196px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	
	// Volume Slider
	
	"volume" : { // Bound to the right of the controls
		"right" : "52px",
		"width" : "100px",
		"height" : "38px",
		"bottom" : "21px",
		"z-index" : 1
	},
	
	"volumeLead" : {
		"top" : "15px",
		"height" : "10px",
		"left" : "0px", // Will be replaced to give scrubber padding
		"width" : "0px", // Will be replaced when timeline width is calculated
		"url" : imgPath + "controls/sliderLead.png",
		"z-index" : 1
	},
	
	"volumeTrail" : {
		"top" : "17px",
		"height" : "6px",
		"left" : "0px", // Will be replaced to match lead
		"width" : "0px", // Will be replaced to match the slider x position
		"url" : imgPath + "controls/sliderTrail.png",
		"z-index" : 2
	},
	
	"volumeLeftEdge" : {
		"height" : "10px",
		"width" : "4px",
		"top" : "15px",
		"left" : "12px", //scrubber width/2 - width
		"url" : imgPath + "controls/leftEdge.png",
		"z-index" : 1
	},
	
	"volumeRightEdge" : {
		"height" : "10px",
		"width" : "4px",
		"top" : "15px",
		"right" : "12px", //scrubber width/2 - width
		"url" : imgPath + "controls/rightEdge.png",
		"z-index" : 1
	},
	
	"volumeScrubber" : {
		"height" : "23px",
		"width" : "32px",
		"top" : "8px",
		"left" : "0px",
		"z-index" : 3
	},
	
	"volumeScrubberDefault" : {
		"top" : "0px",
		"left" : "-236px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"volumeScrubberHover" : {
		"top" : "-39px",
		"left" : "-236px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	// Thumbnail Preview
	
	"preview" : {
		"width" : "138px",
		"height" : "117px",
		"bottom" : "36px",
		"left" : "0px",
		"alpha" : 0,
		"mouseevents" : "disabled",
		"z-index" : 4
	},
	
	"previewBack" : {
		"width" : "138px",
		"height" : "102px",
		"bottom" : "13px",
		"left" : "auto",
		"url" : imgPath + "controls/preview.png"
	},
	
	"noPreviewBack" : {
		"width" : "84px",
		"height" : "33px",
		"bottom" : "9px",
		"left" : "auto",
		"url" : imgPath + "controls/noPreview.png"
	},
	
	"previewTime" : {
		"font" : "Arial",
		"size" : "13px",
		"width" : "100px",
		"height" : "20px",
		"top" : "6px",
		"color" : "0x000000"
	},
	
	"previewTimeShort" : {
		"left" : "53px"
	},
	
	"previewTimeLong" : {
		"left" : "43px"
	},
	
	"noPreviewTime" : {
		"font" : "Arial",
		"size" : "13px",
		"width" : "100px",
		"height" : "20px",
		"top" : "82px",
		"color" : "0x000000"
	},
	
	"noPreviewTimeShort" : {
		"left" : "53px"
	},
	
	"noPreviewTimeLong" : {
		"left" : "43px"
	},
	
	"previewThumb" : {
		"width" : "128px",
		"height" : "72px",
		"top" : "22px",
		"left" : "5px"
	},
	
	"previewTracker" : {
		"width" : "6px",
		"height" : "6px",
		"bottom" : "0px",
		"left" : "65px",
		"mouseevents" : "disabled",
		"url" : imgPath + "controls/whiteBullet.png"
	},
	
	// Go Live Button
	
	"goLive" : {
		"left" : "46px",
		"bottom" : "28px",
		"width" : "49px",
		"height" : "20px",
		"z-index" : 1
	},
	
	"goLiveDefault" : {
		"top" : "-76px",
		"left" : "-112px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	},
	
	"goLiveHover" : {
		"top" : "-76px",
		"left" : "-174px",
		"width" : "348px",
		"height" : "102px",
		"url" : imgPath + "controls/buttons.png"
	}
}

