// AdRotator javascript class

//
// AdRotator v0.3.2 - JR Rickerson
//
function AdRotator()
{

    ///////////////////////////////////////
    // Private member data
    ///////////////////////////////////////
    
    var VERSION_STRING = "v0.3.2";    
    
    //
    // Constants to adjust behavior
    //
    
    // Number of milliseconds between fade levels (total fade is 10 times this value)
    var FADE_SPEED = 50;
    
    // XML attributes for ad information
    var GRAPHIC_URL = "graphic";
    var TARGET_URL = "target";
    var PLAY_TIME = "playtime";
    
    // Convention for self-reference
    var _instance = this;
    
    // Used to request ad information from the server
    var m_strAdInfoURL = "";
    var m_objAdInfoRequest = null;
    var m_objAdInfoXML = null;
    
    // Array of parsed ad info
    var m_objAdArray = null;
    // Index into array of current ad (in the front buffer)
    var m_nAdIndex = null;
    
    // References to page objects
    var m_objAdBlock = null;
    var m_objBannerLinkFront = null;
    var m_objBannerImageFront = null;
    var m_objBannerLinkBack = null;
    var m_objBannerImageBack = null;
    
    // Dimensions of this ad block
    var m_nAdHeight = 0;
    var m_nAdWidth = 0;
    
    ///unique id for ad block
    var m_blockid = 0;
    
    // Used for setInterval timers
    var m_nAdTimerId = 0;
    var m_nAdInfoTimerId = 0;         // Future use
    
    // Flag set to true if the rotator should start with a random ad, or false if the
    // rotator should start at the first ad in the rotation
    var m_bUseRandomInitialAd = false;
    
    // Used to hide a necessarily public function from external scripts
    var m_bFetchingAds = false;
    // Have we loaded the front and back buffer before this?
    var m_bNeedInitialLoad = true;
    // Opacity to use between calls to DoTransitionEffect
    var m_nTransitionOpacity = 1.0;
    
    // Function to call when transition to next or previous ad is complete
    var m_funcTransitionCompleteCallback = null;
    
    // Error details
    var m_strErrorMessage = "";
    
    
    //With open ads, using image tag invocation, the 'n' parameter needs to be different between ads.
    //However, open ads stores a separate value in its session cookie for each value of 'n', so the number of 'n' values
    //must be limited in order to prevent session cookie overflow.
    var m_cookieposition = 1000;
      
    ///////////////////////////////////////
    // Expose public interface
    ///////////////////////////////////////
    this.GetAdInfoURL = GetAdInfoURL;
    this.SetAdInfoURL = SetAdInfoURL;
    this.GetAdBlockId = GetAdBlockId;
    this.SetAdBlockId = SetAdBlockId;
    this.GetNumAdsInRotation = GetNumAdsInRotation;
    this.SetAdDimensions = SetAdDimensions;
    this.GetRandomizeInitialAd = GetRandomizeInitialAd;
    this.SetRandomizeInitialAd = SetRandomizeInitialAd;
       
     
    this.Init = Init;
    this.StartAdRotation = StartAdRotation;
    this.StopAdRotation = StopAdRotation;
    this.NextAd = NextAd;
    this.PrevAd = PrevAd;
    
    // For internal use only, should not be called externally
    this.OnResult = OnResult;
    
    this.GetLastErrorMessage = GetLastErrorMessage;
    
    this.OnInit = null;
    
   
    
    ///////////////////////////////////////
    // Accessors and manipulators
    ///////////////////////////////////////
    
    function GetAdInfoURL()
    {
        return m_strAdInfoURL;
    }
    function SetAdInfoURL(strAdInfoURL)
    {
        m_strAdInfoURL = strAdInfoURL;
    }
    
    function GetAdBlockId()
    {
        return m_objAdBlock.id;
    }
    function SetAdBlockId(strAdBlockLayerId)
    {
        m_objAdBlock = document.getElementById(strAdBlockLayerId);
    }
    
    function GetNumAdsInRotation()
    {
        if(null != m_objAdArray)
        {
            return m_objAdArray.length;
        }
        else
        {
            return 0;
        }
        
    }
    
    function SetAdDimensions(nWidth, nHeight)
    {
        m_nAdWidth = nWidth;
        m_nAdHeight = nHeight;            
    }
        
    function GetLastErrorMessage()
    {
        return m_strErrorMessage;
    }
    
    
    function GetRandomizeInitialAd()
    {
        return m_bUseRandomInitialAd;
    }
    
    function SetRandomizeInitialAd(bStartRandom)
    {
        m_bUseRandomInitialAd = Boolean(bStartRandom);
    }
    
    ///////////////////////////////////////
    // Operations
    ///////////////////////////////////////
    
   
    
    
    function Init()
    {
        //initialize ad block id used for unique open ads cookie value.
        m_blockid = Math.floor(Math.random()*11000);
        m_cookieposition = m_blockid;
    
        // Check necessary data first
        if(null == m_objAdBlock)
        {
            m_strErrorMessage = "You must call SetAdBlockId() with a valid DIV id before calling Init().";
            return false;
        }
        
        if("" == m_strAdInfoURL)
        {
            m_strErrorMessage = "You must call SetAdInfoURL() before calling Init().";
            return false;
        }
        
        /*
        if(0 == m_nAdWidth || 0 == m_nAdHeight)
        {
            m_strErrorMessage = "You must call SetAdDimensions() non-zero values before calling Init().";
            return false;
        }
        */
        
        //
        // Create XML HTTP Request object
        //        
        try
        {
            // Mozilla and Safari browsers
            if(window.XMLHttpRequest)
            {
                m_objAdInfoRequest = new XMLHttpRequest();
            }
            // Internet Explorer
            else if(window.ActiveXObject)
            {
                m_objAdInfoRequest = new ActiveXObject("Microsoft.XMLHTTP");
            }
            else
            {
                throw "ERROR!";            
            }
        }
        catch(err)
        {
            m_objAdInfoRequest = null;
            m_strErrorMessage = "The browser does not support or allow the XMLHttpRequest object.";
            return false;
        }
        
        m_objAdArray = new Array();
        
        // Create structure within Ad block
        CreateAdBlockStructure();
        
        // Get Ad Info from the server
        FetchAds();
                        
        // Show that initialization (thus far) succeeded
        return true;
    }
    
    function StartAdRotation()
    {
        if(m_bNeedInitialLoad)
        {
            InitialLoad();
           
        }
        else
        {
            
            NextAd();
        }
    }
    
    function StopAdRotation()
    {
        // Simply stop the timer for the next ad
        clearTimeout(m_nAdTimerId);
    }    
    
    ///////////////////////////////////////
    // Internal utility functions
    ///////////////////////////////////////
    
    function CreateAdBlockStructure()
    {
    
        // Create "background" link
        m_objBannerLinkBack = document.createElement("a");
        m_objBannerLinkBack.setAttribute("id", "BannerLinkB");
        m_objBannerLinkBack.setAttribute("name", "BannerLinkB");
        m_objBannerLinkBack.setAttribute("href", "");
        m_objBannerLinkBack.setAttribute("target", "_blank");
        
        // Set style properties for "background" link
        m_objBannerLinkBack.style.position = "absolute";
        m_objBannerLinkBack.style.top = 0;
        m_objBannerLinkBack.style.left = 0;
        m_objBannerLinkBack.style.zIndex = 5;
        m_objBannerLinkBack.style.opacity = 1;
        m_objBannerLinkBack.style.MozOpacity = 1;
        m_objBannerLinkBack.style.KhtmlOpacity = 1;
        m_objBannerLinkBack.style.filter = "alpha(opacity=100)";
        
        m_objBannerImageBack = m_objBannerLinkBack.appendChild(document.createElement("img"));
        m_objBannerImageBack.setAttribute("id", "BannerImageB");
        m_objBannerImageBack.setAttribute("name", "BannerImageB");
        m_objBannerImageBack.setAttribute("border", "0");
                       
        //m_objBannerImageBack.setAttribute("src", "");
        
        // Create "foreground" link
        m_objBannerLinkFront = document.createElement("a");
        m_objBannerLinkFront.setAttribute("id", "BannerLinkA");
        m_objBannerLinkFront.setAttribute("name", "BannerLinkA");
        m_objBannerLinkFront.setAttribute("href", "");
        m_objBannerLinkFront.setAttribute("target", "_blank");
        
        // Set style properties for "foreground" link
        m_objBannerLinkFront.style.position = "absolute";
        m_objBannerLinkFront.style.top = 0;
        m_objBannerLinkFront.style.left = 0;
        m_objBannerLinkFront.style.zIndex = 1;
        m_objBannerLinkFront.style.opacity = 1;
        m_objBannerLinkFront.style.MozOpacity = 1;
        m_objBannerLinkFront.style.KhtmlOpacity = 1;
        m_objBannerLinkFront.style.filter = "alpha(opacity=100)";
        
        // Create image within link
        m_objBannerImageFront = m_objBannerLinkFront.appendChild(document.createElement("img"));
        m_objBannerImageFront.setAttribute("id", "BannerImageA");
        m_objBannerImageFront.setAttribute("name", "BannerImageA");
        m_objBannerImageFront.setAttribute("border", "0");
        
        //m_objBannerImageFront.setAttribute("src", "");
        
        
        // Add version identifier to output
        var objVersion = document.createComment("AdRotator " + VERSION_STRING);
        
        
        
        // Attach the links and images to the ad block
        
        // Scour all current child nodes
        while(m_objAdBlock.hasChildNodes())
        {
            m_objAdBlock.removeChild(m_objAdBlock.firstChild);    
        }
        
        m_objAdBlock.appendChild(objVersion);
        m_objAdBlock.appendChild(m_objBannerLinkBack);
        m_objAdBlock.appendChild(m_objBannerLinkFront);
        
        
    }
        
    function FetchAds()
    {
        if(null == m_objAdInfoRequest)
        {
            return;
        }
        
        m_bFetchingAds = true;
        
        // Make sure scope of the handler is same as class scope       
        var _this = _instance;
        m_objAdInfoRequest.onreadystatechange = function(){_this.OnResult();};
            
        m_objAdInfoRequest.open("GET", m_strAdInfoURL, true);    
        m_objAdInfoRequest.send(null);
        
    }
    
    function OnResult()
    {        
        // State "complete"
        if(4 == m_objAdInfoRequest.readyState)
        {
             // Hide this call from external scripts
            if(!m_bFetchingAds)
            {    
                return;
            }
            m_bFetchingAds = false;
    
            // HTTP return code "OK"
            if(200 == m_objAdInfoRequest.status)
            {
                m_objAdInfoXML = m_objAdInfoRequest.responseXML;
                OnAdsFetched();
            }
            else
            {
                m_strErrorMessage = "HTTP Request returned with status code: " + m_objAdInfoRequest.status;
                OnAdsFetched();
            }
        }
    }
    
    function OnAdsFetched()
    {
        // On success, parse the ad info
        if(null != m_objAdInfoXML)
        {
            ParseAdInfo();
            if(null != _instance.OnInit)
            {
                _instance.OnInit(true);
            }
        }
        else
        {
            if(null != _instance.OnInit)
            {
                _instance.OnInit(false);
            }
        }    
    
    }
    
    function ParseAdInfo()
    {
        // Parse the XML returned from the server to create Ad list
        //if(window.ActiveXObject)
        //{
            var objNodeList = m_objAdInfoXML.getElementsByTagName("Ad");
        //}
        //else
        //{
            //var objNodeList = m_objAdInfoXML.firstChild.getElementsByTagName("Ad");
        //}
        
        var objNewAd;
        for(var i = 0; i < objNodeList.length; i++)
        {
        
            objNewAd = new Ad();
            objNewAd.SetGraphicURL(objNodeList[i].getAttribute(GRAPHIC_URL));
            objNewAd.SetTargetURL(objNodeList[i].getAttribute(TARGET_URL));
    
            objNewAd.SetPlayTime(Number(objNodeList[i].getAttribute(PLAY_TIME)));
            
            // Put the new ad in the rotation array
            m_objAdArray.push(objNewAd);
        }
              
    }
    
    
    function InitialLoad()
    {
        // We should only do this once.
        if(!m_bNeedInitialLoad)
        {
            return;
        }
        m_bNeedInitialLoad = false;
        
        //
        // Load the back buffer and switch to be sure it shows up
        //
        
        if(m_bUseRandomInitialAd)
        {
            m_nAdIndex = Math.floor(Math.random() * m_objAdArray.length);
        }
        else
        {
            m_nAdIndex = 0;
        }
       
        m_cookieposition = m_cookieposition+1;  
        if (m_cookieposition>(m_blockid+2)) {
           m_cookieposition=m_blockid;
        }    
       
        m_objAdArray[m_nAdIndex].InstanceId();
        m_objBannerImageBack.setAttribute("src", m_objAdArray[m_nAdIndex].GetGraphicURL(m_cookieposition));
        m_objBannerLinkBack.setAttribute("href", m_objAdArray[m_nAdIndex].GetTargetURL(m_cookieposition));
        
        // If dimension values are nonzero, enforce image size      
        if(0 != m_nAdHeight && 0 != m_nAdWidth)
        {
            ResizeImage();
        }
        
        m_nAdIndex = m_nAdIndex - 1;
        // Use a short timer to show the first ad
        m_nAdTimerId = setTimeout(_instance.NextAd, 100);
        //NextAd();
    
    }

    // Transition to the next ad in the rotation
    function NextAd()
    {
        // If the callback for the transition is set, a transition
        // is in progress and we should probably prevent moving to the
        // next ad
        if(m_funcTransitionCompleteCallback != null)
        {
            return;
        }
        
        if(0 != m_nAdTimerId)
        {
            clearTimeout(m_nAdTimerId);
        }
                
        // Transition to show the back buffer
        m_funcTransitionCompleteCallback = OnNextAdTransitionDone;
        m_nTransitionOpacity = 1.0;
        DoTransitionEffect();            
        
    }
    
    // Called after completing transition effect from PrevAd() because
    // we can't make "DoTransitionEffect" a blocking call.
    function OnNextAdTransitionDone()
    {
                  
        // Swap buffers
        SwapBuffers();
        
        // Move to the next ad
        m_nAdIndex++;
        if(m_nAdIndex >= m_objAdArray.length)
        {
            m_nAdIndex = 0;
        }
        
        // Set timer for next ad
        m_nAdTimerId = setTimeout(_instance.NextAd, m_objAdArray[m_nAdIndex].GetPlayTime() * 1000);
        
        // Load the back buffer in the background to prepare for the next ad swap
        m_cookieposition = m_cookieposition+1;  
        if (m_cookieposition>(m_blockid+2)) {
           m_cookieposition=m_blockid;
        }  
        
        if(m_nAdIndex + 1 < m_objAdArray.length)
        {
            m_objAdArray[m_nAdIndex + 1].InstanceId();
            m_objBannerImageBack.setAttribute("src", m_objAdArray[m_nAdIndex + 1].GetGraphicURL(m_cookieposition));
            m_objBannerLinkBack.setAttribute("href", m_objAdArray[m_nAdIndex + 1].GetTargetURL(m_cookieposition));            
        }
        else
        {
            m_objAdArray[0].InstanceId();
            m_objBannerImageBack.setAttribute("src", m_objAdArray[0].GetGraphicURL(m_cookieposition));
            m_objBannerLinkBack.setAttribute("href", m_objAdArray[0].GetTargetURL(m_cookieposition));                  
        }
        
        // If dimension values are nonzero, enforce image size
        if(0 != m_nAdHeight && 0 != m_nAdWidth)
        {
            ResizeImage();
        }
        
        m_funcTransitionCompleteCallback = null;
    }
    
    // Transition to the previous ad in the rotation
    function PrevAd()
    {
        // If the callback for the transition is set, a transition
        // is in progress and we should probably prevent moving to the
        // previous ad
        if(m_funcTransitionCompleteCallback != null)
        {
            return;
        }
    
        if(0 != m_nAdTimerId)
        {
            clearTimeout(m_nAdTimerId);
        }
                
        //
        // NOTE:  This part is additional to the code in NextAd() because we use
        // an optimistic buffer scheme.  When the Previous Ad is selected our
        // optimistic buffer fails and we have to dump the back buffer and load
        // the ad, then go back to the normal state of things.
        //
        
        // Load the back buffer with the previous ad
        m_cookieposition = m_cookieposition+1;  
        if (m_cookieposition>(m_blockid+2)) {
           m_cookieposition=m_blockid;
        }  
        
        if(m_nAdIndex - 1 >= 0)
        {
            //m_objAdArray[m_nAdIndex - 1].InstanceId(); 
            m_objBannerImageBack.setAttribute("src", m_objAdArray[m_nAdIndex - 1].GetGraphicURL(m_cookieposition));
            m_objBannerLinkBack.setAttribute("href", m_objAdArray[m_nAdIndex - 1].GetTargetURL(m_cookieposition));            
        }
        else
        {
           // m_objAdArray[m_objAdArray.length - 1].InstanceId(); 
            m_objBannerImageBack.setAttribute("src", m_objAdArray[m_objAdArray.length - 1].GetGraphicURL(m_cookieposition));
            m_objBannerLinkBack.setAttribute("href", m_objAdArray[m_objAdArray.length - 1].GetTargetURL(m_cookieposition));                  
        }
        
        // If dimension values are nonzero, enforce image size
        if(0 != m_nAdHeight && 0 != m_nAdWidth)
        {
            ResizeImage();
        }
                
        // Transition to show the back buffer
        m_funcTransitionCompleteCallback = OnPrevAdTransitionDone;
        m_nTransitionOpacity = 1.0;
        DoTransitionEffect();        
              
    }
    
    // Called after completing transition effect from PrevAd() because
    // we can't make "DoTransitionEffect" a blocking call.
    function OnPrevAdTransitionDone()
    {            
        // Swap buffers
        SwapBuffers();
        
        // Move index to the previous ad (basic redo one cycle)
        m_nAdIndex--;
        if(m_nAdIndex < 0)
        {
            m_nAdIndex = m_objAdArray.length - 1;
        }
        
        m_cookieposition = m_cookieposition+1;  
        if (m_cookieposition>(m_blockid+2)) {
           m_cookieposition=m_blockid;
        } 
        
        
        // Set timer for next ad
        m_nAdTimerId = setTimeout(_instance.NextAd, m_objAdArray[m_nAdIndex].GetPlayTime() * 1000);
        
        // Load the back buffer in the background to prepare for the next ad swap
        if(m_nAdIndex + 1 < m_objAdArray.length)
        {
            m_objAdArray[m_nAdIndex + 1].InstanceId();  
            m_objBannerImageBack.setAttribute("src", m_objAdArray[m_nAdIndex + 1].GetGraphicURL(m_cookieposition));
            m_objBannerLinkBack.setAttribute("href", m_objAdArray[m_nAdIndex + 1].GetTargetURL(m_cookieposition));             
        }
        else
        {
            m_objAdArray[0].InstanceId();
            m_objBannerImageBack.setAttribute("src", m_objAdArray[0].GetGraphicURL(m_cookieposition));
            m_objBannerLinkBack.setAttribute("href", m_objAdArray[0].GetTargetURL(m_cookieposition));                   
        }
        
        // If dimension values are nonzero, enforce image size
        if(0 != m_nAdHeight && 0 != m_nAdWidth)
        {
            ResizeImage();
        }
        
        m_funcTransitionCompleteCallback = null;
    
    }

    function DoTransitionEffect()
    {
        if(m_nTransitionOpacity >= 0 && undefined != m_nTransitionOpacity)
        {
            m_nTransitionOpacity -= 0.1;
            // Use variously supported CSS attributes for different browsers
            m_objBannerLinkFront.style.opacity = m_nTransitionOpacity;
            m_objBannerLinkFront.style.MozOpacity = m_nTransitionOpacity;
            m_objBannerLinkFront.style.KhtmlOpacity = m_nTransitionOpacity;
            m_objBannerLinkFront.style.filter = "alpha(opacity=" + (m_nTransitionOpacity * 100) + ")";
               
            setTimeout(DoTransitionEffect, FADE_SPEED);
        }
        else
        {
            m_funcTransitionCompleteCallback();                
        }                   
    }
    
    function SwapBuffers()
    {
        var objSwapTemp;
        
        // Swap member variable references
        objSwapTemp = m_objBannerLinkBack;
        m_objBannerLinkBack = m_objBannerLinkFront;
        m_objBannerLinkFront = objSwapTemp;
        
        objSwapTemp = m_objBannerImageBack;
        m_objBannerImageBack = m_objBannerImageFront;
        m_objBannerImageFront = objSwapTemp;
        
        
        // Use CSS to swap the buffers on the screen
        m_objBannerLinkBack.style.zIndex = 5;
        m_objBannerLinkFront.style.zIndex = 10;
        
        m_objBannerLinkBack.style.opacity = 1;
        m_objBannerLinkBack.style.MozOpacity = 1;
        m_objBannerLinkBack.style.KhtmlOpacity = 1;
        m_objBannerLinkBack.style.filter = "alpha(opacity=100)";
        
        m_objBannerLinkFront.style.opacity = 1;
        m_objBannerLinkFront.style.MozOpacity = 1;
        m_objBannerLinkFront.style.KhtmlOpacity = 1;
        m_objBannerLinkFront.style.filter = "alpha(opacity=100)";
            
    
    }
    
    function ResizeImage()
    {       
        m_objBannerLinkBack.style.height = m_nAdHeight + "px";
        m_objBannerLinkBack.style.width = m_nAdWidth + "px";
        m_objBannerImageBack.style.height = m_nAdHeight + "px";
        m_objBannerImageBack.style.width = m_nAdWidth + "px";
        /*
        m_objBannerLinkFront.style.height = m_nAdHeight + "px;";
        m_objBannerLinkFront.style.width = m_nAdWidth + "px;";
        m_objBannerImageFront.style.height = m_nAdHeight + "px;";
        m_objBannerImageFront.style.width = m_nAdWidth + "px;";         
        */
    }

}


/******************************************
    Container class for Ad information
*******************************************/

function Ad()
{
    var m_strAdGraphicURL = "";
    var m_strAdTargetURL = "";
    var m_nPlayTime = 0;
    var m_instance = 0;
    var m_nvalue = 0;
         
    this.InstanceId = InstanceId;    
    this.GetTargetURL = GetTargetURL;
    this.SetTargetURL = SetTargetURL;
    this.GetGraphicURL = GetGraphicURL;
    this.SetGraphicURL = SetGraphicURL;
    this.GetPlayTime = GetPlayTime;
    this.SetPlayTime = SetPlayTime;
    
  
    function InstanceId() 
    {
        m_instanceid = Math.floor(Math.random()*11000);
          
    }
  
         
    function GetTargetURL(m_cookieposition)
    {
     
      var newurl1 = m_strAdTargetURL + '?n=' + m_cookieposition + '&cb=' + m_instanceid;
      return newurl1;
    }
    
    function SetTargetURL(strTargetURL)
    {
        m_strAdTargetURL = strTargetURL;
    }
 
    function GetGraphicURL(m_cookieposition)
    {
        var newurl2 = m_strAdGraphicURL + '&n=' + m_cookieposition + '&cb=' + m_instanceid;
        return newurl2;
    }
    
    function SetGraphicURL(strGraphicURL)
    {
        m_strAdGraphicURL = strGraphicURL;        
    }
    
    function GetPlayTime()
    {
        return m_nPlayTime;
    }
    
    function SetPlayTime(nPlayTimeInSeconds)
    {
        
        m_nPlayTime = nPlayTimeInSeconds;        
    }


    

}