﻿//!-----------------------------------------------------------------------
//! Copyright (C) Microsoft Corporation. All rights reserved.
//!-----------------------------------------------------------------------
//! PreviewMedia.js
//! Media Framework.
Type.registerNamespace('Sys.Preview.UI.Xaml.Media');

Sys.Preview.UI.Xaml.Media.PlayerElementName  = {
    videoWindow             : "VideoWindow",              // the <mediaelement>
    placeholderImage        : "PlaceholderImage",         // Displays the placeholder image prior to the media loading
    playerControls          : "PlayerControls",           // area encompassing all player controls
    playButton              : "PlayButton",               // a play button
    playPauseButton         : "PlayPauseButton",          // a play/pause toggle button (requires PlaySymbol & PauseSymbol)
    playSymbol              : "PlaySymbol",               // part of play/pause button, represents symbol showing for "play"
    pauseSymbol             : "PauseSymbol",              // part of play/pause button, represents symbol showing for "pause"
    stopButton              : "StopButton",               // the stop button
    pauseButton             : "PauseButton",              // the pause button
    nextButton              : "NextButton",               // the next button (next chapter)
    previousButton          : "PreviousButton",           // the previous button (prev chapter)
    muteButton              : "MuteButton",               // mute button
    muteOnSymbol            : "MuteOnSymbol",             // adornment to show on MuteButton when audio muted
    muteOffSymbol           : "MuteOffSymbol",            // adornment to show on MuteButton when audio enabled
    timeSlider              : "TimeSlider",               // the scrub bar
    timeThumb               : "TimeThumb",                // the play head
    timeCompleted           : "TimeCompleted",            // indicator on slider showing how much time is completed
    volumeSlider            : "VolumeSlider",             // the volume slider bar
    volumeThumb             : "VolumeThumb",              // the volume slider thumb control
    volumeUpButton          : "VolumeUpButton",           // a button to make the volume increase
    volumeDownButton        : "VolumeDownButton",         // a button to make the volume decrease
    totalTimeText           : "TotalTimeText",            // the text area for total duration of video
    currentTimeText         : "CurrentTimeText",          // the text area for the current media time
    downloadSlider          : "DownloadProgressSlider",   // slider to show download progress
    downloadText            : "DownloadProgressText",     // text to show download progress
    bufferingArea           : "BufferingArea",            // canvas that contains buffering feedback UI
    bufferingText           : "BufferingText",            // text to show buffering progress
    fullScreenButton        : "FullScreenButton",         // button to show video full screen
    chapterArea             : "ChapterArea",              // encasing chapters area
    chapterToggleButton     : "ChapterToggleButton",      // toggles the chapter list
    chapterScroll           : "ChapterScroll",            // chapters scroll region
    chapterPrev             : "ChapterScrollPrevious",    // control to scroll chapters to next
    chapterNext             : "ChapterScrollNext",        // control to scroll chapters to previous
    chapterItem             : "ChapterScrollItem",        // item signifying video item
    captionText             : "CaptionText",              // TextBlock to show closed captions in    
    captionArea             : "CaptionArea",              // Background of CaptionText 
    captionToggleButton     : "CaptionToggleButton",      // Toggles closed captions
    captionOnSymbol         : "CaptionOnSymbol",          // adornment to show on CaptionButton when captions on
    captionOffSymbol        : "CaptionOffSymbol",         // adornment to show on CaptionButton when captions off
    fullScreenArea          : "FullScreenArea",           // enabled when player switches to FS
    fullScreenVideoWindow   : "FullScreenVideoWindow",    // video window used for fullscreen mode
    fullScreenCaptionText   : "FullScreenCaptionText",    // mirror of captions for fullscreen mode
    fullScreenCaptionArea   : "FullScreenCaptionArea"     // mirror of captions for fullscreen mode
};
Sys.Preview.UI.Xaml.Media._DomElement = function Sys$Preview$UI$Xaml$Media$_DomElement(host, nameElement) {
    // <summary>Represents a XAML Element</summary>
    // <param name="host">Silverlight host</param>
    // <param name="nameElement" type="String">Name of XAML canvas which represents the element</param>
    this._control = host.content.findName(nameElement);
    if (this._control) {
        this.bindEvent("mouseEnter", nameElement + "_MouseEnter");
        this.bindEvent("mouseLeave", nameElement + "_MouseLeave");
        this._showAnimation = this._control.findName(nameElement + "_Show");
        this._hideAnimation = this._control.findName(nameElement + "_Hide");
        this._enableAnimation = this._control.findName(nameElement + "_Enable");
        this._disableAnimation = this._control.findName(nameElement + "_Disable");
    }
}









    function Sys$Preview$UI$Xaml$Media$_DomElement$get_control() {
if (arguments.length !== 0) throw Error.parameterCount();
        // <value>The underlying XAML control</value>
        return this._control;
    }

    function Sys$Preview$UI$Xaml$Media$_DomElement$get_enabled() {
if (arguments.length !== 0) throw Error.parameterCount();
        return this._enabled;
    }
    function Sys$Preview$UI$Xaml$Media$_DomElement$set_enabled(value) {
        if (value !== this.get_enabled()) {
            // e.g. might make the control look grayed out or increase its alpha
            var anim = value ? this._enableAnimation : this._disableAnimation;
            if (anim) anim.begin();
            this._enabled = value;
        }
    }

    function Sys$Preview$UI$Xaml$Media$_DomElement$bindEvent(eventName, animationName, callback, callbackOwner) {
        // helper that reduces code necessary to bind a xaml event to a function and have it play an animation by name
        // if set_enabled(false) is called, animations stop playing and callbacks aren't called. For example, a disabled button does nothing.
        if (animationName || callback) {
            var animation = null;
            if (animationName) animation = this._control.findName(animationName);
            
            // no animation found and theres no callback, no reason to hook the event
            if (!animation && !callback) return;
            
            if (!this._boundEvents) this._boundEvents = [];

            if (callback) {
                callback = Function.createDelegate(callbackOwner || this, callback);
            }
            
            var _this = this;
            function handleEvent(sender, args) {
                if (!_this.get_enabled()) return;
                if (callback && !callback(sender, args)) return;
                if (animation) animation.begin();
            }
            
            var token = this._control.addEventListener(eventName, handleEvent);
            this._boundEvents[this._boundEvents.length] = { eventName: eventName, token: token };
        }
    }

    function Sys$Preview$UI$Xaml$Media$_DomElement$dispose() {
        if (this._control) {
            if (this._boundEvents) {
                for (var i = 0, l = this._boundEvents.length; i < l; i++) {
                    var e = this._boundEvents[i];
                    this._control.removeEventListener(e.eventName, e.token);
                }
                this._boundEvents = null;
            }
                    
            this._showAnimation = null;
            this._hideAnimation = null;
            this._enableAnimation = null;
            this._disableAnimation = null;
            this._control = null;
        }
    }

    function Sys$Preview$UI$Xaml$Media$_DomElement$setVisible(value) {
        var anim = value ? this._showAnimation : this._hideAnimation;
        if (anim) {
            anim.begin();
        }
        else if (this._control) {
            this._control.visibility = value ? 0 : 1;
        }
    }
Sys.Preview.UI.Xaml.Media._DomElement.prototype = {
    _control: null,
    _boundEvents: null,
    _showAnimation: null,
    _hideAnimation: null,
    _enableAnimation: null,
    _disableAnimation: null,
    _enabled: true,
    
    get_control: Sys$Preview$UI$Xaml$Media$_DomElement$get_control,

    get_enabled: Sys$Preview$UI$Xaml$Media$_DomElement$get_enabled,
    set_enabled: Sys$Preview$UI$Xaml$Media$_DomElement$set_enabled,

    bindEvent: Sys$Preview$UI$Xaml$Media$_DomElement$bindEvent,
    
    dispose: Sys$Preview$UI$Xaml$Media$_DomElement$dispose,
    
    setVisible: Sys$Preview$UI$Xaml$Media$_DomElement$setVisible
}
Sys.Preview.UI.Xaml.Media._DomElement.registerClass('Sys.Preview.UI.Xaml.Media._DomElement', null, Sys.IDisposable);

Sys.Preview.UI.Xaml.Media._Button = function Sys$Preview$UI$Xaml$Media$_Button(host, nameElement, autoRepeatInterval,
                                            clickHandler, doubleClickHandler, handlerOwner, requiresSender) {
    
    Sys.Preview.UI.Xaml.Media._Button.initializeBase(this, [host, nameElement]);
    this._repeatInterval = autoRepeatInterval || 0;
    
    var control = this.get_control();
    if (control) {
        control.cursor = "Hand";
        this.bindEvent("mouseLeftButtonDown", nameElement + "_MouseDown", this._mouseDown);
        this.bindEvent("mouseLeftButtonUp", nameElement + "_MouseUp", this._mouseUp);
        this.bindEvent("mouseLeave", nameElement + "_MouseUp", this._mouseLeave);
    }
    if (handlerOwner) {
        // some button handlers are wired directly into public methods that dont take parameters.
        // others are private methods that need to know the button instance clicked.
        this._requiresSender = !!requiresSender;
        this._clickDelegate = Function.createDelegate(handlerOwner, clickHandler);
        if (doubleClickHandler) {
            this._doubleClickDelegate = Function.createDelegate(handlerOwner, doubleClickHandler);
        }
    }
}









    function Sys$Preview$UI$Xaml$Media$_Button$set_enabled(value) {
        Sys.Preview.UI.Xaml.Media._Button.callBaseMethod(this, "set_enabled", [value]);
        var c = this.get_control();
        if (c) c.cursor = value ? "Hand" : "Default";
    }

	function Sys$Preview$UI$Xaml$Media$_Button$dispose() {
	    this._cancelRepeat();
	    this._clickDelegate = null;
	    this._doubleClickDelegate = null;
        Sys.Preview.UI.Xaml.Media._Button.callBaseMethod(this, 'dispose');                
    }

    function Sys$Preview$UI$Xaml$Media$_Button$_cancelRepeat() {
        if (!this._repeatTimeout) return;
        window.clearTimeout(this._repeatTimeout);
        this._repeatTimeout = null;
        this._repeatClickDelegate = null;
    }

    function Sys$Preview$UI$Xaml$Media$_Button$_doClick(isDouble) {
        if (isDouble && this._doubleClickDelegate) {
            this._requiresSender ? this._doubleClickDelegate(this) : this._doubleClickDelegate();
        }
        else if (this._clickDelegate) {
            this._requiresSender ? this._clickDelegate(this) : this._clickDelegate();
        }
    }

    function Sys$Preview$UI$Xaml$Media$_Button$_mouseDown() {
        this._down = true;
        if (this._repeatInterval && !this._repeatTimeout) {
            // click immediately when it will be repeating,
            // otherwise we don't until leftbuttonup
            this._doClick(false);
            this._repeatClickDelegate = Function.createDelegate(this, this._repeatClick);
            this._repeatTimeout = window.setTimeout(this._repeatClickDelegate, this._repeatInterval);
        }
        return true;
    }

    function Sys$Preview$UI$Xaml$Media$_Button$_mouseLeave() {
        if (!this._down) {
            // we're not already down, so cancel the mouseup animation
            return false;
        }
        this._down = false;
        this._cancelRepeat();
        return true;
    }

    function Sys$Preview$UI$Xaml$Media$_Button$_mouseUp() {
        this._down = false;

        if (this._repeatTimeout) {
            this._cancelRepeat();
        }
        else {
            var tmNow = new Date().getTime();
            var last = this._timeLastLeftButtonUp;
            this._timeLastLeftButtonUp = tmNow;
            var doubleClick = last && ((tmNow - last) < 300);
            if (doubleClick) {
                // so a 3rd click won't result in another double click
                this._timeLastLeftButtonUp = 0;
            }
            this._doClick(doubleClick);
        }
        return true;
    }

    function Sys$Preview$UI$Xaml$Media$_Button$_repeatClick() {
        this._repeatTimeout = window.setTimeout(this._repeatClickDelegate, this._repeatInterval);
        this._doClick(false);
    }
Sys.Preview.UI.Xaml.Media._Button.prototype = {
    _down: false,
    _repeatInterval: 0,
    _repeatTimeout: null,
    _repeatClickDelegate: null,
    _timeLastLeftButtonUp: 0,
    _clickDelegate: null,
    _doubleClickDelegate: null,
    
    set_enabled: Sys$Preview$UI$Xaml$Media$_Button$set_enabled,
    
	dispose: Sys$Preview$UI$Xaml$Media$_Button$dispose,

    _cancelRepeat: Sys$Preview$UI$Xaml$Media$_Button$_cancelRepeat,

    _doClick: Sys$Preview$UI$Xaml$Media$_Button$_doClick,

    _mouseDown: Sys$Preview$UI$Xaml$Media$_Button$_mouseDown,
    
    _mouseLeave: Sys$Preview$UI$Xaml$Media$_Button$_mouseLeave,
    
    _mouseUp: Sys$Preview$UI$Xaml$Media$_Button$_mouseUp,

    _repeatClick: Sys$Preview$UI$Xaml$Media$_Button$_repeatClick
}
Sys.Preview.UI.Xaml.Media._Button.registerClass('Sys.Preview.UI.Xaml.Media._Button', Sys.Preview.UI.Xaml.Media._DomElement);

Sys.Preview.UI.Xaml.Media.Player = function Sys$Preview$UI$Xaml$Media$Player(domElement) {
    /// <param name="domElement"></param>
    var e = Function._validateParams(arguments, [
        {name: "domElement"}
    ]);
    if (e) throw e;

    Sys.Preview.UI.Xaml.Media.Player.initializeBase(this, [domElement]);
    // default scale mode for a media player
    this.set_scaleMode(Sys.Preview.UI.Xaml.ScaleMode.zoom);
}
















































    function Sys$Preview$UI$Xaml$Media$Player$add_chapterStarted(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().addHandler("chapterStarted", handler);
    }
    function Sys$Preview$UI$Xaml$Media$Player$remove_chapterStarted(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().removeHandler("chapterStarted", handler);
    }

    function Sys$Preview$UI$Xaml$Media$Player$add_markerReached(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().addHandler("markerReached", handler);
    }
    function Sys$Preview$UI$Xaml$Media$Player$remove_markerReached(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().removeHandler("markerReached", handler);
    }

    function Sys$Preview$UI$Xaml$Media$Player$add_mediaEnded(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().addHandler("mediaEnded", handler);
    }
    function Sys$Preview$UI$Xaml$Media$Player$remove_mediaEnded(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().removeHandler("mediaEnded", handler);
    }

    function Sys$Preview$UI$Xaml$Media$Player$add_mediaFailed(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().addHandler("mediaFailed", handler);
    }
    function Sys$Preview$UI$Xaml$Media$Player$remove_mediaFailed(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().removeHandler("mediaFailed", handler);
    }

    function Sys$Preview$UI$Xaml$Media$Player$add_mediaOpened(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().addHandler("mediaOpened", handler);
    }
    function Sys$Preview$UI$Xaml$Media$Player$remove_mediaOpened(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().removeHandler("mediaOpened", handler);
    }

    function Sys$Preview$UI$Xaml$Media$Player$add_stateChanged(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().addHandler("stateChanged", handler);
    }
    function Sys$Preview$UI$Xaml$Media$Player$remove_stateChanged(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().removeHandler("stateChanged", handler);
    }

    function Sys$Preview$UI$Xaml$Media$Player$add_volumeChanged(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().addHandler("volumeChanged", handler);
    }
    function Sys$Preview$UI$Xaml$Media$Player$remove_volumeChanged(handler) {
    var e = Function._validateParams(arguments, [{name: "handler", type: Function}]);
    if (e) throw e;

        this.get_events().removeHandler("volumeChanged", handler);
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_autoPlay() {
        /// <value type="Boolean"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (this._mediaElement) return this._mediaElement.AutoPlay;
        if (this._autoPlay !== null) return this._autoPlay;
        return false;
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_autoPlay(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: Boolean}]);
        if (e) throw e;

        if (this._mediaElement) {
            this._mediaElement.AutoPlay = value;
        }
        else {
            this._autoPlay = value;
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_caption() {
        /// <value type="String"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._caption || "";
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_caption(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: String}]);
        if (e) throw e;

        this._caption = value;
        if (this._captionArea) {
            this._captionArea.set_text(value);
        }
        if (this._captionAreaFS) {
            this._captionAreaFS.set_text(value);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_chapters() {
        /// <value type="Array"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (!this._chapters) return [];
        return Array.clone(this._chapters);
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_chapters(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: Array}]);
        if (e) throw e;

        this._chapters = value;
        if (this._chapterArea) {
            this._loadChapters(value, true);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_currentChapter() {
        /// <value type="Number"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._currentChapter;
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_currentChapter(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: Number}]);
        if (e) throw e;

        var chapters = this.get_chapters();
        if (!chapters || value < 0 || value >= chapters.length) {
            throw Error.argumentOutOfRange("currentChapter", value, Sys.Preview.UI.Xaml.Media.Res.invalidChapterIndex);
        }
        var newTime = chapters[value].time;
        if (newTime !== -1) {
            this.set_timeIndex(newTime);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_enableCaptions() {
        /// <value type="Boolean"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return !!this._enableCaptions;
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_enableCaptions(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: Boolean}]);
        if (e) throw e;

        if (this._enableCaptions !== value) {
            this._enableCaptions = value;
            this._ensureCaption();
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_mediaMarkers() {
        /// <value type="Array"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (!this._mediaMarkers) return [];
        return Array.clone(this._mediaMarkers);
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_mediaElement() {
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._mediaElement || null;
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_mediaUrl() {
        /// <value type="String"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (this._mediaElement) return this._mediaElement.Source || "";
        return this._mediaUrl || "";
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_mediaUrl(value) {    
        var e = Function._validateParams(arguments, [{name: "value", type: String}]);
        if (e) throw e;

        if (this._mediaElement) {
            this._loadPlaceholderImage();
            this._loadMediaUrl(value);
        }
        else {
            this._mediaUrl = value;
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_muted() {
        /// <value type="Boolean"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (this._mediaElement) return this._mediaElement.IsMuted;
        return !!this._muted;
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_muted(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: Boolean}]);
        if (e) throw e;

        if (value !== this.get_muted()) {
            if (this._mediaElement) {
                this._mediaElement.IsMuted = value;
                this._muteButton.set_state(value ? 1 : 0);
            }
            else {
                this._muted = value;
            }
            if (!this.get_isUpdating()) {
                this._raiseVolumeChanged(Sys.EventArgs.Empty);
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_placeholderImage() {
        /// <value type="String" mayBeNull="true"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._placeholderImage || "";
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_placeholderImage(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: String, mayBeNull: true}]);
        if (e) throw e;

        this._placeholderImage = value;
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_playState() {
        /// <value type="String"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._mediaElement ? this._mediaElement.CurrentState : "Stopped";
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_timeIndex() {
        /// <value type="Number"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._mediaElement ? this._mediaElement.position.seconds : 0;
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_timeIndex(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: Number}]);
        if (e) throw e;

        if(this._mediaElement && this._canSeek) {
            this._mediaEnded = false;
            this.set_caption("");
            // restrict to within 0 and naturalduration
            value = Math.max(0, value);
            value = Math.min(this._naturalduration, value);
            var position = this._mediaElement.position;
            position.seconds = value;
	        this._mediaElement.position = position;            
	        // force update: the thumb position and time index textblocks need updating even though
	        // the media might not be playing currently. Picked up by the timeout that continuously
	        // syncrhonizes these controls with the media position.
            this._forceUpdate = true;
            // update ui and detect chapter changing
            this._updateTime(value);
            this._currentChapter = this._getChapterAt(value, true);
            this._detectChapterChanged();
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$get_volume() {
        /// <value type="Number"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (this._volume !== null) return this._volume;
        if (this._mediaElement) return this._mediaElement.volume;
        return Sys.Preview.UI.Xaml.Media.Player._defaultVolume;
    }
    function Sys$Preview$UI$Xaml$Media$Player$set_volume(value) {
        var e = Function._validateParams(arguments, [{name: "value", type: Number}]);
        if (e) throw e;

        if (value < 0 || value > 1) {
            throw Error.argumentOutOfRange("value", value, Sys.Preview.UI.Xaml.Media.Res.volumeRange);
        }
        if (value !== this.get_volume()) {
            if (this._mediaElement && this._mediaElement.CurrentState !== "Closed") {
                this._mediaElement.volume = value;
            }
            else {
                this._volume = value;
            }
            if (!this.get_isUpdating()) {
                this._raiseVolumeChanged(Sys.EventArgs.Empty);
            }
        }

        if (this._dragVolume) this._dragVolume.set_value(value);
    }

    function Sys$Preview$UI$Xaml$Media$Player$nextChapter() {
        /// <returns type="Boolean"></returns>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (!this._canSeek) return false;
        var chapters = this.get_chapters();
        if (chapters) {
            var i = this.get_currentChapter();
            if (++i < chapters.length) {
                this.set_currentChapter(i);
                return true;
            }
        }
        return false;
    }

    function Sys$Preview$UI$Xaml$Media$Player$onChapterStarted(chapterEventArgs) {
        /// <param name="chapterEventArgs" type="Sys.Preview.UI.Xaml.Media.ChapterEventArgs"></param>
        var e = Function._validateParams(arguments, [
            {name: "chapterEventArgs", type: Sys.Preview.UI.Xaml.Media.ChapterEventArgs}
        ]);
        if (e) throw e;

    }

    function Sys$Preview$UI$Xaml$Media$Player$onMarkerReached(args) {
        /// <param name="args" type="Sys.Preview.UI.Xaml.Media.MarkerEventArgs"></param>
        var e = Function._validateParams(arguments, [
            {name: "args", type: Sys.Preview.UI.Xaml.Media.MarkerEventArgs}
        ]);
        if (e) throw e;

    }

    function Sys$Preview$UI$Xaml$Media$Player$onPlayStateChanged(stateChangedEventArgs) {
        /// <param name="stateChangedEventArgs" type="Sys.Preview.UI.Xaml.Media.StateChangedEventArgs"></param>
        var e = Function._validateParams(arguments, [
            {name: "stateChangedEventArgs", type: Sys.Preview.UI.Xaml.Media.StateChangedEventArgs}
        ]);
        if (e) throw e;

    }

    function Sys$Preview$UI$Xaml$Media$Player$onVolumeChanged(args) {
        /// <param name="args" type="Sys.EventArgs"></param>
        var e = Function._validateParams(arguments, [
            {name: "args", type: Sys.EventArgs}
        ]);
        if (e) throw e;

    }

    function Sys$Preview$UI$Xaml$Media$Player$pause() {
        if (arguments.length !== 0) throw Error.parameterCount();
        if (!this._mediaElement) throw Error.invalidOperation(Sys.Preview.UI.Xaml.Media.Res.noMediaElement);
        if (!this._mediaOpened) return;
	    this._mediaElement.pause();
    }

    function Sys$Preview$UI$Xaml$Media$Player$play() {
        if (arguments.length !== 0) throw Error.parameterCount();
        if (!this._mediaElement) throw Error.invalidOperation(Sys.Preview.UI.Xaml.Media.Res.noMediaElement);
        if (!this._mediaOpened) return;
        this.set_caption("");
        var me = this._mediaElement;
        if (this._mediaEnded) {
            // user has hit play but the media already played to the end.
            // SL doesn't automatically rewind, so we must call stop first so it starts over.
            me.stop();
            this._mediaEnded = false;
            // we must play from a settimeout because SL doesnt always respond to stop then play immediatley after
            window.setTimeout(function() { me.play(); }, 0);
        }
        else {
            me.play();
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$previousChapter() {
        /// <returns type="Boolean"></returns>
        if (arguments.length !== 0) throw Error.parameterCount();
        if (!this._canSeek) return false;
        var chapters = this.get_chapters();
        if (chapters) {
            var i = this.get_currentChapter();
            if (--i >= 0) {
                this.set_currentChapter(i);
                return true;
            }
        }
        return false;
    }

    function Sys$Preview$UI$Xaml$Media$Player$stop() {
        if (arguments.length !== 0) throw Error.parameterCount();
        if (!this._mediaElement) throw Error.invalidOperation(Sys.Preview.UI.Xaml.Media.Res.noMediaElement);
        if (!this._mediaOpened) return;
        this._mediaEnded = false;
        this._currentChapter = this._getChapterAt(0, true);
	    this._forceUpdate = true;
	    this._mediaElement.stop();
	    this.set_caption("");
    }

    function Sys$Preview$UI$Xaml$Media$Player$toggleMuted() {
        /// <returns type="Boolean"></returns>
        if (arguments.length !== 0) throw Error.parameterCount();
        var v = !this.get_muted();
        this.set_muted(v);
        return v;
    }

    function Sys$Preview$UI$Xaml$Media$Player$togglePlayPause() {
        /// <returns type="String"></returns>
        if (arguments.length !== 0) throw Error.parameterCount();
        this.get_playState() === "Playing" ? this.pause() : this.play();
        return this.get_playState();
    }

    function Sys$Preview$UI$Xaml$Media$Player$xamlDispose() {
        if (this._timerCookie) {
            window.clearTimeout(this._timerCookie);
            this._timerCookie = null;
        }
        if (this._domElements) {
            for (var i = 0, l = this._domElements.length; i < l; i++) {
                this._domElements[i].dispose();
            }
            delete this._domElements;
        }

        // player should not continue playing after disposed
        // safe to call stop in any state
        if (this._mediaElement) this._mediaElement.stop();
        // remove direct references to xaml elements
        this._mediaElement = null;
        this._bufferingText = null;
        this._bufferingStoryboard = null;
        
        var content = this.get_element() ? this.get_element().content : null;
        if (content) {
            content.onFullScreenChange = null;
        }
        
        Sys.Preview.UI.Xaml.Media.Player.callBaseMethod(this, "xamlDispose");        
    }

    function Sys$Preview$UI$Xaml$Media$Player$xamlInitialize() {
        // search and create controls for well named XAML elements
        this._bindChildControls(); 
        Sys.Preview.UI.Xaml.Media.Player.callBaseMethod(this, 'xamlInitialize');
        
        var chapters = this.get_chapters();
        if (chapters) {
            this._loadChapters(chapters, false);
        }
        
        if (this._mediaUrl === null) {
            // no initial media means you can't seek
            this._ensureSeeking(false);
            // disable play, pause, stop, etc
	        this._mediaAvailable(false);
	    }
        this._loadPlaceholderImage();	    
        this._clearMediaCache();
    }

    function Sys$Preview$UI$Xaml$Media$Player$_bindChildControls() {
        var names = Sys.Preview.UI.Xaml.Media.PlayerElementName,
            host = this.get_element(),
            btn = Sys.Preview.UI.Xaml.Media._Button,
            domEl = Sys.Preview.UI.Xaml.Media._DomElement,
            sldr = Sys.Preview.UI.Xaml.Media._Slider,
            mbtn = Sys.Preview.UI.Xaml.Media._MultiStateButton,
            tb = Sys.Preview.UI.Xaml.Media._TextBlock;
        
        var mediaDomElement;
        this._domElements = [
            mediaDomElement = new btn(host, names.videoWindow, null, this.togglePlayPause, this._onFullScreenME, this),
            this._fsCanvas = new btn(host, names.fullScreenArea, null, this.togglePlayPause, this._onFullScreenME, this),
            this._fsVideoWindow = new domEl(host, names.fullScreenVideoWindow),
            this._bufferingProgress = new domEl(host, names.bufferingArea),
            new domEl(host, names.playerControls),
            // buttons
            this._playButton = new btn(host, names.playButton, null, this.play, null, this),
            this._stopButton = new btn(host, names.stopButton, null, this.stop, null, this),
            this._pauseButton = new btn(host, names.pauseButton, null, this.pause, null, this),
            new btn(host, names.volumeUpButton, 20, this._onVolumeUp, null, this),
            new btn(host, names.volumeDownButton, 20, this._onVolumeDown, null, this),
            new btn(host, names.fullScreenButton, null, this._onFullScreen, null, this),
            this._previousButton = new btn(host, names.previousButton, null, this._chapterPrevious, null, this),
            this._nextButton = new btn(host, names.nextButton, null, this._chapterNext, null, this),
            this._playPauseButton = new mbtn(host, names.playPauseButton, null, this.togglePlayPause, null, this, names.playSymbol, names.pauseSymbol),
            this._muteButton = new mbtn(host, names.muteButton, null, this.toggleMuted, null, this, names.muteOffSymbol, names.muteOnSymbol),
            // time slider
            this._dragTime = new sldr(host, names.timeThumb, names.timeSlider, this._onTimeSliderChanged, this),
            // volume slider
            this._dragVolume = new sldr(host, names.volumeThumb, names.volumeSlider, this._onVolumeSliderChanged, this),
            // time
            this._totalTimeText = new tb(host, names.totalTimeText),
            this._currentTimeText = new tb(host, names.currentTimeText),
            this._downloadProgress = new Sys.Preview.UI.Xaml.Media._ProgressBar(host, names.downloadSlider, names.downloadText),
            // chapter area        
            this._chapterArea = new Sys.Preview.UI.Xaml.Media._ChapterArea(this),
            // caption area
            this._captionArea = new tb(host, names.captionText, names.captionArea),
            this._captionAreaFS = new tb(host, names.fullScreenCaptionText, names.fullScreenCaptionArea),
            // toggle captions on/off
            this._captionButton = new mbtn(host, names.captionToggleButton, null, this._onCaptionToggle, null, this, names.captionOnSymbol, names.captionOffSymbol),
            // placeholder image
            this._imageElement = new domEl(host, names.placeholderImage)
        ];

        mediaDomElement.bindEvent("mediaOpened", null, this._meMediaOpened, this);
        mediaDomElement.bindEvent("mediaFailed", null, this._meMediaFailed, this);
        mediaDomElement.bindEvent("mediaEnded", null, this._meMediaEnded, this);
        mediaDomElement.bindEvent("downloadProgressChanged", null, this._meDownloadProgress, this);
        mediaDomElement.bindEvent("bufferingProgressChanged", null, this._meBufferingProgress, this);
        mediaDomElement.bindEvent("markerReached", null, this._meMarkerReached, this);
        mediaDomElement.bindEvent("currentStateChanged", null, this._meStateChanged, this);

        // UI for buffering feedback        
        this._bufferingStoryboard = host.content.findName(names.bufferingArea + "_Buffering");
        this._bufferingText = host.content.findName(names.bufferingText);

        this._dragVolume.set_value(this.get_volume());

        // full screen event
        host.content.onFullScreenChange = Function.createDelegate(this, this._fullScreenChanged);
        
        this._mediaElement = mediaDomElement.get_control();
        if (!this._mediaElement) {
            throw Error.invalidOperation(Sys.Preview.UI.Xaml.Media.Res.noMediaElement);
        }
        this._mediaElement.AutoPlay = false;
    }

    function Sys$Preview$UI$Xaml$Media$Player$_chapterNext() {
        var chapters = this.get_chapters();
        if (!chapters || !chapters.length) {
            // if there are no chapters, the next and previous buttons jump by a percentage of play time
            this._skipTime(1);
        }
        else {
            this.nextChapter();
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_chapterPrevious() {
        var chapters = this.get_chapters();
        if (!chapters || !chapters.length) {
            // if there are no chapters, the next and previous buttons jump by a percentage of play time
            this._skipTime(-1);
        }
        else {
            // find previous chapter (don't use previousChapter() because we need to allow 1s lead time)
            // e.g. clicking the previous chapter button in the middle of chapter #X should start at the beginning of chapter #X,
            // not chapter #X-1.
            // getChapterAt will tell us which chapter is playing at the current time minus 1 second
            var newChapter = this._getChapterAt(this.get_timeIndex() - 1);
            if (newChapter === -1) {
                // 1 second ago = before the first chapter in the list
                this.set_timeIndex(0);
            }
            else {
                this.set_currentChapter(newChapter);
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_clearMediaCache() {
        // some properties can't be set until the MediaElement has content
        if (this._muted !== null) {
            this._mediaElement.IsMuted = this._muted;
            this._muteButton.set_state(this._muted ? 1 : 0);
            this._muted = null;
        }
        if (this._volume !== null) {
            this._mediaElement.Volume = this._volume;
            this._dragVolume.set_value(this._volume);
            this._volume = null;
        }
        if (this._autoPlay !== null) {
            this._mediaElement.AutoPlay = this._autoPlay;
            this._autoPlay = null;
        }
        if (this._mediaUrl !== null) {
            this._loadMediaUrl(this._mediaUrl);
            this._mediaUrl = null
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_detectChapterChanged(currentTime) {
        if (this._lastChapterStarted !== this._currentChapter) {
            // may have skipped into a chapter
            this._lastChapterStarted = this._currentChapter;
            this._raiseChapterStarted(new Sys.Preview.UI.Xaml.Media.ChapterEventArgs(this._currentChapter));
        }
        else {
            // We think we're on the same chapter we last raised an event for. But natural progression of the media
            // or seeking operations may have put the position outside the bounds of this chapter.
            
            // DevDiv Bugs 126619: use a 0.001 second padding to prevent false chapter start detection
            if ((this._nextChapterTime !== -1 && currentTime >= (this._nextChapterTime - 0.001)) ||
                (this._currentChapterTime !== -1 && currentTime < (this._currentChapterTime - 0.001))) {
                // the time index jumped outside the bounds of the current chapter
                this._currentChapter = this._getChapterAt(currentTime, true);
                this._lastChapterStarted = this._currentChapter;
                this._raiseChapterStarted(new Sys.Preview.UI.Xaml.Media.ChapterEventArgs(this._currentChapter));
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_enableBuffering(enabled, percent) {
        if (enabled) {
            if (this._bufferingText) {
                this._bufferingText.Visibility = 0;
                this._bufferingText.Text = percent.toString();
            }
            if (!this._bufferingProgressVisible) {
                this._bufferingProgress.setVisible(true);
                if (this._bufferingStoryboard) this._bufferingStoryboard.begin();
            }
            this._bufferingProgressVisible = true;
        }
        else if (this._bufferingProgressVisible) {
            if (this._bufferingText) {
                this._bufferingText.Visibility = 1;
            }
            this._bufferingProgress.setVisible(false);
            if (this._bufferingStoryboard) this._bufferingStoryboard.stop();
            this._bufferingProgressVisible = false;
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_ensureCaption() {
        var showCaptions = this._toggledCaptions && this.get_enableCaptions();
        if (showCaptions) {
            var caption = this.get_caption();
            if (this._captionArea) {
                this._captionArea.set_text(caption);
            }
            if (this._captionAreaFS) {
                this._captionAreaFS.set_text(caption);
            }
        }
        else {
            if (this._captionArea) {
                this._captionArea.setVisible(false);
            }
            if (this._captionAreaFS) {
                this._captionAreaFS.setVisible(false);
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_ensureChapterArea() {
        var displayChapters = this._canSeek;
        if (displayChapters) {
            var chapters = this.get_chapters();
            if (chapters) {
                // we may have chapters but none have images. In that case don't show the chapter area.
                displayChapters = false;
                for (var i = 0, l = chapters.length; i < l; i++) {
                    if (chapters[i].imageUrl) {
                        displayChapters = true;
                        break;
                    }
                }
            }
        }
        
        if (displayChapters && !this._chaptersActive) {
            this._chapterArea.activate();
            this._chaptersActive = true;
        }
        else if(!displayChapters && this._chaptersActive) {
            this._chapterArea.deactivate();
            this._chapterArea.setVisible(false);
            this._chaptersActive = false;
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_ensureSeeking(canSeek) {
        // when media is opened that doesn't support seeking (e.g. live streams), disable seek related controls
        if (this._canSeek !== canSeek) {
            this._canSeek = canSeek;
            this._previousButton.set_enabled(canSeek);
            this._nextButton.set_enabled(canSeek);
            this._ensureChapterArea();
            // it might be that the slider should still show time progress, but not allow you to click on it to set the time
            this._dragTime.set_enableSeeking(canSeek);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_ensureDuration(hasDuration) {
        if (this._hasDuration !== hasDuration) {
            this._hasDuration = hasDuration;
            this._totalTimeText.setVisible(hasDuration);
            this._currentTimeText.setVisible(hasDuration);
            // when there is no duration (e.g. live feed) the time slider is meaningless.
            this._dragTime.set_enabled(hasDuration);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_formatTime(time) {
    	var hours = Math.floor(time / (1000*60*60));
    	var minutes = Math.floor(time / (1000*60)) - (hours*60);
    	var seconds = Math.floor(time / 1000) - (hours*60*60) - (minutes*60);
	    var timeString = "";
    	if (hours > 0) {
    	    timeString = hours < 10 ? ("0" + hours) : ("" + hours);
    	    timeString += ":";
    	}
        timeString += minutes < 10 ? ("0" + minutes) : ("" + minutes);
	    timeString += ":";
        timeString += seconds < 10 ? ("0" + seconds) : ("" + seconds);
	    return timeString;
    }

    function Sys$Preview$UI$Xaml$Media$Player$_fullScreenChanged(sender, eventArgs) {
        var fs = this._fsCanvas.get_control();
        if (!fs) return;
        if (this.get_element().content.fullScreen) {
            var rootTransform = this.get_element().content.root.RenderTransform;
            var rootX = 1;
            var rootY = 1;
            if (rootTransform && rootTransform.toString() === "ScaleTransform") {
                rootX = rootTransform.ScaleX;
                rootY = rootTransform.ScaleY;
            }
            
            var s = Sys.Preview.UI.Xaml.Control._computeScale(fs);
            var newXScale = s.horizontal / rootX;
            var newYScale = s.vertical / rootY;

            Sys.Preview.UI.Xaml.Control._ensureScale(fs, s.horizontal / rootX, s.vertical / rootY);

            var fsVideoWindow = this._fsVideoWindow.get_control();                        
            if (fsVideoWindow)  {
                var minScale = Math.min(s.horizontal, s.vertical);
                var scale = Math.min(s.horizontal / rootX, s.vertical / rootY);
                var offX = (fs.getHost().content.ActualWidth-fsVideoWindow.width*minScale)/2;
                var offY = (fs.getHost().content.ActualHeight-fsVideoWindow.height*minScale)/2;
                if (newXScale>newYScale)
                    Sys.Preview.UI.Xaml.Control._ensureMatrix(fsVideoWindow,
                        newYScale/newXScale,
                        1.0,
                        offX/s.horizontal,
                        offY/s.vertical);
                else
                    Sys.Preview.UI.Xaml.Control._ensureMatrix(fsVideoWindow,
                        1.0,
                        newXScale/newYScale,
                        offX/s.horizontal,
                        offY/s.vertical);
            }
            fs.Visibility = 0;
        }
        else {
            fs.Visibility = 1;
            // force updatePosition since we avoided doing this during fullscreen
            this._updatePosition();
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_getChapterAt(seconds, isCurrentTime) {
        var chapters = this.get_chapters();
        var chapterIndex = -1;
        seconds += 0.001;
        if (chapters) {
            for (var i=0, l=chapters.length; i < l; i++) {
                // adjust the time 0.001, because actual chapter time is not as accurate as the time you specify.
                // If you specify a chapter to start at 5s, it might actually start at 4.999s or 5.001s, for example.
                // In other words you are considered at a chapter if you are at least within 0.001 seconds of it.
                var t = chapters[i].time - 0.001;
                if (t <= seconds) {
                    chapterIndex = i;
                }
                else {
                    break;
                }
            }
        }
        // if seconds is the current time index, we store the next chapter's start time so the timer
        // knows when to raise the chapter changed event while the video is naturally seeking forward.
        // otherwise we'd have to constantly index the chapter collection to see if the chapter changed.
        if (isCurrentTime) {
            this._currentChapterTime = (chapterIndex >= 0) ? chapters[chapterIndex].time : -1;
            this._nextChapterTime = (chapterIndex < chapters.length-1) ? chapters[chapterIndex+1].time : -1;
        }
        return chapterIndex;
    }

    function Sys$Preview$UI$Xaml$Media$Player$_getMediaFailedError() {
        var displayMessage = "Sys.Preview.UI.Xaml.Media.MediaFailedException: " +
            String.format(Sys.Preview.UI.Xaml.Media.Res.mediaFailed, this.get_mediaUrl());
        var e = Error.create(displayMessage, { name: "Sys.Preview.UI.Xaml.Media.MediaFailedException", mediaUrl: this.get_mediaUrl() });
        e.popStackFrame();
        return e;
    }

    function Sys$Preview$UI$Xaml$Media$Player$_loadChapters(chapters, raiseEvent) {
        this._ensureChapterArea();
        this._chapterArea.setChapters(chapters);
        this._currentChapter = this._getChapterAt(this.get_timeIndex(), true);
        this._lastChapterStarted = -1;
        if (raiseEvent) {
            this._detectChapterChanged();
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_loadMediaUrl(url) {    
        this._currentChapter = -1;
        this._lastChapterStarted = -1;
        this._mediaElement.Source = url;
    }

    function Sys$Preview$UI$Xaml$Media$Player$_loadPlaceholderImage() {
        // show placeholder image over video
        var url = this.get_placeholderImage();
        if (url) {
            var img = this._imageElement.get_control();
            if (img) {
                img.Source = url;
                this._placeholderImageShowing = true;
                this._imageElement.setVisible(true);
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_onCaptionToggle() {
        this._toggledCaptions = !this._toggledCaptions;
        this._ensureCaption();
        this._captionButton.set_state(this._toggledCaptions ? 0 : 1);
    }

    function Sys$Preview$UI$Xaml$Media$Player$_onFullScreen() {
        var content = this.get_element().content;
        content.fullScreen = !content.fullScreen;
    }
    function Sys$Preview$UI$Xaml$Media$Player$_onFullScreenME() {
        // full screen request came from double clicking the media, which caused it to toggle play/pause
        // toggle once again to put back
        this.togglePlayPause();
        this._onFullScreen();
    }
    function Sys$Preview$UI$Xaml$Media$Player$_onTimeSliderChanged() {
        this.set_timeIndex(this._dragTime.get_value() * this._naturalduration);    
    }
    function Sys$Preview$UI$Xaml$Media$Player$_onVolumeDown() {
        this.set_volume(Math.max(0, this.get_volume() - 0.02));
    }
    function Sys$Preview$UI$Xaml$Media$Player$_onVolumeSliderChanged() {
        this.set_volume(this._dragVolume.get_value());
    }
    function Sys$Preview$UI$Xaml$Media$Player$_onVolumeUp() {
        this.set_volume(Math.min(1, this.get_volume() + 0.02));
    }

    function Sys$Preview$UI$Xaml$Media$Player$_mediaAvailable(available) {
        // when media is not available (e.g. it is closed or none was opened from the start), disable player controls
        if (this._mediaOpened !== available) {
            this._mediaOpened = available;
            this._playPauseButton.set_enabled(available);
            this._playButton.set_enabled(available);
            this._pauseButton.set_enabled(available);
            this._stopButton.set_enabled(available);
            if (!available) {
                this.set_caption("");
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_meBufferingProgress() {
        var progress = this._mediaElement.bufferingProgress;
        var percent = Math.round(progress * 100);
        if (percent >= 100) {
            this._enableBuffering(false);
        }
        else {
            this._enableBuffering(true, percent);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_meDownloadProgress() {
        // progressive download occuring, means there is no buffering. They don't occur at the same time.
        this._enableBuffering(false);
        this._downloadProgress.set_value(this._mediaElement.downloadProgress);
    }

    function Sys$Preview$UI$Xaml$Media$Player$_meMarkerReached(sender, args) {
        this._raiseMarkerReached(new Sys.Preview.UI.Xaml.Media.MarkerEventArgs(args.marker));
    }

    function Sys$Preview$UI$Xaml$Media$Player$_meMediaEnded() {
        this._mediaEnded = true;
        this._raiseEvent("mediaEnded", Sys.EventArgs.Empty);
    }

    function Sys$Preview$UI$Xaml$Media$Player$_meMediaFailed() {   
        this._naturalduration = null;
        this._enableBuffering(false);
        this._mediaAvailable(false);
        this._ensureDuration(false);
        this._ensureSeeking(false);
        this._mediaEnded = false;
        // existing captions should be cleared if the media fails to open
        this.set_caption("");
        
        var handler = this.get_events().getHandler('mediaFailed');
        if (handler) {
            handler(this, Sys.EventArgs.Empty);
        }
        else {
            throw this._getMediaFailedError();
        }   
    }

    function Sys$Preview$UI$Xaml$Media$Player$_meMediaOpened() {
        // note: this event may occur multiple times with a single mediaurl, if its an ASX stream with multiple entries.
        
        this._mediaEnded = false;
        // make sure properties set before hand are now copied in (e.g. Volume cant be set until media is loaded)
        this._clearMediaCache();
        // if a placeholder is showing, remove it
        if (this._placeholderImageShowing) {
            this._imageElement.setVisible(false);
            this._placeholderImageShowing = false;
        }
        // existing captions should be cleared if a new media file is opened
        this.set_caption("");
        
        // load markers in the head of the media
        this._markers = [];
        var markers = this._mediaElement.Markers;
        for (var i = 0, l = markers.Count; i < l; i++) {
            Array.add(this._markers, markers.getItem(i));
        }

        this._naturalduration = this._mediaElement.naturalduration.seconds;
        var hasDuration = !!this._naturalduration;
        var canSeek = hasDuration && this._mediaElement.CanSeek;
        if (canSeek) {
            // if seeking is supported, initialize chapter detection
            this._currentChapter = this._getChapterAt(0, true);
            this._lastChapterStarted = -1;
            this._detectChapterChanged();
	    }
	    if (hasDuration) {
            // and set the total/current time labels
            this._totalTimeText.set_text(this._formatTime(this._naturalduration * 1000));
            this._currentTimeText.set_text(this._formatTime(this.get_timeIndex() * 1000));
            this._dragTime.set_value(this.get_timeIndex() / this._naturalduration);
	    }
	    
	    // make sure player controls are in the right state
	    this._mediaAvailable(true);
	    this._ensureDuration(hasDuration);
	    this._ensureSeeking(canSeek);

        // hookup timer for monitoring time index (for chapter detection, time slider and currenttimetext updates)
        if (!this._timerCookie) {
            this._tickTimerDelegate = Function.createDelegate(this, this._tickTimer);
            this._timerCookie = window.setTimeout(this._tickTimerDelegate, 200);
        }
        this._raiseEvent("mediaOpened", Sys.EventArgs.Empty);
    }

    function Sys$Preview$UI$Xaml$Media$Player$_meStateChanged() {
        var newState = this.get_playState();
        if (newState === "Closed") {
            this._enableBuffering(false);
            this._mediaAvailable(false);
            this._ensureSeeking(false);
            this._mediaEnded = false;
        }
        else if (newState === "Playing" || newState === "Paused") {
            // playing/paused, make sure buffering area is hidden
            this._enableBuffering(false);
        }
        
        var oldState = this._oldState || "";
        if (newState !== oldState) {
            this._oldState = newState;
            this._raisePlayStateChanged(new Sys.Preview.UI.Xaml.Media.StateChangedEventArgs("playState", oldState, newState));
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_raiseChapterStarted(chapterEventArgs) {
        this.onChapterStarted(chapterEventArgs);
        this._raiseEvent("chapterStarted", chapterEventArgs);
        this.raisePropertyChanged("currentChapter");
    }

    function Sys$Preview$UI$Xaml$Media$Player$_raiseEvent(name, args) {
        var handler = this.get_events().getHandler(name);
        if (handler) {
            handler(this, args);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_raiseMarkerReached(args) {
        if (this._toggledCaptions && this.get_enableCaptions()) {
            var marker = args.get_marker();
            var type = marker.type ? marker.type.toLowerCase() : "";
            if (type === "caption") {
                if (!this._enabledCaptionToggleButton) {
                    this._enabledCaptionToggleButton = true;
                    this._captionButton.setVisible(true);
                }
                var text = marker.text ? marker.text : "";
                if (text.trim().length === 0) {
                    text = "";
                }
                this.set_caption(text);
                this.raisePropertyChanged("caption");
            }
        }

        this.onMarkerReached(args);
        this._raiseEvent("markerReached", args);
    }

    function Sys$Preview$UI$Xaml$Media$Player$_raisePlayStateChanged(args) {
        this._playPauseButton.set_state(args.get_currentState() === "Playing" ? 1/*pause*/ : 0/*play*/);
        
        this.onPlayStateChanged(args);
        this._raiseEvent("stateChanged", args);
        this._raiseEvent("propertyChanged", args);
    }

    function Sys$Preview$UI$Xaml$Media$Player$_raiseVolumeChanged(args) {
        this.onVolumeChanged(args);
        this._raiseEvent("volumeChanged", args);
        this.raisePropertyChanged("volume");
    }

    function Sys$Preview$UI$Xaml$Media$Player$_skipTime(direction) {
        // skipping always skips by 10% of the total duration
        var delta = this._naturalduration / 10;
        // always skip by at least 5 seconds
        delta = direction * Math.max(5, delta);
        var newTime = delta + this.get_timeIndex();
        this.set_timeIndex(newTime);
    }

    function Sys$Preview$UI$Xaml$Media$Player$_tickTimer() {
        this._timerCookie = window.setTimeout(this._tickTimerDelegate, 200);
        if (this._forceUpdate || (this.get_playState() === "Playing")) {
            this._forceUpdate = false;
            this._updatePosition();
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_updatePosition() {
        var time = null;
        if (!this.get_element().content.fullScreen && this._hasDuration) {
            time = this.get_timeIndex();
            if (!this._dragTime._isDragging) {
                this._dragTime.set_value(time / this._naturalduration);
            }
            this._updateTime(time);
        }
        if (this._canSeek) {
            if (time === null) {
                time = this.get_timeIndex();
            }
            this._detectChapterChanged(time);
        }
    }

    function Sys$Preview$UI$Xaml$Media$Player$_updateTime(time) {
        this._currentTimeText.set_text(this._formatTime(time * 1000));
    }
Sys.Preview.UI.Xaml.Media.Player.prototype = {
    _mediaEnded: false,
    _naturalduration: null,
    _domElements: null,
    _timerCookie: null,
    _mediaOpened: true,
    _enabledCaptionToggleButton: false,
    _autoPlay: null,
    _canSeek: true,
    _hasDuration: true,
    _caption: null,
    _chapters: null,
    _currentChapter: -1,
    _lastChapterStarted: -1,
    _nextChapterTime: -1,
    _currentChapterTime: -1,
    _enableCaptions: true,
    _toggledCaptions: true,
    _mediaMarkers: null,
    _mediaUrl: null,
    _muted: null,
    _placeholderImage: null,
    _imageElement: null,
    _volume: null,
    _chaptersActive: false,
    _bufferingProgressVisible: false,
    // controls
    _bufferingProgress: null,
    _bufferingStoryboard: null,
    _bufferingText: null,
    _captionButton: null,
    _captionArea: null,
    _captionAreaFS: null,
    _chapterArea: null,
    _currentTimeText: null,
    _downloadProgress: null,
    _dragTime: null,
    _dragVolume: null,
    _mediaElement: null,
    _muteButton: null,
    _nextButton: null,
    _playPauseButton: null,
    _playButton: null,
    _pauseButton: null,
    _stopButton: null,
    _previousButton: null,
    _totalTimeText: null,
    
    add_chapterStarted: Sys$Preview$UI$Xaml$Media$Player$add_chapterStarted,
    remove_chapterStarted: Sys$Preview$UI$Xaml$Media$Player$remove_chapterStarted,

    add_markerReached: Sys$Preview$UI$Xaml$Media$Player$add_markerReached,
    remove_markerReached: Sys$Preview$UI$Xaml$Media$Player$remove_markerReached,

    add_mediaEnded: Sys$Preview$UI$Xaml$Media$Player$add_mediaEnded,
    remove_mediaEnded: Sys$Preview$UI$Xaml$Media$Player$remove_mediaEnded,

    add_mediaFailed: Sys$Preview$UI$Xaml$Media$Player$add_mediaFailed,
    remove_mediaFailed: Sys$Preview$UI$Xaml$Media$Player$remove_mediaFailed,

    add_mediaOpened: Sys$Preview$UI$Xaml$Media$Player$add_mediaOpened,
    remove_mediaOpened: Sys$Preview$UI$Xaml$Media$Player$remove_mediaOpened,

    add_stateChanged: Sys$Preview$UI$Xaml$Media$Player$add_stateChanged,
    remove_stateChanged: Sys$Preview$UI$Xaml$Media$Player$remove_stateChanged,

    add_volumeChanged: Sys$Preview$UI$Xaml$Media$Player$add_volumeChanged,
    remove_volumeChanged: Sys$Preview$UI$Xaml$Media$Player$remove_volumeChanged,

    get_autoPlay: Sys$Preview$UI$Xaml$Media$Player$get_autoPlay,
    set_autoPlay: Sys$Preview$UI$Xaml$Media$Player$set_autoPlay,

    get_caption: Sys$Preview$UI$Xaml$Media$Player$get_caption,
    set_caption: Sys$Preview$UI$Xaml$Media$Player$set_caption,

    get_chapters: Sys$Preview$UI$Xaml$Media$Player$get_chapters,
    set_chapters: Sys$Preview$UI$Xaml$Media$Player$set_chapters,

    get_currentChapter: Sys$Preview$UI$Xaml$Media$Player$get_currentChapter,
    set_currentChapter: Sys$Preview$UI$Xaml$Media$Player$set_currentChapter,

    get_enableCaptions: Sys$Preview$UI$Xaml$Media$Player$get_enableCaptions,
    set_enableCaptions: Sys$Preview$UI$Xaml$Media$Player$set_enableCaptions,
    
    get_mediaMarkers: Sys$Preview$UI$Xaml$Media$Player$get_mediaMarkers,
    
    get_mediaElement: Sys$Preview$UI$Xaml$Media$Player$get_mediaElement,

    get_mediaUrl: Sys$Preview$UI$Xaml$Media$Player$get_mediaUrl,
    set_mediaUrl: Sys$Preview$UI$Xaml$Media$Player$set_mediaUrl,

    get_muted: Sys$Preview$UI$Xaml$Media$Player$get_muted,
    set_muted: Sys$Preview$UI$Xaml$Media$Player$set_muted,

    get_placeholderImage: Sys$Preview$UI$Xaml$Media$Player$get_placeholderImage,
    set_placeholderImage: Sys$Preview$UI$Xaml$Media$Player$set_placeholderImage,

    get_playState: Sys$Preview$UI$Xaml$Media$Player$get_playState,

    get_timeIndex: Sys$Preview$UI$Xaml$Media$Player$get_timeIndex,
    set_timeIndex: Sys$Preview$UI$Xaml$Media$Player$set_timeIndex,
    
    get_volume: Sys$Preview$UI$Xaml$Media$Player$get_volume,
    set_volume: Sys$Preview$UI$Xaml$Media$Player$set_volume,

    nextChapter: Sys$Preview$UI$Xaml$Media$Player$nextChapter,

    onChapterStarted: Sys$Preview$UI$Xaml$Media$Player$onChapterStarted,

    onMarkerReached: Sys$Preview$UI$Xaml$Media$Player$onMarkerReached,

    onPlayStateChanged: Sys$Preview$UI$Xaml$Media$Player$onPlayStateChanged,

    onVolumeChanged: Sys$Preview$UI$Xaml$Media$Player$onVolumeChanged,

    pause: Sys$Preview$UI$Xaml$Media$Player$pause,

    play: Sys$Preview$UI$Xaml$Media$Player$play,

    previousChapter: Sys$Preview$UI$Xaml$Media$Player$previousChapter,
    
    stop: Sys$Preview$UI$Xaml$Media$Player$stop,

    toggleMuted: Sys$Preview$UI$Xaml$Media$Player$toggleMuted,

    togglePlayPause: Sys$Preview$UI$Xaml$Media$Player$togglePlayPause,
    
    xamlDispose: Sys$Preview$UI$Xaml$Media$Player$xamlDispose,   

    xamlInitialize: Sys$Preview$UI$Xaml$Media$Player$xamlInitialize,

    _bindChildControls: Sys$Preview$UI$Xaml$Media$Player$_bindChildControls,
    
    _chapterNext: Sys$Preview$UI$Xaml$Media$Player$_chapterNext,
        
    _chapterPrevious: Sys$Preview$UI$Xaml$Media$Player$_chapterPrevious,
    
    _clearMediaCache: Sys$Preview$UI$Xaml$Media$Player$_clearMediaCache,
    
    _detectChapterChanged: Sys$Preview$UI$Xaml$Media$Player$_detectChapterChanged,

    _enableBuffering: Sys$Preview$UI$Xaml$Media$Player$_enableBuffering,
    
    _ensureCaption: Sys$Preview$UI$Xaml$Media$Player$_ensureCaption,

    _ensureChapterArea: Sys$Preview$UI$Xaml$Media$Player$_ensureChapterArea,
    
    _ensureSeeking: Sys$Preview$UI$Xaml$Media$Player$_ensureSeeking,
    
    _ensureDuration: Sys$Preview$UI$Xaml$Media$Player$_ensureDuration,

    _formatTime: Sys$Preview$UI$Xaml$Media$Player$_formatTime,

    _fullScreenChanged: Sys$Preview$UI$Xaml$Media$Player$_fullScreenChanged,
    
    _getChapterAt: Sys$Preview$UI$Xaml$Media$Player$_getChapterAt,
    
    _getMediaFailedError: Sys$Preview$UI$Xaml$Media$Player$_getMediaFailedError,

    _loadChapters: Sys$Preview$UI$Xaml$Media$Player$_loadChapters,

    _loadMediaUrl: Sys$Preview$UI$Xaml$Media$Player$_loadMediaUrl,    
    
    _loadPlaceholderImage: Sys$Preview$UI$Xaml$Media$Player$_loadPlaceholderImage,
    
    _onCaptionToggle: Sys$Preview$UI$Xaml$Media$Player$_onCaptionToggle,

    _onFullScreen: Sys$Preview$UI$Xaml$Media$Player$_onFullScreen,
    _onFullScreenME: Sys$Preview$UI$Xaml$Media$Player$_onFullScreenME,
    _onTimeSliderChanged: Sys$Preview$UI$Xaml$Media$Player$_onTimeSliderChanged,
    _onVolumeDown: Sys$Preview$UI$Xaml$Media$Player$_onVolumeDown,
    _onVolumeSliderChanged: Sys$Preview$UI$Xaml$Media$Player$_onVolumeSliderChanged,
    _onVolumeUp: Sys$Preview$UI$Xaml$Media$Player$_onVolumeUp,
    
    _mediaAvailable: Sys$Preview$UI$Xaml$Media$Player$_mediaAvailable,

    _meBufferingProgress: Sys$Preview$UI$Xaml$Media$Player$_meBufferingProgress,
    
    _meDownloadProgress: Sys$Preview$UI$Xaml$Media$Player$_meDownloadProgress,

    _meMarkerReached: Sys$Preview$UI$Xaml$Media$Player$_meMarkerReached,
    
    _meMediaEnded: Sys$Preview$UI$Xaml$Media$Player$_meMediaEnded,

    _meMediaFailed: Sys$Preview$UI$Xaml$Media$Player$_meMediaFailed,

    _meMediaOpened: Sys$Preview$UI$Xaml$Media$Player$_meMediaOpened,
    
    _meStateChanged: Sys$Preview$UI$Xaml$Media$Player$_meStateChanged,
    
    _raiseChapterStarted: Sys$Preview$UI$Xaml$Media$Player$_raiseChapterStarted,
    
    _raiseEvent: Sys$Preview$UI$Xaml$Media$Player$_raiseEvent,
    
    _raiseMarkerReached: Sys$Preview$UI$Xaml$Media$Player$_raiseMarkerReached,
    
    _raisePlayStateChanged: Sys$Preview$UI$Xaml$Media$Player$_raisePlayStateChanged,    
    
    _raiseVolumeChanged: Sys$Preview$UI$Xaml$Media$Player$_raiseVolumeChanged,
    
    _skipTime: Sys$Preview$UI$Xaml$Media$Player$_skipTime,
    
    _tickTimer: Sys$Preview$UI$Xaml$Media$Player$_tickTimer,
    
    _updatePosition: Sys$Preview$UI$Xaml$Media$Player$_updatePosition,
    
    _updateTime: Sys$Preview$UI$Xaml$Media$Player$_updateTime
}
Sys.Preview.UI.Xaml.Media.Player._defaultVolume = 0.5;
Sys.Preview.UI.Xaml.Media.Player.registerClass('Sys.Preview.UI.Xaml.Media.Player', Sys.Preview.UI.Xaml.Control);

Sys.Preview.UI.Xaml.Media.StateChangedEventArgs = function Sys$Preview$UI$Xaml$Media$StateChangedEventArgs(propertyName, previousState, currentState) {
    /// <param name="propertyName" type="String"></param>
    /// <param name="previousState"></param>
    /// <param name="currentState"></param>
    var e = Function._validateParams(arguments, [
        {name: "propertyName", type: String},
        {name: "previousState"},
        {name: "currentState"}
    ]);
    if (e) throw e;

    this._currentState = currentState;
    this._previousState = previousState;
    Sys.Preview.UI.Xaml.Media.StateChangedEventArgs.initializeBase(this, [propertyName]);
}

    function Sys$Preview$UI$Xaml$Media$StateChangedEventArgs$get_currentState() {
        /// <value></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._currentState || null;
    }
    function Sys$Preview$UI$Xaml$Media$StateChangedEventArgs$get_previousState() {
        /// <value></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._previousState || null;
    }
Sys.Preview.UI.Xaml.Media.StateChangedEventArgs.prototype = {
    get_currentState: Sys$Preview$UI$Xaml$Media$StateChangedEventArgs$get_currentState,
    get_previousState: Sys$Preview$UI$Xaml$Media$StateChangedEventArgs$get_previousState
}
Sys.Preview.UI.Xaml.Media.StateChangedEventArgs.registerClass("Sys.Preview.UI.Xaml.Media.StateChangedEventArgs", Sys.PropertyChangedEventArgs);
Sys.Preview.UI.Xaml.Media.ChapterEventArgs = function Sys$Preview$UI$Xaml$Media$ChapterEventArgs(chapterIndex) {
    /// <param name="chapterIndex" type="Number"></param>
    var e = Function._validateParams(arguments, [
        {name: "chapterIndex", type: Number}
    ]);
    if (e) throw e;

    this._chapterIndex = chapterIndex;
    Sys.Preview.UI.Xaml.Media.ChapterEventArgs.initializeBase(this);
}

    function Sys$Preview$UI$Xaml$Media$ChapterEventArgs$get_chapterIndex() {
        /// <value type="Number"></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._chapterIndex;
    }
Sys.Preview.UI.Xaml.Media.ChapterEventArgs.prototype = {
    get_chapterIndex: Sys$Preview$UI$Xaml$Media$ChapterEventArgs$get_chapterIndex
}
Sys.Preview.UI.Xaml.Media.ChapterEventArgs.registerClass("Sys.Preview.UI.Xaml.Media.ChapterEventArgs", Sys.EventArgs);
Sys.Preview.UI.Xaml.Media.MarkerEventArgs = function Sys$Preview$UI$Xaml$Media$MarkerEventArgs(marker) {
    /// <param name="marker"></param>
    var e = Function._validateParams(arguments, [
        {name: "marker"}
    ]);
    if (e) throw e;

    this._marker = marker;
    Sys.Preview.UI.Xaml.Media.MarkerEventArgs.initializeBase(this);
}

    function Sys$Preview$UI$Xaml$Media$MarkerEventArgs$get_marker() {
        /// <value></value>
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._marker || null;
    }
Sys.Preview.UI.Xaml.Media.MarkerEventArgs.prototype = {
    get_marker: Sys$Preview$UI$Xaml$Media$MarkerEventArgs$get_marker
}
Sys.Preview.UI.Xaml.Media.MarkerEventArgs.registerClass("Sys.Preview.UI.Xaml.Media.MarkerEventArgs", Sys.EventArgs);

Sys.Preview.UI.Xaml.Media._TextBlock = function Sys$Preview$UI$Xaml$Media$_TextBlock(host, textBlockElementName, backgroundElementName) {
    // <param name="host">Silverlight host</param>
    // <param name="textBlockElementName" type="String">Name of XAML TextBlock</param>
    // <param name="backgroundElementName" type="String" optional="true" mayBeNull="true">Name of XAML element that will serve as a background for the text block, if any</param>
    Sys.Preview.UI.Xaml.Media._TextBlock.initializeBase(this, [host, textBlockElementName]);
    var control = this.get_control();
    if (control && backgroundElementName) {
        var bg = control.findName(backgroundElementName);
        if (bg) {
            this._centerX = bg["Canvas.Left"] + bg.width / 2;
            this._bottomY = bg["Canvas.Top"] + bg.height;
            this._background = bg;
        }
    }
    if (control && !this._background) {
        this._centerX = control["Canvas.Left"] + control.ActualWidth / 2;
        this._bottomY = control["Canvas.Top"] + control.ActualHeight;
        this._background = control;
    }
}





    function Sys$Preview$UI$Xaml$Media$_TextBlock$get_backgroundControl() {
        if (arguments.length !== 0) throw Error.parameterCount();
        // <value mayBeNull="true">The Silverlight control that acts as the background for the text block.</value>
        return this._background || null;
    }

    function Sys$Preview$UI$Xaml$Media$_TextBlock$get_text() {
        if (arguments.length !== 0) throw Error.parameterCount();
        // <value type="String" mayBeNull="true"></value>
        var control = this.get_control();
        return control ? (control.Text || "") : "";
    }
    function Sys$Preview$UI$Xaml$Media$_TextBlock$set_text(value) {
        var control = this.get_control();
        if (control) {
            control.Text = value || "";
            this.setVisible(!!value);
            var bg = this.get_backgroundControl();
            if (bg) {
                var x = control.ActualWidth;
                var y = control.ActualHeight;
                bg["Canvas.Left"] = this._centerX - x / 2;
                bg["Canvas.Top"] = this._bottomY - y;
                bg.width = x;
                bg.height = y;
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$_TextBlock$dispose() {
        Sys.Preview.UI.Xaml.Media._TextBlock.callBaseMethod(this, "dispose");
        this._background = null;
    }

    function Sys$Preview$UI$Xaml$Media$_TextBlock$setVisible(value) {
        Sys.Preview.UI.Xaml.Media._TextBlock.callBaseMethod(this, "setVisible", [value]);
        var c = this.get_backgroundControl();
        if (c) c.visibility = value ? 0 : 1;        
    }
Sys.Preview.UI.Xaml.Media._TextBlock.prototype = {
    _centerX: 0,
    _bottomY: 0,
    _background: null,
    
    get_backgroundControl: Sys$Preview$UI$Xaml$Media$_TextBlock$get_backgroundControl,
    
    get_text: Sys$Preview$UI$Xaml$Media$_TextBlock$get_text,
    set_text: Sys$Preview$UI$Xaml$Media$_TextBlock$set_text,

    dispose: Sys$Preview$UI$Xaml$Media$_TextBlock$dispose,
    
    setVisible: Sys$Preview$UI$Xaml$Media$_TextBlock$setVisible
}
Sys.Preview.UI.Xaml.Media._TextBlock.registerClass('Sys.Preview.UI.Xaml.Media._TextBlock', Sys.Preview.UI.Xaml.Media._DomElement);
Sys.Preview.UI.Xaml.Media._MultiStateButton = function Sys$Preview$UI$Xaml$Media$_MultiStateButton(host, nameElement, autorepeatInterval, clickHandler, doubleClickHandler, handlerOwner, stateList) {
    Sys.Preview.UI.Xaml.Media._MultiStateButton.initializeBase(this, [host, nameElement, autorepeatInterval, clickHandler, doubleClickHandler, handlerOwner]);
    // animations for state changes
    var stateCount = arguments.length-6;
    
    
    this._animationsOn = new Array(stateCount);
    this._animationsOff = new Array(stateCount);
    this._controls = new Array(stateCount);

    var control = this.get_control();
    for (var i = 0; i < stateCount; i++) {
        var nameControl = arguments[i + 6];
        var ctl = control ? control.findName(nameControl) : null;
        // check for (control)_Show and (control)_Hide
        this._controls[i] = ctl || null;
        this._animationsOn[i] = ctl ? ctl.findName(nameControl + "_Show") : null;
        this._animationsOff[i] = ctl ? ctl.findName(nameControl + "_Hide") : null;
    }
}






    function Sys$Preview$UI$Xaml$Media$_MultiStateButton$get_state() {
        if (arguments.length !== 0) throw Error.parameterCount();
        // <value type="Number" integer="true">current button state</value>
        return this._state;
    }
    function Sys$Preview$UI$Xaml$Media$_MultiStateButton$set_state(value) {
        
        if (value !== this._state) {
            var a = this._animationsOff[this._state];
            if (a) {
                a.begin();
            }
            else {
                var cOff = this._controls[this._state];
                if (cOff) cOff.visibility = 1;
            }
            this._state = value;
            a = this._animationsOn[this._state];
            if (a) {
                a.begin();
            }
            else {
                var cOn = this._controls[this._state];
                if (cOn) cOn.visibility = 0;
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$_MultiStateButton$dispose() {
        Sys.Preview.UI.Xaml.Media._MultiStateButton.callBaseMethod(this, "dispose");
        this._animationsOn = null;
        this._animationsOff = null;
        this._controls = null;
        this._state = 0;
    }
Sys.Preview.UI.Xaml.Media._MultiStateButton.prototype = {
    _state: 0,
    _animationsOn: null,
    _animationsOff: null,
    _controls: null,
    
    get_state: Sys$Preview$UI$Xaml$Media$_MultiStateButton$get_state,
    set_state: Sys$Preview$UI$Xaml$Media$_MultiStateButton$set_state,
    
    dispose: Sys$Preview$UI$Xaml$Media$_MultiStateButton$dispose
}
Sys.Preview.UI.Xaml.Media._MultiStateButton.registerClass('Sys.Preview.UI.Xaml.Media._MultiStateButton', Sys.Preview.UI.Xaml.Media._Button);

Sys.Preview.UI.Xaml.Media._ImageList = function Sys$Preview$UI$Xaml$Media$_ImageList(host, imageListName) {
    // Implements the script required to drive a horizontal ImageList.
    // The ImageList is xaml that contains the following structure:
    // TODO: explaination
    Sys.Preview.UI.Xaml.Media._ImageList.initializeBase(this, [host, imageListName]);
    var control = this.get_control();
    if (!control) return;
    control.cursor = "Arrow";

    this._scrollAnimationSB = control.findName(imageListName + "_ScrollAnimationStoryboard");
    if (this._scrollAnimationSB) this._scrollAnimation = control.findName(imageListName + "_ScrollAnimation");
    
    var interval = this._scrollAnimation ? (this._scrollAnimation.duration.seconds*1000) : 200;
    interval = Math.max(interval, 200);
    this._scrollNext = new Sys.Preview.UI.Xaml.Media._Button(host, imageListName + "_ScrollNext", interval, this._scrollNextClick, null, this);
	this._scrollPrev = new Sys.Preview.UI.Xaml.Media._Button(host, imageListName + "_ScrollPrevious", interval, this._scrollPrevClick, null, this);
	
	this._findItems(imageListName);
	this._virtualItems = [];
}











    function Sys$Preview$UI$Xaml$Media$_ImageList$get_items() {
        if (arguments.length !== 0) throw Error.parameterCount();
        return this._virtualItems;
    }
    function Sys$Preview$UI$Xaml$Media$_ImageList$set_items(value) {
        this._virtualItems = Array.clone(value);
        this._reset();
        this._assignImages();
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$onItemClick(virtualIndex) {
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_assignImages() {
        for (var i = 0, l = this._items.length; i < l; i++) {
            var item = this._items[i];
            var offset = this._itemOffset + i;
            if (offset < this._virtualItems.length) {
                item.image.Source = this._virtualItems[offset];
                item.button.get_control().visibility = 0; // visible
                item.button._virtualIndex = offset;
            }
            else {
                item.button.get_control().visibility = 1; // collapsed
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_findItems(baseName) {
        var control = this.get_control();
        var i = 1;
        this._items = [];
        var itemName = baseName + "_ScrollItem1",
            imageName = baseName + "_ScrollItem1_Image",
            item = control.findName(itemName),
            image = control.findName(imageName);

        while(item) {
            var btn = new Sys.Preview.UI.Xaml.Media._Button(
                        control.getHost(), itemName, null,
                        this._itemClick, null, this, /*requiresSender*/true);
            btn._physicalIndex = i-1;
            this._items[this._items.length] = { button: btn, image: image };
            i++;
            itemName = baseName + "_ScrollItem" + i;
            imageName = baseName + "_ScrollItem" + i + "_Image";
            item = control.findName(itemName);
            image = control.findName(imageName);
        }

        if (this._items.length === 0) {
            throw Error.invalidOperation("ImageList needs at least one scroll item.");
        }

        var firstItem = this._items[0].button.get_control();
        this._itemSize = firstItem.width;
        //this._itemSpacing = (firstItem["Canvas.Left"] - firstItem.getParent()["Canvas.Left"]) * 2;
        this._itemSpacing = firstItem["Canvas.Left"] * 2;
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_handleOverflow(direction) {
        // ensures the overflow item is in the right position
        
        // determine virtual index of the overflow item
        var layoutIndex = direction === 1 ? (this._items.length-1) : -1;
        var virtualIndex = this._itemOffset + layoutIndex;
        
        // assign virtual item data to the overflow item
        var overflowItem = this._items[this._overflowIndex];
        overflowItem.image.Source = this._virtualItems[virtualIndex];
        overflowItem.button._virtualIndex = virtualIndex;
        
        // position the overflow item
        var button = overflowItem.button.get_control();
        button["Canvas.Left"] = virtualIndex * (this._itemSize + this._itemSpacing) + (this._itemSpacing / 2);
        
        // overflow item is no longer an overflow item, advance the index
        this._overflowIndex += direction;
        if (this._overflowIndex < 0) {
            this._overflowIndex = this._items.length - 1;
        }
        else if (this._overflowIndex >= this._items.length) {
            this._overflowIndex = 0;
        }
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_itemClick(sender) {
        // sender given because Button was instantiated with requiresSender=true
        this.onItemClick(sender._virtualIndex);
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_reset() {
	    this._itemOffset = 0;
	    for (var i = 0, l = this._items.length; i < l; i++) {
	        var button = this._items[i].button;
	        button._virtualIndex = i;
    	    button.get_control()["Canvas.Left"] = i * (this._itemSize + this._itemSpacing) + (this._itemSpacing/2);
	    }
	    this._overflowIndex = this._items.length - 1;
	    // ensure scrolled to the beginning
        if (this._scrollAnimation) {
            this._scrollAnimation.To = "0";
            this._scrollAnimationSB.begin();
        }
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_scroll(direction) {
        if (this._scrollAnimation) {
            this._handleOverflow(direction);

            var fromOffset = this._itemOffset;
            this._itemOffset += direction;

            this._scrollAnimation.From = "-" + (fromOffset * (this._itemSize + this._itemSpacing));
            this._scrollAnimation.To = "-" + (this._itemOffset * (this._itemSize + this._itemSpacing));
            this._scrollAnimationSB.begin();
        }
        else {
            this._itemOffset += direction;
            this._assignImages();            
        }
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_scrollNextClick() {
        if (this._itemOffset < (this._virtualItems.length - this._items.length + 1)) {
            this._scroll(1);
        }
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$_scrollPrevClick() {
        if (this._itemOffset > 0) {
            this._scroll(-1);
        }
    }

    function Sys$Preview$UI$Xaml$Media$_ImageList$dispose() {
        if (this._scrollNext) this._scrollNext.dispose();
        if (this._scrollPrev) this._scrollPrev.dispose();
        this._scrollNext = null;
        this._scrollPrev = null;

        if (this._items) {
            for (var i = 0, l = this._items.length; i < l; i++) {
                var button = this._items[i].button;
                button.dispose();
            }
            this._items = null;
        }     
        this._virtualItems = null;
        this._itemSize = null;
        this._itemSpacing = null;
        this._scrollAnimation = null;
        this._scrollAnimationSB = null;
        Sys.Preview.UI.Xaml.Media._ImageList.callBaseMethod(this, "dispose");
    }
Sys.Preview.UI.Xaml.Media._ImageList.prototype = {
    _items: null,
    _virtualItems: null,
    _scrollNext: null,
    _scrollPrev: null,
    _scrollAnimation: null,
    _scrollAnimationSB: null,
    _itemSize: 0,
    _itemSpacing: 0,
    _overflowIndex: 0,
    
    get_items: Sys$Preview$UI$Xaml$Media$_ImageList$get_items,
    set_items: Sys$Preview$UI$Xaml$Media$_ImageList$set_items,
    
    onItemClick: Sys$Preview$UI$Xaml$Media$_ImageList$onItemClick,    
    
    _assignImages: Sys$Preview$UI$Xaml$Media$_ImageList$_assignImages,
    
    _findItems: Sys$Preview$UI$Xaml$Media$_ImageList$_findItems,
    
    _handleOverflow: Sys$Preview$UI$Xaml$Media$_ImageList$_handleOverflow,
    
    _itemClick: Sys$Preview$UI$Xaml$Media$_ImageList$_itemClick,
    
    _reset: Sys$Preview$UI$Xaml$Media$_ImageList$_reset,
    
    _scroll: Sys$Preview$UI$Xaml$Media$_ImageList$_scroll,
    
    _scrollNextClick: Sys$Preview$UI$Xaml$Media$_ImageList$_scrollNextClick,
    
    _scrollPrevClick: Sys$Preview$UI$Xaml$Media$_ImageList$_scrollPrevClick,

    dispose: Sys$Preview$UI$Xaml$Media$_ImageList$dispose
}
Sys.Preview.UI.Xaml.Media._ImageList.registerClass('Sys.Preview.UI.Xaml.Media._ImageList', Sys.Preview.UI.Xaml.Media._DomElement);
Sys.Preview.UI.Xaml.Media._ChapterArea = function Sys$Preview$UI$Xaml$Media$_ChapterArea(player) {
    this._player = player;
    var names = Sys.Preview.UI.Xaml.Media.PlayerElementName;
    Sys.Preview.UI.Xaml.Media._ChapterArea.initializeBase(this, [player.get_element(), names.chapterArea]);
    var control = this.get_control();
    if (control) {
        this._toggleButton = new Sys.Preview.UI.Xaml.Media._Button(player.get_element(), names.chapterToggleButton, null, this._onToggle, null, this);
    }
}





    function Sys$Preview$UI$Xaml$Media$_ChapterArea$activate() {
        // activate means there are chapters to be shown, so the chapter area should be 'activated', but not necessarily visible.
        // for example, a chapter area that is only visible when the mouse is over it. It should be active in that it shows when you
        // hover over it, but not always visible. We use visibility to activate/deactivate, the skin defines its own _Hide and _Show
        // animation which we control via the toggle button (or they could define a MouseEnter MouseLeave for simply reveal opacity).
        // If there are no chapters for the media, the chapter area is deactivated (e.g. so no hover occurs) and the toggle button is
        // hidden (if it exists).
        var c = this.get_control();
        if (!c) return;
        c.visibility = 0;
        this._toggleButton.setVisible(true);
    }

    function Sys$Preview$UI$Xaml$Media$_ChapterArea$deactivate() {
        var c = this.get_control();
        if (!c) return;
        c.visibility = 1;
        this._toggleButton.setVisible(false);
    }

    function Sys$Preview$UI$Xaml$Media$_ChapterArea$dispose() {
        Sys.Preview.UI.Xaml.Media._ChapterArea.callBaseMethod(this, "dispose");
        this._player = null;
        if (this._toggleButton) this._toggleButton.dispose();
        this._toggleButton = null;
    }

    function Sys$Preview$UI$Xaml$Media$_ChapterArea$onItemClick(index) {
        this._player.set_currentChapter(this._imageChapters[index]);
    }

    function Sys$Preview$UI$Xaml$Media$_ChapterArea$setChapters(chapters) {
        // <param name="chapters" type="Array" mayBeNull="true" elementMayBeNull="true">Array of chapters.</param>
        if (!this.get_control()) return;
        var imageArray = [];
        // only care about chapters that have images with them
        if (chapters) {
            this._imageChapters = [];
            for (var i = 0, l = chapters.length; i < l; i++) {
                var chapter = chapters[i];
                if (chapter.imageUrl) {
                    this._imageChapters[this._imageChapters.length] = i;
                    imageArray[imageArray.length] = chapter.imageUrl;
                }
            }
        }
        this.set_items(imageArray);
    }

    function Sys$Preview$UI$Xaml$Media$_ChapterArea$_onToggle() {
        this._visible = !this._visible;
        this.setVisible(this._visible);
        var c = this.get_control();
        // make sure the chapter area isn't hit testable when its supposed to be hidden
        if (c) c.IsHitTestVisible = this._visible;
    }
Sys.Preview.UI.Xaml.Media._ChapterArea.prototype = {
    _player: null,
    _visible: false,
    _toggleButton: null,
    
    activate: Sys$Preview$UI$Xaml$Media$_ChapterArea$activate,
    
    deactivate: Sys$Preview$UI$Xaml$Media$_ChapterArea$deactivate,
    
    dispose: Sys$Preview$UI$Xaml$Media$_ChapterArea$dispose,

    onItemClick: Sys$Preview$UI$Xaml$Media$_ChapterArea$onItemClick,
    
    setChapters: Sys$Preview$UI$Xaml$Media$_ChapterArea$setChapters,
    
    _onToggle: Sys$Preview$UI$Xaml$Media$_ChapterArea$_onToggle
}
Sys.Preview.UI.Xaml.Media._ChapterArea.registerClass('Sys.Preview.UI.Xaml.Media._ChapterArea', Sys.Preview.UI.Xaml.Media._ImageList);

Sys.Preview.UI.Xaml.Media._Slider = function Sys$Preview$UI$Xaml$Media$_Slider(host, nameThumb, nameSlider, valueChangedHandler, handlerOwner) {
    // assumption: the thumb and slider canvases are siblings.
    Sys.Preview.UI.Xaml.Media._Slider.initializeBase(this, [host, nameSlider]);
    
    this._slider = this.get_control();
    this._thumb = new Sys.Preview.UI.Xaml.Media._DomElement(host, nameThumb);
    this._thumbControl = this._thumb.get_control();

    if (!this._thumbControl || !this._slider) {
        return;
    }
    this._highlight = new Sys.Preview.UI.Xaml.Media._DomElement(host, nameSlider + "_Highlight");
    this._highlightControl = this._highlight.get_control();
    
    this._slider.cursor = "Hand";
    this._thumbControl.cursor = "Hand";

    this._thumb.bindEvent("mouseLeftButtonDown", null, this._thumbMouseLeftButtonDown, this);
    this._thumb.bindEvent("mouseLeftButtonUp", null, this._thumbMouseLeftButtonUp, this);
    this._thumb.bindEvent("mouseMove", null, this._thumbMouseMove, this);
    this.bindEvent("mouseLeftButtonDown", null, this._sliderLeftButtonDown, this);
    
    // get to the root canvas and listen to its mouseLeave, so that we can ensure we know when
    // we loose mouse capture when the mouse leaves the silverlight host
    this._rootToken = this._slider.getHost().content.root.addEventListener("mouseLeave", Function.createDelegate(this, this._cancelDragging));

    this._isHorizontal = (this._slider.width >= this._slider.height);

    if (this._highlightControl) {
        this._highlightControl[this._isHorizontal ? "width" : "height"] = 0;
    }

    if (handlerOwner) {
        this._changedHandler = Function.createDelegate(handlerOwner, valueChangedHandler);
    }
}











    function Sys$Preview$UI$Xaml$Media$_Slider$set_enabled(value) {
        if (this.get_enabled() !== value) {
            Sys.Preview.UI.Xaml.Media._Slider.callBaseMethod(this, "set_enabled", [value]);
            // highlight bar should not respond when time is not shown
            this._highlight.set_enabled(value);
            // thumb should fade away when time disabled
            this._thumb.setVisible(value);
            // thumb should not have hand cursor when disabled
            if (this._thumbControl) this._thumbControl.cursor = value ? "Hand" : "Default";
            // slider's position should be 0 when disabled
            if (!value) this.set_value(0);
            // slider should not have hand cursor when disabled
            if (this._slider) this._slider.cursor = value ? "Hand" : "Default";
        }        
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$get_enableSeeking() {
        if (arguments.length !== 0) throw Error.parameterCount();
        return !!this._enableSeeking;
    }
    function Sys$Preview$UI$Xaml$Media$_Slider$set_enableSeeking(value) {
        if (this._enableSeeking !== value) {
            this._enableSeeking = value;
            if (!value) this._cancelDragging();
        }
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$get_value() {
        if (arguments.length !== 0) throw Error.parameterCount();
        // <value type="Number">A number between 0 and 1 representing the current position of the slider's thumb.</value>
        if (!this._thumbControl || !this._slider) return 0;

        var val;
        if (this._isHorizontal) {
            //val = this._thumbControl["Canvas.Left"] - this._slider["Canvas.Left"] + (this._thumbControl.width/2);
            val = this._thumbControl["Canvas.Left"] - this._slider["Canvas.Left"];
            val = val / (this._slider.width - this._thumbControl.width);
        }
        else {
            val = this._thumbControl["Canvas.Top"] - this._slider["Canvas.Top"] + (this._thumbControl.height/2);
            val = 1 - (val / this._slider.height);
        }
        // make value accurate to 0.001
        val = Math.round(val*1000)/1000;
        return Math.min(1, Math.max(0, val));
    }
    function Sys$Preview$UI$Xaml$Media$_Slider$set_value(value) {
        value = Math.min(1, Math.max(0, value));
        this._setThumbPosition(value);
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$dispose() {
        if (this._highlight) this._highlight.dispose();
        if (this._thumb) this._thumb.dispose();
        this._changedHandler = null;
        if (this._rootToken) this._slider.getHost().content.root.removeEventListener("mouseLeave", this._rootToken);
        this._slider = null;
        this._thumb = null;
        this._thumbControl = null;
        this._rootToken = null;
        this._highlight = null;
        this._highlightControl = null;
        Sys.Preview.UI.Xaml.Media._Slider.callBaseMethod(this, 'dispose');                
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_cancelDragging() {
        if (this._isDragging) {
            this._isDragging = false;
            this._thumbControl.ReleaseMouseCapture();
        }
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_setThumbPosition(value) {
        if (this._thumbControl && this._slider) {
            var loc = this._toLocation(value);
            if (this._isHorizontal) {
                this._thumbControl["Canvas.Left"] = this._slider["Canvas.Left"] + loc - (this._thumbControl.width/2);
                if (this._highlightControl) this._highlightControl.width = loc + (this._thumbControl.width/2);
            }
            else {
                this._thumbControl["Canvas.Top"] = this._slider["Canvas.Top"] + loc - (this._thumbControl.height/2);
                if (this._highlightControl) {
                    this._highlightControl["Canvas.Top"] = this._thumbControl["Canvas.Top"] + (this._thumbControl.height/2);
                    this._highlightControl.height = value * (this._slider.height - this._thumbControl.height) - (this._thumbControl.height/2);
                }
            }
        }
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_sliderLeftButtonDown(sender, eventArgs) {
        if (!this._enableSeeking) return false;
        var newValue = this._toValue(eventArgs.getPosition(sender));
        this._setThumbPosition(newValue);
        if (this._changedHandler) this._changedHandler();
        if (this._thumbControl) {
            this._isDragging = true;
            this._thumbControl.CaptureMouse();
        }
        return true;
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_thumbMouseLeftButtonDown() {
        if (!this._enableSeeking) return false;
        this._isDragging = true;
        this._thumbControl.CaptureMouse();
        return true;
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_thumbMouseLeftButtonUp() {
        if (!this._enableSeeking) return false;
        this._isDragging = false;
        this._thumbControl.ReleaseMouseCapture();
        return true;
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_thumbMouseMove(sender, args) {
        if (this._isDragging) {
            this._setThumbPosition(this._toValue(args.getPosition(this._slider)));
            if (this._changedHandler) this._changedHandler();
        }
        return true;
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_toValue(point) {
        // converts a point which is relative to the Slider control's position to a logical slider value
        var val;
        if (this._isHorizontal) {
            val = (point.X - (this._thumbControl.width / 2)) / (this._slider.width - this._thumbControl.width);
        }
        else {
            val = (point.Y - (this._thumbControl.height / 2)) / (this._slider.height - this._thumbControl.height);
            val = 1 - val;
        }
        return Math.min(1, Math.max(0, val));
    }

    function Sys$Preview$UI$Xaml$Media$_Slider$_toLocation(value) {
        // converts a logical value into a point which is relative to the Slider control's position
        value = Math.min(1, Math.max(0, value));
        if (this._isHorizontal) {
            return (value * (this._slider.width - this._thumbControl.width)) + (this._thumbControl.width / 2);
        }
        else {
            var range = this._slider.height - this._thumbControl.height;
            return (range - (value * range)) + (this._thumbControl.height / 2);
        }
    }
Sys.Preview.UI.Xaml.Media._Slider.prototype = {
    _slider: null,
    _thumb: null,
    _thumbControl: null,
    _enableSeeking: true,
    _highlight: null,
    _highlightControl: null,
    _isDragging: false,
    _isHorizontal: true,
    _rootToken: null,

    set_enabled: Sys$Preview$UI$Xaml$Media$_Slider$set_enabled,
    
    get_enableSeeking: Sys$Preview$UI$Xaml$Media$_Slider$get_enableSeeking,
    set_enableSeeking: Sys$Preview$UI$Xaml$Media$_Slider$set_enableSeeking,

    get_value: Sys$Preview$UI$Xaml$Media$_Slider$get_value,
    set_value: Sys$Preview$UI$Xaml$Media$_Slider$set_value,
    
    dispose: Sys$Preview$UI$Xaml$Media$_Slider$dispose,    
    
    _cancelDragging: Sys$Preview$UI$Xaml$Media$_Slider$_cancelDragging,
    
    _setThumbPosition: Sys$Preview$UI$Xaml$Media$_Slider$_setThumbPosition,
    
    _sliderLeftButtonDown: Sys$Preview$UI$Xaml$Media$_Slider$_sliderLeftButtonDown,
    
    _thumbMouseLeftButtonDown: Sys$Preview$UI$Xaml$Media$_Slider$_thumbMouseLeftButtonDown,

    _thumbMouseLeftButtonUp: Sys$Preview$UI$Xaml$Media$_Slider$_thumbMouseLeftButtonUp,

    _thumbMouseMove: Sys$Preview$UI$Xaml$Media$_Slider$_thumbMouseMove,
    
    _toValue: Sys$Preview$UI$Xaml$Media$_Slider$_toValue,
    
    _toLocation: Sys$Preview$UI$Xaml$Media$_Slider$_toLocation    
}
Sys.Preview.UI.Xaml.Media._Slider.registerClass('Sys.Preview.UI.Xaml.Media._Slider', Sys.Preview.UI.Xaml.Media._DomElement);
Sys.Preview.UI.Xaml.Media._ProgressBar = function Sys$Preview$UI$Xaml$Media$_ProgressBar(host, nameSlider, nameText) {
    // <summary>An element whose width depends on the value.</summary>
    // <param name="host">The Silverlight host.</param>
    // <param name="nameSlider" type="String">name of XAML canvas that represents the slider, where the existing width is the 100% point</param>
    // <param name="nameText" type="String">Optional name of XAML TextBlock where the actual percentage amount should be displayed</param>
    Sys.Preview.UI.Xaml.Media._ProgressBar.initializeBase(this, [host, nameSlider]);
    
    var control = this.get_control();
    if (control) {
        this._originalWidth = control.width;
        control.width = 0;
    }
    if (nameText) {
        this._xamlText = new Sys.Preview.UI.Xaml.Media._TextBlock(host, nameText);
        this._xamlText.set_text("");
    }
}




    function Sys$Preview$UI$Xaml$Media$_ProgressBar$get_value() {
        if (arguments.length !== 0) throw Error.parameterCount();
        // <value type="Number">Progress value between 0 and 1.</value>
        var c = this.get_control();
        if (!c) return 0;
        return c.width / this._originalWidth;
    }
    function Sys$Preview$UI$Xaml$Media$_ProgressBar$set_value(value) {
        var c = this.get_control();
        if (c) c.width = this._originalWidth * value;
        this._xamlText.set_text("" + Math.floor(value * 100));
    }

    function Sys$Preview$UI$Xaml$Media$_ProgressBar$setVisible(value) {
        Sys.Preview.UI.Xaml.Media._ProgressBar.callBaseMethod(this, "setVisible", [value]);
        if (this._xamlText) this._xamlText.setVisible(value);
    }

    function Sys$Preview$UI$Xaml$Media$_ProgressBar$dispose() {
        Sys.Preview.UI.Xaml.Media._ProgressBar.callBaseMethod(this, "dispose");
        if (this._xamlText) {
            this._xamlText.dispose();
            this._xamlText = null;
        }
    }
Sys.Preview.UI.Xaml.Media._ProgressBar.prototype = {
    _xamlText: null,
    _originalWidth: 0,
    
    get_value: Sys$Preview$UI$Xaml$Media$_ProgressBar$get_value,
    set_value: Sys$Preview$UI$Xaml$Media$_ProgressBar$set_value,
    
    setVisible: Sys$Preview$UI$Xaml$Media$_ProgressBar$setVisible,
   
    dispose: Sys$Preview$UI$Xaml$Media$_ProgressBar$dispose
}
Sys.Preview.UI.Xaml.Media._ProgressBar.registerClass('Sys.Preview.UI.Xaml.Media._ProgressBar', Sys.Preview.UI.Xaml.Media._DomElement);

Type.registerNamespace('Sys.Preview.UI.Xaml.Media');
Sys.Preview.UI.Xaml.Media.Res={
"volumeRange":"Volume must be a number greater than or equal to 0 and less than or equal to 1.",
"mediaFailed":"Unable to load media \"{0}\".",
"noMediaElement":"The XAML document does not contain a MediaElement.",
"invalidChapterIndex":"Must be greater than or equal to 0 and less than the length of the chapters array."
};

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();