var g_dWmpControlHeight = 64;
var g_dWmpAspectRatio = (4/3);

var g_dTicksPerSecond = 10000000;

// wrapper for WMP player object
function VideoPlayer(el, id, bArchival)
{
    var m_el = el;
    var m_contentEl = CreateChildElement(m_el, "div", "wmpVideoPlayerContent");
    var m_pVideo = null;
    var m_pInfo = null;
    
    var m_sliderChangedCallback = null;
    var m_playstateChangedCallback = null;

    if (!id) id = "VideoPlayer";

    // this is needed by TabViewer for layout
    // Default to 4/3 in case we fail to retrieve native aspect ratio from video.
    this.AspectRatio = g_dWmpAspectRatio;

    var m_pVideo = CreateChildElement(m_contentEl, "object", "", id);
    if (m_pVideo)
    {
        var width = m_contentEl.offsetWidth;
        var height = Math.floor(width / g_dWmpAspectRatio + g_dWmpControlHeight);

        // don't let the width/height ever be 0 as this will cause a crash
        m_pVideo.width = Math.max(width, 1);
        m_pVideo.height = Math.max(height, 1);
        m_pVideo.classid= "clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"; 
        m_pVideo.stretchToFit = "true";
        m_pVideo.invokeURLs = "false";

        // make sure we cover all versions when disabling invokeURLs
        if (m_pVideo.Settings)
        {
            m_pVideo.Settings.invokeURLs = "false";
        }

        // hide controls for object video player
        if (!bArchival)
        {
            m_pVideo.uiMode = "none";
        }

        function OnPositionChange(oldPosition, newPosition)
        {
            if (m_sliderChangedCallback != null)
            {
                m_sliderChangedCallback(newPosition, true);
            }
        }

        function OnPlayStateChange(newState)
        {
            var playState = TranslatePlayState(newState);

            if (playState && m_playstateChangedCallback)
            {
                m_playstateChangedCallback(playState);
            }

            if (!bArchival && m_pVideo)
            {
                if (playState == "Buffering")
                {
                    m_pVideo.uiMode = "mini";
                }
                else
                {
                    m_pVideo.uiMode = "none";
                }
            }
        }

        function OnOpenStateChange(openState)
        {
            // If media is open
            if (openState == 13)
            {
                this.AspectRatio = m_pVideo.currentMedia.imageSourceWidth / m_pVideo.currentMedia.imageSourceHeight;
                // BUGBUG: We should refactor tabviewer / videoplayers such that videoplayer handles vertical centering.
                // Then we can just resize the videoplayer.
                g_pViewer.Resize();
            }
        }

        function OnMediaError(mediaObject)
        {
            setTimeout(function()
            {
                m_pVideo.URL = m_pInfo.Url
            }, 2000);
        }

        // set up our event handlers
        m_pVideo.attachEvent("PositionChange", OnPositionChange);
        m_pVideo.attachEvent("PlaystateChange", OnPlayStateChange);
        m_pVideo.attachEvent("MediaError", OnMediaError);
        // retrieve aspect ratio for object video once loaded.
        // archival video is fixed aspect ratio, so don't bother listening for event.
        if (!bArchival)
        {
            m_pVideo.attachEvent("OpenStateChange", Function.createDelegate(this, OnOpenStateChange));
        }
    }

    // info is a stream definition - create in DeliveryInfo in Viewer.js
    this.Initialize = function(info, sliderChangedCallback, playStateChangedCallback)
    {  
        m_pInfo = info;
        m_pVideo.URL = info.Url;
        
        m_sliderChangedCallback = sliderChangedCallback;
        m_playstateChangedCallback = playStateChangedCallback;
    }
    
    this.GetVideoPlayer = function()
    {
        return m_pVideo;
    }

    this.SetVideoPosition = function(dTime) 
    {
        if (m_pVideo && m_pVideo.controls) 
        {
            m_pVideo.controls.currentPosition = dTime;
        }
    }

    this.GetVideoPosition = function() 
    {
        if (m_pVideo && m_pVideo.controls) 
        {
            return m_pVideo.controls.currentPosition;
        }
    }

    this.GetPlayState = function()
    {
        return TranslatePlayState(m_pVideo.playState);
    }
    
    function TranslatePlayState(playState)
    {
        switch (playState)
        {
            case 1:     return "Stopped";
            case 2:     return "Paused";
            case 3:     return "Playing";
            case 6:     return "Buffering";
            case 7:     return "Buffering";
            default:    return null;
        }
    }

    this.SetPlayState = function(playState)
    {
        if (m_pVideo && m_pVideo.controls)
        {
            switch (playState)
            {
                case this.GetPlayState()    : return;
                case "Playing"              : m_pVideo.controls.play(); break;
                case "Paused"               : m_pVideo.controls.pause(); break;
                case "Stopped"              : m_pVideo.controls.stop(); break;
            }
        }
    }

    this.SetFullScreen = function(fullScreen)
    {
        try
        {
            m_pVideo.fullScreen = fullScreen;
        }
        catch (exception)
        {
        }
    }
        
    // used for archival video player
    this.OnResize = function(maxHeight, maxWidth)
    {
        var desiredWidth = maxWidth == undefined ? m_contentEl.clientWidth : maxWidth;

        // change our height based on our width
        this.Height = desiredWidth / g_dWmpAspectRatio + g_dWmpControlHeight;
        if (this.Height > maxHeight)
        {
            this.Height = maxHeight;
        }
        this.Width = (this.Height - g_dWmpControlHeight) * g_dWmpAspectRatio;

        if (m_pInfo != null && m_pInfo.Tag == "AUDIO")
        {
            this.Height = g_dWmpControlHeight;
        }

        this.Height = Math.floor(this.Height);
        this.Width = Math.floor(this.Width);

        m_el.style.height = this.Height + "px";
        m_contentEl.style.height = this.Height + "px";

        if (!m_pVideo)
            return;

        m_pVideo.style.width = this.Width + "px";
        m_pVideo.style.height = this.Height + "px";
    }
    
    // used for object video player
    this.SetSize = function(width, height)
    {
        m_el.style.width = width + "px";
        m_el.style.height = height + "px";
        m_contentEl.style.height = height + "px";
                
        if( !m_pVideo )
            return;
                
        m_pVideo.style.width = width + "px";
        m_pVideo.style.height = height + "px"; 
    }

    this.UpdateStatus = function(pEvent, bUserInitiated)
    {
        if (!m_pVideo) return;

        // synchronize positions - if we are more than the threshold away from the
        // archival video then synchronize
        var fTargetObjPos;
        if (m_pInfo.Segments)
        {
            var iTargetSeg = 0;
            while (iTargetSeg < m_pInfo.Segments.length && m_pInfo.Segments[iTargetSeg].RelativeStart <= pEvent.Time)
            {
                iTargetSeg++;
            }
            iTargetSeg--;
            var pTargetSeg = m_pInfo.Segments[iTargetSeg];
            fTargetObjPos = Math.max(pTargetSeg.Offset + pEvent.Time - pTargetSeg.RelativeStart, 0);
        }
        else
        {
            // our target with respect to the archival video
            fTargetObjPos = Math.max(pEvent.Time - m_pInfo.RelativeStart, 0);
        }

        // only update the position if we are way off or this update was initiated by a user action   
        var fCurPos = this.GetVideoPosition();
        if (bUserInitiated || (Math.abs(fCurPos - fTargetObjPos) > g_fOffsetThreshold))
        {
            this.SetVideoPosition(fTargetObjPos);
        }
    }
    
    this.SetVisible = function(bVisible)
    {
        SetVisible(m_el, bVisible);
    }
}
