﻿// JScript File
function Player(playerType,streamURL)
{
    /**
     * Player parameters
    */
   
    this.obj            = false;
    this.objName        = "player";
    this.width          = 240;
    this.height         = 69;
    this.zIndex         = 0;   
   
    this.url            = streamURL;
    this.playerType     = playerType;
    this.playerAPI      = browserCheck["agent"]=="ie"?"object":"embed";
    this.playerVersion  = 0;
    this.autostart      = true;
    
    /**
     * Interface parameters
    */
    this.showSlider     = true;


    /**
     * Slider parameters
    */
    this.sliderStartMouse = 0;
    this.sliderStartObj   = 0;
    this.sliderPosition   = 0;
    this.sliderLastJump   = 0;
    this.sliderSeeking    = false;
    this.setPositionTimer = 0; 

    this.useCustomAPI = true;
    this.useCustomControls = false;

    if (browserCheck["agent"]=="ie") {
        this.useCustomControls = true;
    } else if (browserCheck["agent"]=="opera" && this.playerType!="Real") {
        this.useCustomControls = true;
    } else if (browserCheck["agent"]=="gecko" && this.playerType!="Windows") {
        this.useCustomControls = true;
    }
    
    if (browserCheck["platform"]!="win") {
        this.useCustomControls = false;
    }


    if (this.playerType == "Windows") {
        this.playerVersion = parseInt(browserCheck["player_wme"]);
    } else if (this.playerType == "Real") {
        this.playerVersion = parseInt(browserCheck["player_real"]);
    }

    if(this.useCustomControls) {
        this.height = 0;
    }

    /**
     * Check if player obj can be scripted or customAPI is disabled
     *
     * Plugin/ActiveX Control API calls are a time critical feature that can easily trigger
     * a javascript error if invoked in the wrong moment or if blocked by browser security
     * features.
     *
     * A common way to check for a function is: if (this.obj.function) this.obj.function()
     * While this is standard conform and in most cases reliable, internet explorer raises
     * an error instead of returning false if you invoke an existing object function but the 
     * call gets blocked by browser security settings (e.g. safe for scripting disabled) or 
     * deprecated features (e.g. invoking through EMBED API in IE 6.x).
     *
     * Therefor we use a try...catch statement to suppress possible error messages. This 
     * solution is easier to handle than using a global window.onerror event sink. 
     *
     * By calling this method before every other API call we can avoid API timing related 
     * problems. Make sure every direct API call is "protected"!
     *
     * @access     public
     * @param      void
     * @return     float duration
    */       
    this.canScript = function() {
        var can = false
        if (!this.useCustomAPI) {
            can = false            
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) {
            try {
                if (this.obj.ClientID) { can = true; }                
            } catch (e) { can = false;  }
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) {
            try {
                if (this.obj.versionInfo) { can = true; }                
            } catch (e) { can = false; }
        } else if (this.playerType == "Windows" && this.playerAPI == "embed" ) {
            try {
                if (this.obj.GetClientID()) { can = true; }      
            } catch (e) { can = false; }
        } else if (this.playerType == "Real") { 
            try {
                if (this.obj.GetVersionInfo() || this.obj.GetSource()) { can = true; }   
            } catch (e) { can = false; }
        }
        return can;
    }    
    
    /** 
     * Create the OBJECT and EMBED tags and add GUI features
     * 
     * Writing the controls to HTML is the most critical part of the player class. See the player 
     * documentation for details on the specific parameters. 
     *
     * Generally speaking there is always a CUSTOM and a STANDARD GUI version, the CUSTOM GUI is mostly
     * embedded into a table structere. Also there is always an OBJECT and an EMBED API version.
     *
     * @access  public
     * @param   void
     * @return  string playerHTML
    */    
    
     this.draw = function () {
             
        var out = '';
        
        this.width  = parseInt(this.width);
        this.height = parseInt(this.height);
        
        
        /**
         * Windows Media Player using OBJECT API 6.4
         *
         * Width and height are measured INCLUDING the standard controls if available. Therefore we 
         * extend the height if they are available. The original Windows Media Player 6.4 controls are
         * a few pixels smaller but this can be ignored.
         *
         * API 9 6BF52A52-394A-11D3-B153-00C04F79FAA6
         *
         * Parameter & Scripting docu: 
         * http://msdn.microsoft.com/library/en-us/wmp6sdk/htm/microsoftwindowsmediaplayercontrolversion64sdk.asp
         *
        */        
  
        if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) {
   
            if (!this.useCustomControls) { 
                out += '<OBJECT id="MediaPlayer" classid="CLSID:22D6f312-B0F6-11D0-94AB-0080C74C7E95" border="0" width="'+this.width+'" height="'+this.height+'"><param name="showControls" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="AutoStart" value="'+(this.autostart?'true':'false')+'"><param name="TransparentAtStart" value="false"><param name="showPositionControls" value="false"><param name="showTracker" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="showStatusBar" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="DisplaySize" value="0"><param name="AutoSize" value="0"><param name="src" value="'+this.url+'"><\/OBJECT>\n' 
            }
            if ( this.useCustomControls) { 
                out += '<table cellpadding="0" cellspacing="0" border="0" width="'+this.width+'" height="'+this.height+'"><tr><td valign="middle" align="center"><OBJECT id="MediaPlayer" classid="CLSID:22D6f312-B0F6-11D0-94AB-0080C74C7E95" border="0" width="'+this.width+'" height="'+this.height+'"><param name="showControls" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="AutoStart" value="'+(this.autostart?'true':'false')+'"><param name="TransparentAtStart" value="false"><param name="showPositionControls" value="false"><param name="showTracker" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="showStatusBar" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="DisplaySize" value="0"><param name="AutoSize" value="0"><param name="src" value="'+this.url+'"><\/OBJECT><\/td><\/tr><\/table>\n' 
            }
        }
        

        /**
         * Windows Media Player using OBJECT API 7-10
         *
         * Width and height are measured INCLUDING the standard controls if available. Therefore we 
         * extend the height if they are available. The original Windows Media Player 6.4 controls are
         * a few pixels smaller but this can be ignored.
         *
         * API 9 6BF52A52-394A-11D3-B153-00C04F79FAA6
         *
         * Parameter & Scripting docu: 
         * http://msdn.microsoft.com/library/en-us/wmp6sdk/htm/microsoftwindowsmediaplayercontrolversion64sdk.asp
         *
        */        
        if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) {
            var uiMode = "invisible";
            if (!this.useCustomControls) { 
                uiMode = "mini"
            }
            if (!this.useCustomControls) { 
                out += '<OBJECT id="MediaPlayer" classid="CLSID:6BF52A52-394A-11D3-B153-00C04F79FAA6" border="0" width="'+this.width+'" height="'+this.height+'"><param name="showControls" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="AutoStart" value="'+(this.autostart?'true':'false')+'"><param name="uiMode" value="'+uiMode+'"><param name="url" value="'+this.url+'"><\/OBJECT>\n' 
            }
            if ( this.useCustomControls) { 
                out += '<table cellpadding="0" cellspacing="0" border="0" width="'+this.width+'" height="'+this.height+'"><tr><td valign="middle" align="center"><OBJECT id="MediaPlayer" classid="CLSID:6BF52A52-394A-11D3-B153-00C04F79FAA6" border="0" width="'+this.width+'" height="'+this.height+'"><param name="showControls" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="AutoStart" value="'+(this.autostart?'true':'false')+'"><param name="uiMode" value="invisible"><param name="url" value="'+this.url+'"><\/OBJECT><\/td><\/tr><\/table>\n' 
            }
        }        
        
        /**
         * Windows Media Player using EMBED API
         *
         * See OBJECT API comments for details about height adjustment.
        */
        if (this.playerType == "Windows" && this.playerAPI == "embed") {
            if (!this.useCustomControls) { 
                out += '<embed style="position:relative;" border=0 type="application/x-mplayer2" name="MediaPlayer" id="MediaPlayer" border="0" width="'+this.width+'" height="'+this.height+'" autostart="'+(this.autostart?'1':'0')+'" showStatusBar="'+((!this.useCustomControls)?'1':'0')+'" showTracker="'+((!this.useCustomControls)?'1':'0')+'" showPositionControls="0" showControls="'+((!this.useCustomControls)?'1':'0')+'" transparentatstart="0" src="'+this.url+'"><\/embed>\n' 
            }        
            if ( this.useCustomControls) { 
                out += '<table cellpadding="0" cellspacing="0" border="0" width="'+this.width+'" height="'+this.height+'"><tr><td valign="middle" align="center"><embed border=0 type="application/x-mplayer2" name="MediaPlayer" id="MediaPlayer" border="0" width="'+this.width+'" height="'+this.height+'" autostart="'+(this.autostart?'1':'0')+'" showStatusBar="'+((!this.useCustomControls)?'1':'0')+'" showTracker="'+((!this.useCustomControls)?'1':'0')+'" showPositionControls="0" showControls="'+((!this.useCustomControls)?'1':'0')+'" transparentatstart="0" src="'+this.url+'"><\/embed><\/td><\/tr><\/table>\n' 
            }        
        }

        /**
         * Real Media Player using OBJECT API
         *
         * Parameter & Scripting docu: 
         * http://service.real.com/help/library/guides/realonescripting/browse/realscript.htm
        */
		if (this.playerType == "Real" && this.playerAPI == "object") {
            if(!this.useCustomControls) {
                out += '<OBJECT classid="CLSID:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" id="RealAudio2" width="'+this.width+'" height="'+this.height+'"><param name="AutoStart" value="true"><param name="ShowControls" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="ShowAudioControls" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="ShowTracker" value="'+((!this.useCustomControls)?'true':'false')+'"><param name="ShowStatusBar" value="true"><param name="console" value="media"><param name="src" value="'+this.url+'"><\/OBJECT>';            
            }else {
                out += '<OBJECT classid="CLSID:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" id="RealAudio2" width="1" height="1"><param name="AutoStart" value="true"><param name="controls" value="ImageWindow"><param name="console" value="media"><param name="src" value="'+this.url+'"><\/OBJECT>';            
            }
		}
		
        /**
         * Real Media Player using EMBED API
        */
		if (this.playerType == "Real" && this.playerAPI == "embed") {
            if(!this.useCustomControls) {
                out += '<EMBED type="audio/x-pn-realaudio-plugin" name="RealAudio2" id="RealAudio2" console="media" controls="StatusBar"  autostart="true" border="0" width="'+this.width+'" height="'+this.height+'" showstatussar="1" showTracker="'+((!this.useCustomControls)?'1':'0')+'" showcontrols="'+((!this.useCustomControls)?'1':'0')+'" showaudiocontrols="'+((!this.useCustomControls)?'1':'0')+'" src="'+this.url+'" SCRIPTCALLBACKS="OnAuthorChange"><\/EMBED>';
            }else {
                out += '<EMBED type="audio/x-pn-realaudio-plugin" name="RealAudio2" id="RealAudio2" console="media" controls="ImageWindow"  autostart="true" border="0" width="1" height="1" src="'+this.url+'" SCRIPTCALLBACKS="OnAuthorChange"><\/EMBED>';
            }
		}	
		
		if(this.playerType == "LivePhone") {
	        out += '<table width="100%" height="100%" border="0" cellpadding="0" cellspacing="0">';
		    out +=  '	<tr bgcolor="black">';
		    out +=  '		<td ><p><span class="cntMed"><font color="#FFFFFF">' + phoneText ;
		    out +=  '		<\/font><br>';
		    out +=  '		<\/span></p>';
		    out +=  '		<\/td>';
		    out +=  '	<\/tr>';
		    out +=  '<\/table>';
		    document.getElementById("audioPlayer_Player").innerHTML = out;
		    hideDiv("audioPlayer_thomson_logo");
            playerFrame = "loaded";
		    return;
		}

        if (this.useCustomControls) { 
            out += this.drawStatus() 
        }

        if (this.useCustomControls) { 
            out += this.drawSlider() 
        }
        if (this.useCustomControls) { 
            out += this.drawControls() 
        }
        document.getElementById("audioPlayer_Player").innerHTML = out;
        
        if (this.playerType == "Windows") { 
            this.obj = document.getElementById("MediaPlayer")
        } else if (this.playerType == "Real") { 
            this.obj = document.getElementById("RealAudio2")
        }            

        if (this.playerType == "Real") {
            try { this.obj.SetWantErrors(true); } catch(e) { }
        }
        
        if (this.useCustomControls) { 
            player.handleEvents();        
        }
        playerFrame = "loaded";
    }
    
    /** 
     * Create the controls object HTML code
     * 
     * We hide the fullscreen button in Quicktime. See this.setFullscreen() for details
     *
     * @access  private
     * @param   void
     * @return  string htmlControls
    */    
    this.drawControls = function() {
        
        var out = "";
        out += '<table border="0" cellpadding="0" cellspacing="0" width="'+this.width+'">';
        out += '<tr><td height="2"><\/td><\/tr><tr>';
        out += '<td width="4"><div style="width:4px"><\/div><\/td>';
        out += '<td valign="middle"><img src="Images/player_play.gif" width="35" height="38" alt="Play" onclick="if(player.getStatus()==2){player.pause()}else{player.start()}" id="player_controls_start"><\/td>';
        out += '<td valign="middle"><img src="Images/player_stop_disabled.gif" width="20" height="28" alt="Stop" onclick="player.stop()" id="player_controls_stop"><\/td>';
        out += '<td valign="middle" align="right" style="background-image:url(Images/player_controlbar.gif)" width="100%">';
        out += '<div style="position:relative; width:65px; height:24px; overflow:hidden;">';
        out += '<img width="12" height="17" src="Images/player_audio.gif" border="0" alt="Toggle mute" id="player_mute" onclick="player.toggleMute()" style="position: absolute; top:2px; left:0px;">';
        out += '<div style="position:absolute; left:18px; top:0px; width:48px; height:24px; overflow:hidden; background-image:url(Images/player_audio_slider_light.gif)">';
        out += '<div style="position:absolute; left:0px; top:0px; width:48px; height:24px; overflow:hidden;" id="player_audio_dark"><img src="Images/player_audio_slider_dark.gif"></div>';
        out += '<div style="position:absolute; left:22px; top:5px;" id="player_audio_knob" onMouseDown="player.audioStartMove(event);"><div style="cursor:pointer; width:8px; height:13px; overflow:hidden; background-image:url(Images/volume_control_slider.gif);"></div></div>';
        out += '</div>';
        out += '<\/div>';
        out += '<\/td>';
        out += '<td valign="middle"><img src="Images/player_controlcorner.gif" width="9" height="40" alt=""><\/td>';
        out += '<td width="4"><div style="width:4px"><\/div><\/td>';
        out += '<\/tr>';
        out += '<\/table>';        
                      
        return out;
    }   
    
    function audioDoMove(e) {
        if (window.event) { 
            e = window.event
        }
        player.audioDoMoveX(e)
    }
    this.audioDoMove = audioDoMove
    
    this.audioDoMoveX = function(e) {

        if (window.event) { 
            e = window.event
        }
        var newX = parseInt(this.audioStartObj+(e.clientX-this.audioStartMouse))
        if (newX <= 3)  newX = 3;
        if (newX >= 39) newX = 39;
        
        document.getElementById("player_audio_knob").style.left = newX+"px"
        document.getElementById("player_audio_dark").style.width = newX+"px"
        
        this.setVolume(Math.floor((newX-3)/3.45));

    }    
  
    function audioEndMove(e) {
        player.audioEndMoveX(e)
    }
    this.audioEndMove = audioEndMove    

    this.audioEndMoveX = function() {
        document.onmouseup   = null
        document.onmousemove = null
        return true
    }

    this.audioStartMove = function(e) {
        if (window.event) {
            e = window.event
        }
        this.audioStartMouse     = e.clientX 
        this.audioStartObj       = parseInt(document.getElementById("player_audio_knob").style.left)
        document.onmouseup   = this.audioEndMove
        document.onmousemove = this.audioDoMove
        this.audioDoMove(e)    
        return true
    }    
    
    /** 
     * Create the slider object HTML code
     * 
     * Do not use an IMH tag as silder (safari drags the image as a desktop object) and keep the
     * div with the background-image in another span (this avoids image reloading in IE).
     *
     * @access  private
     * @param   void
     * @return  string htmlSlider
    */    
    this.drawSlider = function() {
      
        var out = "";
        out += '<table border="0" cellpadding="0" cellspacing="0" width="'+this.width+'">';
        out += '<tr><td height="4" colspan="5"><\/td><\/tr><tr>';
        out += '<td width="4"><div style="width:4px"><\/div><\/td>';
        out += '<td valign="middle"><img src="Images/player_slider_left.gif" height="14" alt=""><\/td>';
        out += '<td width="100%">';        


        out += '<div style="width:100%; height:14px; position:relative; background-image:url(Images/player_slider_bg.gif)" onMouseDown="player.sliderJump(event);">';
        out += '<div id="player_slider_bg" style="position:absolute; left:0px; top:5px; height:3px; overflow:hidden; background-color:#ffdb31; width:0px;">&nbsp;<\/div>';
        out += '<div id="player_slider" style="height:14px;position:relative;cursor:default;">';
        out += '<span style="position:absolute;"><div style="position:absolute;top:0px;left:0px;height:12px;width:12px;background-image:url(\'Images/player_audio_knob.gif\');overflow:hidden; cursor:pointer;" onMouseDown="player.sliderStartMove(event);" id="player_slider_knob"><\/span><\/div>';
        out += '<\/div>';
        out += '<\/div>';      

        out += '<\/td>';
        out += '<td valign="middle"><img src="Images/player_slider_right.gif" height="14" alt=""><\/td>';
        out += '<td width="4"><div style="width:4px"><\/div><\/td>';
        out += '<\/tr>';
        out += '<\/table>';                       
        return out
        
    }

  
    /** 
     * Create the status object HTML code
     * 
     * @access  private
     * @param   void
     * @return  string htmlStatus
    */    
    this.drawStatus = function() {
        var out = "";    
        out += '<div style="width:'+this.width+'px;height:19px;overflow:hidden;background-color:#000000;"><div style="margin:2px;width:'+(this.width-8)+'px;"><div style="font-size:11px;font-family:Arial;color:#FFFFFF;line-height:16px;text-align:right;"><span id="player_status">Initiating player object...<\/span><\/div><\/div><\/div>\n'
        return out
    }                
     
           
    /**
     * Convert a float into a human readable timestamp in format hh:mm:ss
     *
     * @access  private
     * @param   float time
     * @return  string timestamp (hh:mm:ss)
    */         
    this.float2timestamp = function(f) {
        var hours   = Math.floor(f/3600);
        var minutes = Math.floor((f-hours*3600)/60);
        var seconds = Math.floor(f-hours*3600-minutes*60)
        if (hours   <= 9) {
            hours = "0"+hours; 
        }            
        if (minutes <= 9) {
            minutes = "0"+minutes;
        }            
        if (seconds <= 9) {
            seconds = "0"+seconds;
        }            
        return hours+":"+minutes+":"+seconds;
    };           
    
    /**
     * Get the current player buffer level
     * 
     * Attention: In case fast-start is activated the bufferProgress reamains always 0 in Windows 
     * Media Player. Therefor we check if there was any buffering using bufferingCount and return
     * 100 if not.
     *
     * Real and Quicktime do not report any good percentage values. We just distinguish between 0 and 100.
     * 
     * @access  private
     * @param   void
     * @return  int buffer (0-100)
    */        
    this.getBuffer = function() {
        var buf = 0;
        if (!this.canScript()) {
            buf = 0;              
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) {
            buf =  (this.obj.bufferingCount > 0)?this.obj.BufferingProgress:100;  
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) {
            buf =  (this.obj.network.bufferingCount > 0)?this.obj.network.BufferingProgress:100;  
        } else if (this.playerType == "Windows" && this.playerAPI == "embed") {
            buf =  (this.obj.GetBufferingCount() > 0)?this.obj.GetBufferingProgress():100;  
        } else if (this.playerType == "Real") {
            buf =  (this.obj.GetPlayState() == 2)?0:100;
        }
        if (!buf) { buf = 0; }
        return buf
    }    
        
 /**
     * Get the duration of the clip if available
     * 
     * For easier handling we floor the duration to 1/10 second
     *
     * The TimeScale property is a special Quicktime feature to describe te number of fractions 
     * per second (usually it's roughly 600). We need to devide all time values by the scale 
     * the get the value in seconds.
     *
     * @access  public
     * @param   void
     * @return  float duration
    */         
    this.getDuration = function() {
        var duration = 0
        if (!this.canScript()) {
            duration = 0;
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) {
            duration = this.obj.duration;  
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) {
            duration = this.obj.currentMedia.duration;  
        } else if (this.playerType == "Windows" && this.playerAPI == "embed") {
            duration = this.obj.GetDuration();  
        } else if (this.playerType == "Real") {
            duration = this.obj.GetLength()/1000
        }
        if (!duration) {
            duration = 0
        }     
        return Math.floor(duration*10)/10;       
    }    
    
    /**
     * Get the duration of the clip human readable
     * 
     * This function just wraps around {@link this.getDuration()}
     *
     * @access  public
     * @param   void
     * @return  string duration
    */       
    this.getDurationString = function() {
        return this.float2timestamp(this.getDuration())
    }
            
    /**
     * Get the current position of the clip if available
     * 
     * For easier handling we floor the duration to 1/10 second
     *
     * The TimeScale property is a special Quicktime feature to describe te number of fractions 
     * per second (usually it's roughly 600). We need to devide all time values by the scale 
     * the get the value in seconds.
     *
     * The checks for negative values or values beyond duration is a workaround for Windows Media
     * player 6.4. When under heavy load (e.g. multiple setPositions per second) the currentPosition
     * property contains enpredictable values. Maybe an undocumented api error message or just a bug.
     *
     * @access  public
     * @param   void
     * @return  float position
    */               
    this.getPosition = function() {
        var position = 0
        if (!this.canScript()) {
            position = 0;
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) {
            position = this.obj.currentPosition;  
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) {
            position = this.obj.controls.currentPosition;  
        } else if (this.playerType == "Windows" && this.playerAPI == "embed") {
            position = this.obj.GetCurrentPosition();  
        } else if (this.playerType == "Real") {
            position = this.obj.GetPosition()/1000
              // force a stop if end of clip reached
              if (position > 0 && position >= (this.getDuration()-0.6)) { 
                try { this.stop(); } catch(e) { }
              }
        }
        if (!position || position < 0 || position > this.getDuration()) {
            position = 0
        }            
        return Math.floor(position*10)/10;
    }       
    
    /**
     * Get the current position of the clip human readable
     * 
     * This function just wraps around {@link this.getPosition()}
     *
     * @access  public
     * @param   void
     * @return  string position
    */    
       
    this.getPositionString = function() {
        return this.float2timestamp(this.getPosition())
    }       
    
    /**
     * Get the current player status code
     * 
     * Attention: Windows Media Player 9 reports the Series 9 status codes even if forced to use 
     * the series 6 API. 0,1,2 are the same, but beware if you ever use further status codes like 
     * "re-buffering" or "fast-forward". This will end up in unexpectable results.
     *
     * @access  public
     * @param   void
     * @return  int status (0 = stopped, 1 = paused, 2 = playing, 3 = waiting)
    */     
     this.getStatus = function() {
        var stat = 0;
        if (!this.canScript()) {
            stat = 0;
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) {
            if (this.obj.PlayState == 0) {
                stat =  0;       
            } else if (this.obj.PlayState == 1 || this.obj.PlayState == 8) {
                stat =  1;     
            } else if (this.obj.PlayState == 2) { 
                stat =  2;      
            } else if (this.obj.PlayState >= 3) {
                stat =  3;       
            }                
        } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) {
            if (this.obj.PlayState == 0) {
                stat =  3;       
            } else if (this.obj.PlayState == 1 || this.obj.PlayState == 8 || this.obj.PlayState == 10) {
                stat =  0;       
            } else if (this.obj.PlayState == 2) {
                stat =  1;     
            } else if (this.obj.PlayState == 3) { 
                stat =  2;      
            } else if (this.obj.PlayState >= 4) {
                stat =  3;       
            }                
        } else if (this.playerType == "Windows" && this.playerAPI == "embed") {
            if (this.obj.GetPlayState() == 0) {
                stat =  0;  
            } else if (this.obj.GetPlayState() == 1) {
                stat =  1;  
            } else if (this.obj.GetPlayState() == 2) { 
                stat =  2;  
            } else if (this.obj.GetPlayState() >= 3) {
                stat =  3;  
            }
        } 
        else if (this.playerType == "Real") {
            if (this.obj.GetPlayState() == 0) {
                stat =  0; 
            } else if (this.obj.GetPlayState() == 1) { 
                stat =  3;  
            } else if (this.obj.GetPlayState() == 2) { 
                stat =  3;  
            } else if (this.obj.GetPlayState() == 3) { 
                stat =  2;  
            } else if (this.obj.GetPlayState() >= 4) {
                stat =  1; 
            }
        } 
        if (!stat) { 
            stat = 0
        }
        return stat
     }
    

    /**
     * Get the current player status string
     * 
     * This is a combination of {@link this.getStatus()} and {@link getBuffer()}
     *
     * We only display a "buffering" message if the buffer level underrun 99% to avoid a constant 
     * switching between "Buffering 99%" and "Playing" if the internet connection is unstable or 
     * the client uses a really tiny buffer (2 seconds or less). 
     *
     * The buffer level only overrides the normal status string if the player is playing or waiting.
     * This avoids a constant buffering messages if player is stopped/paused or the network connection 
     * gets lost during buffering.
     *
     * @access  public
     * @param   void
     * @return  string status
    */          
    this.getStatusString = function() {
        var statusString = ""
        if (!this.canScript())
        {
            statusString =  "No scripting support"
        }
        else
        {            
            var state  = this.getStatus()
            var buffer = this.getBuffer()               
            if (buffer == 0 && state >= 2) {
                statusString = "Buffering"
            } else if (buffer < 99 && state >= 2) {
                statusString = "Buffering "+buffer+"%"
            } else if (state  == 0) {
                statusString = "Stopped"
            } else if (state  == 1) {
                statusString = "Paused"
            } else if (state  == 2) { 
                statusString = "Playing"
            } else if (state  == 3) { 
                statusString = "Connecting"
            } else {
                statusString = "Unknown status"
            }                
        }        
        return statusString
    }
        
    /**
     * Get the volume level of the current player
     *
     * This function includes a helper function (decibel2volume) to convert the 1/100 decibel
     * damper to numeric volume levels. Array conversion is faster than logarithmic conversion.
     *
     * @access  public
     * @param   void
     * @return  int volume (0-9)
    */        
    this.getVolume = function() {
        function decibel2volume(decibel) {
            var decibel = Math.abs(decibel)
            var decibelLevels = new Array(10000,2000,1397,1045,795,602,443,309,193,91,0)
            for(var volume=0;volume<decibelLevels.length;volume++) if (decibel>=decibelLevels[volume]) break   
            return volume
        }
        var volume = 7
        
        if (!this.canScript()) {
            volume = 7;        
        } else if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion < 7) {
            volume = decibel2volume(this.obj.volume)  
        } else if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion >= 7) {
            volume = Math.round(this.obj.settings.volume/10)
        } else if (this.playerType == "Windows"  && this.playerAPI == "embed") {
            volume = decibel2volume(this.obj.GetVolume())    
        } else if (this.playerType == "Real") {
            volume = Math.round(this.obj.GetVolume()/10)
        }
        
        if (!volume) {
            volume = 0
        }
        if (volume < 0) { 
            volume = 0
        }
        if (volume > 10) { 
            volume = 10
        }
        return volume
    }        
   
    
    /**
     * Init event handling emulation
     *
     * This function inits the main loop to emulate the event handling. To avoid timing
     * issues we wait a bit to allow the players to start and call the function again.
     *
     * @access     public
     * @param      waited bool
     * @return     void
    */      
    this.handleEvents = function(waited) {
        if (!waited) {
            window.setTimeout(this.objName+".handleEvents(true)",500);
        } else {       
            playerInterval = window.setInterval(this.objName+".interval()",500);
        }            
    }  
    
    
    /**
     * A constant loop to emulate event handling cross-browser
     *
     * We re-init obj every cycle to prevent various timing issues. Also some
     *
     * @access     public
     * @param      void
     * @return     float duration
    */      
    this.lastRealCaption = "";
    this.lastStatus      = "";
    
    this.interval = function() {
        try {
        if (this.playerType == "Windows") { 
            this.obj = document.getElementById("MediaPlayer")
        } else if (this.playerType == "Real") { 
            this.obj = document.getElementById("RealAudio2")
        }            
        

        var curPosition = this.getPosition()
        var curDuration = this.getDuration()
        var curPercent  = 0
        if (curDuration > 0) {
            curPercent  = Math.floor(curPosition/curDuration*100) 
        }                
        var w = (this.width-36)/100*curPercent
        var newS = ""
        if(this.url == "")
        {
            newS = "The Archive for this event has expired.";
        }
        else
        {
            if (this.sliderSeeking) {
                newS = "Seeking "+this.float2timestamp(this.sliderPosition)+" / "+this.getDurationString()
            } else {
                if (document.getElementById("player_slider_knob")) {
                    document.getElementById("player_slider_knob").style.left = w+"px";
                    document.getElementById("player_slider_bg").style.width = w+"px";
                }                    
                newS = this.getStatusString()+" "+this.getPositionString()+" / "+this.getDurationString()
            }
        }
  
        if (document.getElementById("player_status") && document.getElementById("player_status").innerHTML != newS) {
            document.getElementById("player_status").innerHTML = newS
        }     

        if (this.playerType == "Real" && this.canScript() && this.lastRealCaption != this.obj.GetAuthor()) {
            this.lastRealCaption = this.obj.GetAuthor();               
            refresh.forceCommand(this.lastRealCaption);
        }      
          
          
        var curStatus = this.getStatus();
        if (curStatus != this.lastStatus) {
            this.lastStatus = curStatus;
            if( document.getElementById("player_controls_start") && document.getElementById("player_controls_stop")) {

                switch (curStatus) {
                    case 0:
                        document.getElementById("player_controls_start").setAttribute("alt","Play");
                        document.getElementById("player_controls_start").src = "Images/player_play.gif"
                        document.getElementById("player_controls_stop").src = "Images/player_stop_disabled.gif"
                    break;                    
                    case 1:
                        document.getElementById("player_controls_start").setAttribute("alt","Play");
                        document.getElementById("player_controls_start").src = "Images/player_play.gif"
                        document.getElementById("player_controls_stop").src = "Images/player_stop.gif"
                    break;                    
                    case 2:
                        document.getElementById("player_controls_start").setAttribute("alt","Pause");
                        document.getElementById("player_controls_start").src = "Images/player_pause.gif"
                        //document.getElementById("player_controls_stop").src = "Images/player_stop.gif"
                    break;                    
                    case 3:
                        document.getElementById("player_controls_start").setAttribute("alt","Pause");
                        document.getElementById("player_controls_start").src = "Images/player_pause.gif"
                        document.getElementById("player_controls_stop").src = "Images/player_stop.gif"
                    break;                    
                }
                
            }        
    
        }
        } catch(e) { }
       
    }

    


    /**
     * Pause the player output
     * 
     * Always check the IsBroadcast flag to avoid warning messages in Windows Media Player 6.4 
     * before calling this.obj.pause(). The Canthis.pause() in Real is not really necessary but maybe 
     * it will be in the future. 
     *
     * @access  public
     * @param   void
     * @return  void
    */        
    this.pause = function() {
        if (this.canScript()) {
            if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion < 7 ) {
                this.obj.Pause()   
            } else if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion >= 7) {
                this.obj.controls.pause()   
            } else if (this.playerType == "Windows"  && this.playerAPI == "embed") {
                this.obj.Pause()   
            } else if (this.playerType == "Real" && this.obj.CanPause()) {
                this.obj.DoPause()
            }
        }                       
    }        
        
 
    
    /**
     * Set the current position of the clip if possible
     * 
     * The TimeScale property is a special Quicktime feature to describe te number of fractions 
     * per second (usually it's roughly 600). We need to devide all time values by the scale 
     * the get the value in seconds.
     *
     * When using Darwin Streaming Server instead of progressive download setPosition and getTimeScale
     * can return unexpected results when heavily used. A workaround is a setRate(0) and a setRate(1) 
     * before and after the this.setPosition().
     *
     * Window Media Player Object API needs an extra check for currentPosition before changing it's
     * value. In rare cases the player already accepts API commands but throws an error if used. 
     * This seems to happen most during transitioning process and is probably a glitch in microsofts
     * backward compatibility because it does not happen in series 6.4, only in series 7-9 players in
     * compatibility mode.
     *
     * We only allow a setPosition if not stopped and if the last setPosition call is at least 500ms ago.
     * The 500ms barrier is mainly a workaround to stop Windows Media Player 6.4 loosing server connection
     * and to stop Quicktime from eating up all system ressources.
     *
     * @access  public
     * @param   float position
     * @return  bool 
    */    
    
    this.setPosition = function(pos) {
        var pos = parseFloat(pos)+0.01;
        if (pos > this.getDuration()) {
            pos = this.getDuration()
        }  		
        var now = new Date();
        var ms  = now.getTime();
        if ((ms-this.setPositionTimer)>500) { 
            this.setPositionTimer = ms    
            if (this.canScript() && this.getStatus() != 0 && pos > 0) {
                //if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7 && this.obj.currentPosition) { 
                if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) { 
                    this.obj.currentPosition = pos;  
                //} else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7 && this.obj.controls.currentPosition) { 
                } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) { 
                    this.obj.controls.currentPosition = pos;  
                } else if (this.playerType == "Windows" && this.playerAPI == "embed" ) {
                    this.obj.SetCurrentPosition(pos);  
                } else if (this.playerType == "Real") {
                    this.obj.SetPosition(pos*1000)
                }
            }
        }            
    }   
            
    /**
     * Get the volume level of the current player
     *
     * This function includes a helper function (volume2decibel) to convert the numeric volume 
     * levels to an 1/100 decibel damper. Array conversion is faster than logarithmic conversion.
     *
     * @access  public
     * @param   int volume (0-10)
     * @return  void
    */        
    this.setVolume = function(volume) {
        function volume2decibel(volume) {
            var decibelLevels = new Array(10000,2000,1397,1045,795,602,443,309,193,91,0)
            return decibelLevels[volume]
        }    
                
        if (this.canScript()) {
            if (volume < 0) {
                volume = 0
            }                
            if (volume > 10) {
                volume = 10      
            }                
            if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion < 7) {
                this.obj.volume = volume2decibel(volume)*-1  
            } else if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion >= 7) {
                this.obj.settings.volume = volume*10
            } else if (this.playerType == "Windows"  && this.playerAPI == "embed") {
                this.obj.SetVolume(volume2decibel(volume)*-1)   
            } else if (this.playerType == "Real") {
                this.obj.SetVolume(volume*10)
            }
        }                     
    }       

    /** 
     * Event sink for click event on volume control
     *
     * @access  public
     * @param   e eventObject
     * @return  void
    */       
    this.setVolumeControl = function(e) {
        var eObj  = (window.event)?window.event.srcElement:e.target
        var eLeft = (window.event)?window.event.offsetX:e.layerX
        var newV  = parseInt(eLeft/parseInt(eObj.width)*11) 
        this.setVolume(newV)
    }   
 
     
    /** 
     * Event sink for mousemove event on slider object
     * 
     * Take care the slider does not leave it's boundaries and avoid reaching exact 0 or duration
     * because this might result in unpredictable reactions depending on the embedded player
     *
     * The function returns false if the player is stopped
     *
     * @access  public
     * @param   e eventObject
     * @return  void
    */    
    function sliderDoMove(e) {
        if (window.event) { 
            e = window.event
        }
        player.sliderDoMoveX(e)
    }
    this.sliderDoMove = sliderDoMove
    
    this.sliderDoMoveX = function(e) {
        if (this.getStatus() == 0) {
            this.sliderEndMove()
        } else {
            if (window.event) { 
                e = window.event
            }
            var newX = parseInt(this.sliderStartObj+(e.clientX-this.sliderStartMouse))
            if (newX > 0 && newX < (this.width-36)) {
                document.getElementById("player_slider_knob").style.left = newX+"px"
                document.getElementById("player_slider_bg").style.width = newX+"px"
                d = player.getDuration()
                pLeft = newX/(this.width-36)*100
                this.sliderPosition = Math.round(d/100*pLeft)
            }
        }            
    }    

    /** 
     * Event sink for mouseup event on slider object
     * 
     * Basicly only a helper function to release the event sinks and the this.sliderSeeking
     * Sets the player to the specified position by the last known this.sliderPosition
     *
     * @access  public
     * @param   void
     * @return  void
    */       
    function sliderEndMove(e) {
        if (window.event) { 
            e = window.event
        }
        player.sliderEndMoveX(e)
    }
    this.sliderEndMove = sliderEndMove    

    this.sliderEndMoveX = function() {
        this.sliderSeeking        = false    
        player.setPosition(this.sliderPosition)
        document.onmouseup   = null
        document.onmousemove = null
        return true
    }

    /** 
     * Event sink for click event on slider line
     * 
     * Opera doesn't like calls to window.event in this case, therefor we transfer the
     * needed values into other variables instead of e=window.event. This is a workaround,
     * maybe it's worth to dig into this later. Opera throws a security exception, somehow 
     * he wants to protect the event object, maybe to avoid event spoofing?!
     *
     * The function returns false if the player is stopped
     *
     * @access  public
     * @param   e eventObject
     * @return  void
    */        
    this.sliderJump = function(e) {
        if (this.getStatus() != 0) { 
            var eObj  = (window.event)?window.event.srcElement:e.target
            var eLeft = (window.event)?window.event.offsetX:e.layerX
            if (eObj.id == "player_slider") {
                d = this.getDuration()
                eLeft = eLeft-8
                if (eLeft<1) { 
                    eLeft = 1
                }
                if (eLeft>this.width-36) { 
                    eLeft = this.width-36
                }
                pLeft = eLeft/(this.width-36)*100
                this.setPosition(d/100*pLeft)
            }
        }                        
    }

     /** 
     * Event sink for mousedown event on slider object
     * 
     * We set this.sliderSeeking to true to avoid constant movement of both {@link sliderDoMove()}
     * and the updates coming from {@link interval()}
     *
     * The function returns false if the player is stopped
     *
     * @access  public
     * @param   e eventObject
     * @return  bool
    */
    this.sliderStartMove = function(e) {
        if (this.getStatus() == 0) {
            return false
        } else {            
            if (window.event) {
                e = window.event
            }
            this.sliderStartMouse     = e.clientX 
            this.sliderStartObj       = parseInt(document.getElementById("player_slider_knob").style.left)
            this.sliderSeeking        = true
            document.onmouseup   = this.sliderEndMove
            document.onmousemove = this.sliderDoMove
            this.sliderDoMove(e)    
            return true
        }               
    }
    
    /** 
     * Start the player output
     * 
     * @access  public
     * @param   void
     * @return  void
    */
    this.start = function() {
        if (this.canScript()) {
            if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion < 7) {
                this.obj.Play() 
            } else if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion >= 7) {
                this.obj.controls.Play()   
            } else if (this.playerType == "Windows"  && this.playerAPI == "embed") {
                this.obj.Play() 
            } else if (this.playerType == "Real" && this.obj.CanPlay()) {
                this.obj.DoPlay()
            }
        }                      
    }

    /**
     * Stop the player output
     * 
     * Windows Media Player 6.4 does not always return to the beginning of the clip if stopped. 
     * Therefor we need a this.setPosition(0) before the stop.
     *
     * Quicktime does not return to the beginning of the clip if stopped. It seems this.obj.stop() 
     * only reduces the rate to zero. Therefor we need a rewind before the stop.
     *
     * @access  public
     * @param   void
     * @return  void
    */    
    this.stop = function() {
        if (this.canScript()) { 
            if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion < 7) {
                this.setPosition(0);
                this.obj.Stop()   
            } else if (this.playerType == "Windows"  && this.playerAPI == "object" && this.playerVersion >= 7) {
                this.setPosition(0);
                this.obj.controls.Stop()   
            } else if (this.playerType == "Windows"  && this.playerAPI == "embed") {
                this.setPosition(0);
                this.obj.Stop() 
            } else if (this.playerType == "Real" && this.obj.CanStop()) {
                this.obj.DoStop()
            }
        }            
    }
        
    /**
     * Toggle mute state of player object
     *
     * @access     public
     * @param      void
     * @return     void
    */        
    this.toggleMute = function() {
        if (this.canScript()) {
            var newState = true;
            if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion < 7) {
                this.obj.mute = !this.obj.mute
                newState = this.obj.mute;
            } else if (this.playerType == "Windows" && this.playerAPI == "object" && this.playerVersion >= 7) {
                this.obj.settings.mute = !this.obj.settings.mute
                newState = this.obj.settings.mute;
            } else if (this.playerType == "Windows" && this.playerAPI == "embed" ) {
                this.obj.SetMute(!this.obj.GetMute()) 
                newState = !this.obj.GetMute();
            } else if (this.playerType == "Real") {
                this.obj.SetMute(!this.obj.GetMute()) 
                newState = !this.obj.GetMute();
            }
            
            try {
                document.getElementById("player_mute").src = newState?"Images/player_audio_mute.gif":"Images/player_audio.gif";
            } catch(e) {}
        }    
    }
             
}
