/*
   Class: FD
   
   *Version: 0.5*
   
  
     Base class of the Fairfax Digital Javascript Framework.
     This class will allow the registration of FD widgets and
     allows a simple API for adding scripts, advertisements
     and tracking images.
     The class will also automatically initialise the Nielson
     tracking script.
*/ 

var FD = {
  /*
    Group: INITIALISATION
    
    Function: init
    
      FD.init() is run inline to initialise all arrays and to create
      an onDomReady event to call the <FD._initFD> function.
   */
  
  init: function() {
    FD._removeAds = false;
    FD._registeredWidgets = [];
    FD._widgets = [];
    FD._ads = [];
    FD._adLU = []; // Ad Lookup.
    FD._scripts = [];
    FD._images = [];
    FD._trackingImages = [];
    FD._useWidgetPriority = false;
    window.addEvent("domready", FD._initFD);
  },
  
  /*
    Function: _initFD
    
      Run onDomReady to execute all registered functions,
      spawn Advertisements, inject script tags and images.
   */
  _initFD: function() {
    // Init Widgets
    if(eval("typeof(initPost)") == "function") {
      initPost();
    }
    
    // Check for excluded ads
    FD._excludeAds();
    
    // Spawn the ads
    FD._spawnWidgets();
    // Inject tracking Scripts
    FD._initTracking();
    // Inject Script tags
    FD._spawnScripts();
    // Inject Image tags
    FD._spawnImages();
  },
    
  /*
    Group: WIDGETS
    
    Function: _sortByPriority
   
      Helper function to sort widgets and ads by priority.
   */
  _sortByPriority: function(a, b) {
    return a.priority - b.priority;
  }, 
  
  /*
    Function: _spawnWidgets

      Initialises the registered widgets by priority (if any)
   */
  _spawnWidgets: function() {
    if(FD._widgets.length > 1 && FD._useWidgetPriority) {
      FD._widgets.sort(FD._sortByPriority);
    }
    
    FD._widgets.each(function(thisWidget) {
      // Call each widgets init function
      if(thisWidget.type == "ad" && !FD._removeAds && !thisWidget.exclude) {
        FD._spawnAd(thisWidget);
      } else {
        if(!thisWidget.exclude && $type(eval(thisWidget.initF)) == "function") {
          eval(thisWidget.initF).call();
        }
      }
    });
  },
  
  /*
    Function: exclude
   
     Marks a function as excluded which prevents it from being executed.
      
    Parameters: 
   
      widgetName - The name of the widget to exclude from initialisation
     
   */
  exclude: function(widgetName) {
    FD._widgets.each(function(thisWidget) {
      if(thisWidget.name == widgetName) {
        thisWidget.exclude = true;
      }
    });
  }, 
  
  /*
  
    Function: register
    
      Registers a function to be executed by priority onDomReady.
      
   */
  register: function(name, initF, priority) {
    if(name && initF) {
      if(!FD.inArray(FD._registeredWidgets, name)) {
        if(isNaN(priority)) {
          priority = 99;
        } else {
          FD._useWidgetPriority = true;
        }
        FD._registeredWidgets[FD._widgets.length] = name;
        FD._widgets[FD._widgets.length] = {name: name, initF: initF, priority: priority};
      }
    }
  },
  
  /*
   Function: setWidgetPriority
   
    Manually sets the priority of a widget
    
   Parameters:
   
     widgetName - The name of the widget.
     priority - The new priority of the named widget.
     
   */
  setWidgetPriority: function(widgetName, priority) {
    for(var a = 0; a < FD._widgets.length; a++) {
      if(FD._widgets[a].name == widgetName) {
        FD._widgets[a].priority = priority;
      }
    }
  },

  /*
    Group: SCRIPT INJECTION
    
    Function: _injectScript
    
      Creates a new Javascript asset and injects it into the head of the document.
      
   */
  _injectScript: function(id, src) {
    if(!$(id)) {
      FD._scripts[id] = new Asset.javascript(src, {id: id});
    }
  }, 
  
  /*
    Function: _spawnScripts
   
      Injects all registed scripts.
     
   */
  _spawnScripts: function() {
    var thisScript;
    for(var x = 0; x < FD._scripts.length; x++) {
      thisScript = FD._scripts[x];
      FD._injectScript(thisScript.id, thisScript.src);
    }
  },
  
  /*
    Function: addScript
    
      Public setter function to register a script to be injected.
      
   */
  addScript: function(id, src) {
    if(!FD.inArray(FD._scripts, id)) {
      FD._scripts[FD._scripts.length] = {id: id, src: src};
    }
  },
  
  /*
    Group: IMAGE INJECTION
    
    Function: _spawnImages
    
      Initialises all registed images.
      
   */
  _spawnImages: function() {
    for(var x = 0; x < FD._images.length; x++) {
      FD.injectImage(FD._images[x].id, FD._images[x].src, FD._images[x].width, FD._images[x].height);
    }
  },
  
  /*
    Function: addImage
    
      Public setter function to register an image to be injected.
      
   */
  addImage: function(id, src, width, height) {
    if(!FD.inArray(FD._images, id)) {
      FD._images[FD._images.length] = {id: id, src: src, width: width, height: height};
    }
  },  
  
  /*
    Function: injectImage
    
      Injects a new Image  asset into the body of the document.
      
   */
  injectImage: function(id, src, width, height) {
    if(!$(id)) {
      FD._images[id] = Asset.image(src, {"src": src, "width": width, "height": height});
    }
  },

  /*
    Group: ADVERTISEMENTS
  
    Function: _spawnAd
    
      Takes an Advertisement Object and spawns a new iFrame for it if it's div is located.
      If the advertisement's src property is an array of URL's then an iFrame is 
      created for each one and injected randomly into the ads div.

    Parameters:
    
      thisAd - The advertisement object created by <FD.addAd>.
      
    See Also:
    
      <FD.addAd>
      
   */
  _spawnAd: function(thisAd) {
    var thisAdHolder;
    if(thisAdHolder = $(thisAd.id)) {
      if(thisAd.addSmall) {
        var thisSmall = new Element("small");
        thisSmall.setHTML("Advertisement");
      }
      if($type(thisAd.src) == "string") {
        thisAd.src = [thisAd.src];
      }
      if(thisAd.addSmall) {
        thisSmall.injectInside(thisAdHolder);
      }
      var iFrameAttribs = {
        frameBorder: "0",
        marginHeight: "0",
        marginWidth: "0",
        hspace: "0",
        vspace: "0",
        scrolling: "no",
        width: thisAd.width,
        height: thisAd.height
      };
      if(thisAd.src.length > 1) {
        for (var i = thisAd.src.length -1; i >= 0; --i) {
            var j =  Math.floor(Math.random() * (i + 1));
            if (i == j) continue;
            var temp = thisAd.src[i];
            thisAd.src[i] = thisAd.src[j];
            thisAd.src[j] = temp;
        }
      }
      for(var a = 0; a < thisAd.src.length; a++) {
        var src = thisAd.src[a];
        var props = {};
        // Check for js reference in ad tag URL
        if(src.indexOf("/js.ng/") > -1) {
          src = src.replace(/(\/js.ng\/)/i, "/html.ng/");
        }
        if(isNaN(iFrameAttribs.width) || isNaN(iFrameAttribs.height)) {
          // Get the width and height of this ad
          if(src.indexOf("adspace=") > -1) {
            var thisWH;
            if(thisWH = src.match(/adspace=([0-9]+)x([0-9]+)/i)) {
              if(!isNaN(thisWH[1]) && !isNaN(thisWH[2])) {
                props.width = thisWH[1];
                props.height = thisWH[2];
              }
            }
          }
        }
        props.src = src;
        props.id = thisAd.iframeId;
        if(a > 0) {
          props.id += a;
        }
        props.name = props.id;
        /* THIS IS A TEMPORARY INLINE WAY FOR IE's SAKE (self.name issue) */
        var iFrame = "<iframe ";
        var finalProps = $extend(iFrameAttribs, props);
        for(var p in finalProps) {
          iFrame += p+"='"+finalProps[p]+"' ";
        }
        iFrame += "></iframe>";
        thisAdHolder.innerHTML += iFrame;
        /* GOOD DOM WAY 
        var thisIframe = new Element("iframe");
        thisIframe.setProperties($extend(iFrameAttribs, props));
        //thisIframe.addEvent("load", FD.adFrameLoaded.bind(this, thisIframe));
        thisAdHolder.adopt(thisIframe);
        */
      }
      if(thisAd.addSmall) {
        thisSmall.clone().injectInside(thisAdHolder);
      }
    }
  },
  
  /*
    Function: _excludeAds
    
      Checks to see if the ffxAdExclusionList variable has been set
      and excludes ads based on it's content.
      
   */
  
  _excludeAds: function() {
    if (typeof(ffxAdExclusionList) != "undefined") {
      var thisPage = window.location.pathname;
      for (var i = 0; i < ffxAdExclusionList.length; i++) {
        var current = ffxAdExclusionList[i];
        if (current == 'remove_all_ads') {
          FD._removeAds = true;
        } else if (current == 'remove_article_ads') {
          // News Specific
          if (thisPage.match(/\/news\/[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+\/[0-9]{4}\/[0-9]{2}\/[0-9]{2}\/[0-9]+.html/) || thisPage.match(/\/articles\/.*?/)){
            FD._removeAds = true;
          }
        } else if (current == 'remove_index_ads') {
          if  (thisPage.match(/\/index.html$/) || !thisPage.match(/.html$/)) {
            FD._removeAds = true;
          }
        } else if (current == thisPage) {
          FD._removeAds = true;
        }
      }
    }
  },
  
  /*
    Function: addAd
    
      Registers an Advertisement to be initilised onDomReady.
      Advertisements can be registered using the parameters below (depreciated) or by using 
      an object to define the properties (encouraged). See the Examples below for more information.
      
      The Advertisements are added to the _widgets array and initialised inline with the widgets 
      to allow for a visually tailored load process. (i.e: Ads and widgets at the top of the page
      load before those at the bottom).
          
    Parameters:
    
      id - The ID of the Div to insert the Advertisement into.
      iframeId - The ID to use for the iFrame that is inserted into the Advertisement Div.
      src - Either a single URL or an array of URL's. See <FD._spawnAd> for more details.
      width - Optional. The final width of the Advertisement Div.
      height - Optional. The final height of the Advertisement Div.
      addSmall - Optional. Adds &lt;small&gt;Advertisement&lt;/small&gt; before and after the advertisement.
      priority - Optional. Sets the priority of the advertisement in the loading sequence.
      
    Examples: 
      
      (start code)
      
        function initPost() {
          var bust = Math.floor(1000000*Math.random());
          var baseAd = {
            src: "http://ffxcam.smh.com.au/html.ng/",
            params: {
              site: "smh",
              domain: "smh.com.au",
              isiframe: "yes",
              cat: "news"
            }
          };
          
          // Creating an ad for a single 300x250 island ad with priority 1
          FD.addAd($merge(baseAd, {
            id: "adSpotIsland",
            iframeId: "AdPlaceholder-2",
            params: $merge(baseAd.params, {
              adspace: "300x250",
              loc: "search",
              ctype: "page",
              adtype: "doubleisland",
              bust: bust
            }),
            priority: 1,
            addSmall: true
          }));
          
          // Creating an array of text ads each 300x28px to be inserted into the same div
          FD.addAd($merge(baseAd, {
            id: "adSpot-textBox",
            iframeId: "AdPlaceholder-hptextad1",
            src: ["http://ffxcam.smh.com.au/html.ng/loc=1&", 
                  "http://ffxcam.smh.com.au/html.ng/loc=2&",
                  "http://ffxcam.smh.com.au/html.ng/loc=3&",
                  "http://ffxcam.smh.com.au/html.ng/loc=4&",
                  "http://ffxcam.smh.com.au/html.ng/loc=5&"],
            params: $merge(baseAd.params, {
              adspace: "textad",
              ctype: "page",
              fontsize: ".83em"
            }),
            width: 300,
            height: 28
          }));
        }
      
      (end code)
      
   */
  addAd: function(id, iframeId, src, width, height, addSmall, priority) {
    var fields = ['id', 'iframeId', 'src', 'width', 'height', 'addSmall', 'priority'];
    if(arguments.length > 0) {
      var obj = {};
      if($type(arguments[0]) == "object") {
        obj = arguments[0];
      } else {
        for(var a = 0; a < arguments.length; a++) {
          obj[fields[a]] = arguments[a];
        }
      }
      obj.type = "ad";
      if(obj.params) {
        if($type(obj.src) != "array") {
          obj.src = [obj.src];
        }
        for(var a = 0; a < obj.src.length; a++) {
          if(obj.src[a].indexOf("html.ng") == -1 && 
             obj.src[a].indexOf("js.ng") == -1 && 
             obj.src[a][obj.src[a].length - 1] != "/" &&
             obj.src[a][obj.src[a].length - 1] != "?") {
            obj.src[a] += "?";
          }
          for(var p in obj.params) {
            obj.src[a] += p+'='+obj.params[p]+'&';
          }
        }
      }
      if(!FD._ads[obj.iframeId] && $(obj.id)) {
        var thisAd = $(obj.id);
        if(isNaN(obj.priority)) {
          obj.priority = 99;
        } else {
          FD._useWidgetPriority = true;
        }
        
        FD._ads[obj.iframeId] = true;
        FD._widgets.push(obj);
        FD._adLU.push(obj.iframeId);
      }
    }
  }, 
 
  /*
    Function: refreshAd
    
      Refreshes an ad iFrame to (hopefully) display a new ad
      
   */
  refreshAd: function(id) {
    if(id) {
      if(id == "*") {
        // Refresh all ads. 
        FD._adLU.each(function(ad) {
          FD.refreshAd(ad);
        });
      } else {
        var adHolder;
        var adObj;
        if(adObj = FD._ads[id]) {
          if(ad = $(adObj.iframeId)) {
            ad.src = ad.src;
          }
        }
      }
    }
  }, 

  /*
    Group: TRACKING
  
    Function: _getNielsonURL
      
      Returns the current Nielson URL.
   */
  _getNielsonURL: function() {
    return FD.getProtocol()+'//secure-au.imrworldwide.com/';
  },
  
  /*
    Function: _nnRecordFactory
    
      Gathers variables to track a content impression with Nielson
   */
  _nnRecordFactory: function(_nnClickURL) {
    if(_nnClickURL.indexOf("http") == -1) {
      var location = window.location;
      var appendLoc = "";
      if(_nnClickURL.charAt(0) != "/") { // Relative URL
        appendLoc = "/";
      }
      _nnClickURL = location.protocol+"//"+location.host+appendLoc+_nnClickURL;
    }
    var _nnCI = "f2"; // client id no.
    var _nnCY = "au"; // country code
    var _nnCC = 0;    // cookie check
    if (typeof(_nnCG) == "undefined") {
      if(typeof(_rsCG) != "undefined") {
        _nnCG = _rsCG;
      } else {
        _nnCG = 0;
      }
    }
  	var _nnND = FD._getNielsonURL();
  	var _nnPixelSrc = _nnND + 'cgi-bin/m?rnd=' + (new Date()).getTime();
  	_nnPixelSrc += '&ci=' + _nnCI;
  	_nnPixelSrc += '&cg=' + escape(_nnCG); // Site ID picked up globally.
  	_nnPixelSrc += '&cc=' + _nnCC;
  	_nnPixelSrc += '&si=' + _nnCI + '-ctgw-' + escape(_nnClickURL);
  	_nnPixelSrc += '&rp=' + escape(window.location);
    return _nnPixelSrc;
  },
  
  /*
    Function: _initTracking
    
      Initialises the Nielson tracking system by creating a script element
      for the latest version of the Nielson Netratings script.
   */
  _initTracking: function() {
    if(typeof(_rsCG) != "undefined" && typeof(_rsLP) == "undefined") {
      if(!$("nielsonTS")) {
      	var url = FD._getNielsonURL()+"v52.js";
        FD.addScript("nielsonTS", url);
      }
    }
  },  
  
  /*
    Function: _trackingImageLoaded
    
      Removes a tracking image from the image buffer 
      when it has successfully loaded. 
   */
  _trackingImageLoaded: function(id, x) {
    if(FD._trackingImages[id]) {
      FD._trackingImages[id].shift();
    }
  },
  
  /*
    Function: doContentImpression
      
      Tracks a URL with Nielson (and in future Omniture)
   */
  doContentImpression: function(id, url) {
    // Request Buffering
    if(!FD._trackingImages[id]) {
      FD._trackingImages[id] = [];
    }
    // Nielson
    var cCount = FD._trackingImages[id].length;
    var src = FD._nnRecordFactory(url);
    FD._trackingImages[id][cCount] = new Element("img");
    FD._trackingImages[id][cCount].src = src;
		FD._trackingImages[id][cCount].onload = this._trackingImageLoaded.bind(this, [id, cCount]);
  },
  
  /*
    Group: MISC
    
    Function: addTag
    
      Registers an arbitary tag to be injected onDomReady
   */
  addTag: function(type, dest, tag) {
    var thisId = false;
    var splitTag = tag.split(/ /);
    var imgProps = {};
    for(var a = 0; a < splitTag.length; a++) {
      var thisVal;
      if(splitTag[a].indexOf("\"") > -1 || splitTag[a].indexOf("'") > -1) {
        var re = /([a-zA-Z]+)[ =][\"\']+([\d\w\W\s]+?)[\"\']+/i;
      } else {
        var re = /([a-zA-Z]+)[ =]([\d\w\W\s]+?)/i;
      }
      if(thisVal = splitTag[a].match(re)) {
        imgProps[thisVal[1]] = thisVal[2];
      }
    }
    var thisImg = new Element(type);
    thisImg.setProperties(imgProps);
    thisImg.injectInside($$(dest)[0]);
  },  
  
  /*
    Function: getProtocol
      
      Returns the current Protocol.
   */
  getProtocol: function() {
    return location.protocol.indexOf('https') >- 1 ? 'https:' : 'http:';
  },
  
  /*
    Function: inArray
    
      Returns true if the passed value is found in the passed array
   */
  inArray: function(array, value) {
    for(var x = 0; x < array.length; x++) {
      if(array[x] == value) {
        return true;
      }
    }
  },
  
  /*
    Function: setBatchStyle
    
      Sets a style to an array of elements.
   */
  setBatchStyle: function(elements, style, value) {
    for(var a = 0; a < elements.length; a++) {
      elements[a].setStyle(style, value);
    }
  }
};
/*
document.rewrite = document.write;

document.write = function(thisWrite) {
  if(thisWrite.indexOf("ie_ready") > -1) {
    document.rewrite(thisWrite);
  } else if(thisWrite.test(/\<img /i)) {
    FD.addTag("img", "body", thisWrite);
  } else if(thisWrite.test(/\<script/i)) {
    FD.addTag("script", "head", thisWrite);
  } else {
    document.rewrite(thisWrite);
  }
};*/
FD.init();

