/**
 * This Javascript reads all anchors on a page that go to a different page, in
 * other words are not hash '#' hrefs for other Javascript functionality or to
 * jump to a section of the current page. It then evaluates whether the link goes
 * to an external page or document, and binds an onclick event that sends a
 * tracking event to Google Analytics accordingly.
 *
 * Dependent on the configuration at /cms/admin/config/occ_js_conf/settings,
 * passed through as var {Object} options, the result of .click() will either
 * apply target="_blank" to the anchor and let the browser run normally, or stop
 * the browser from following the link and instead redirect the window manually
 * after a short delay.
 *
 * The latter case is to allow the browser enough time to complete the event
 * tracking task, since the current window will be redirected to a new page. In
 * the former case, the timeout is not necessary since the current window stays
 * open, and in any case, the time it would take a user to notice this and
 * potentially close the previous window would be long enough for the tracking
 * code to execute.
 *
 * All care and attention has been given to make this code as efficient as
 * possible, since it will run on every page for every anonymous user. Please
 * make speed the utmost priority when developing this script. For example, use
 * strict comparison operators (===, !==, etc) wherever possible.
 *
 * CHANGES: 30/01/2012
 * - Placed code inside a function that now gets called from template.php and has options passed to it.
 * - Allowed options to define whether a link opens in a new window or the same
 * window. This means the tracking code runs either as is or in a setTimeout(),
 * respectively.
 * - As a result of both the above, the setting of 'target="_blank"' for 'open
 * in new window' links has been moved to within the onclick handler function.
 * It was assumed that problems would arise from changing a clicked-on element
 * right when it is being evaluated - like the browser wouldn't pick up on the
 * new target attribute value - but this has been tested and works in Chrome,
 * Firefox, and IE7.
 * - Also as a result of the above, the anchor jQuery object needed to be passed
 * to the anonymous function in which the onclick handler function is wrapped.
 * - Refined regex_doctype to exclude all hrefs that don't begin with '/'. Some
 * 'mailto:'s were being evaluated as 'documents' because they satisfied the
 * original RegExp, which was just checking the last 2-4 characters. Since
 * 'external link' hrefs had already been checked (due to the order of execution),
 * it was wrongly assumed that the beginning of the href string did not need checking.
 *
 * CHANGES: 06/02/2012
 * - Added new RegExp object to test for images. If found, code jumps to the next
 * item in the loop, as we don't want to do anything with images. This decision
 * was made because our image galleries on standard_page type content, made
 * functional with fancybox (image opens in an overlay), had onclick events on
 * the anchors that were being interrupted by the onclicks added by this code -
 * only when the option to not open in a new window was set for whatever type the
 * image was being evaluated as. (They could be either absolute or relative.) An
 * assumption was made that image download tracking is not required.
 */

/**
 * @param {Object} options An object of the configuration options set at
 * /cms/admin/config/occ_js_conf/settings. This is used to determine the
 * setTimeout() delay for links without the target attribute set to "_blank" or
 * "_new".
 *
 * options.timeout = {Integer} Length of setTimeout() delay for links opening in
 * the same window. 
 */
function occ_link_tracker_run(options)
{
  // Set default options if none set.
  if( typeof options !== "object" )
  {
    options = new Object();
  }
  if( !options.hasOwnProperty('timeout') )
  {
    options.timeout = 100;
  }
  jQuery(document).ready( function()
  {
    // Get all anchors that don't have an href value starting with '#'.
    var anchors = jQuery( '#wrapper a' ).not( 'a[href^="#"]' );
    // Initialise our variables here so they don't get scoped globally.
    var anchor, type, href, i, doctype, target;
    // Create our regex patterns as compiled RegExp objects, for greater speed.
    // Case-insensitive: match '/' at the beginning, then anything apart from a
    // newline, then the following returned group: a dot followed by 2 to 4 letters
    // from a-z at the end of the string. The '^\/' match is necessary to exclude
    // 'mailto:' hrefs.
    var regex_doctype = new RegExp( /^\/.+(\.[a-z]{2,4})$/i );
    // Case-insensitive: match 'http://' or 'https://' at the beginning that
    // doesn't have 'www.oxfordshire.gov.uk' following it.
    var regex_is_ext = new RegExp( /^http(s)?:\/\/(?!www.oxfordshire.gov.uk)/i );
    // Case-insensitive: match image extensions.
    var regex_is_img = new RegExp( /\.(jpeg|jpg|gif|png)$/i );
    // Now we parse the anchors and set onclicks and other attributes for Google Analytics tracking.
    for( i = 0; i < anchors.length; i++ )
    {
      // Reset comparison variables. This could also be accomplished with
      // anonymous function closure, but setting type to false means we can make
      // a strict comparison when we ask "Do we want to modify this anchor?"
      type = false;
      // Get a jQuery set of the single anchor we are currently at. Though this
      // is costly, we need a jQuery object to use jQuery's .attr() method, which
      // returns the value before the DOM modifies it. For example, a href of
      // "/cms/foo/bar", when accessed through a DOM element, will become
      // "http://www.oxfordshire.gov.uk/cms/foo/bar".
      anchor = jQuery( anchors[i] );
      // Get the href, the determining value for this script.
      href = anchor.attr('href');
      // Does this anchor have the href attribute set? Forforward-compatibility
      // with jQuery, we must check for undefined AND empty string. This is due
      // to an upgrade to the .attr() module as of jQuery v1.6. For an href to be
      // set, it must be neither undefined nor an empty string.
      // @ see http://api.jquery.com/attr/
      if( typeof href !== "undefined" && href !== '' )
      {
        // Is this link to an image? Here we use RegExp.test() that returns a
        // boolean, since we don't need to use any matched text.
        if( regex_is_img.test(href) )
        {
          // End current iteration and continue to next item in the loop.
          continue;
        }
        // Is this link to an external page? Here we use RegExp.test() that returns
        // a boolean, since we don't need to use any matched text.
        if( regex_is_ext.test(href) )
        {
          type = 1; // External page.
        }
        else
        {
          // Is this link to a document? RegExp.exec() returns an array of matches,
          // or null for no matches.
          doctype = regex_doctype.exec(href);
          if( doctype !== null )
          {
            type = doctype[1]; // We want to use the matched parenthesised group.
          }
        }
        // Do we want to modify this anchor?
        if( type !== false )
        {
          // Get the target attribute value from this anchor.
          target = anchor.attr('target');
          /**
           * A note for the following conditionals that bind an onclick event to
           * the current anchor in this for loop:
           * We use an anonymous function to create a closure, in which the
           * current value of the variables 'type' and 'href' are passed to the
           * onclick function at the time the closure was created. This ensures
           * the correct values are used in the onclick event. Without this
           * closure, the variables would contain the last value assigned to them
           * when it comes to running the function upon firing the onclick event.
           * This is common practice for using jQuery.click() inside loops.
           * @see http://stackoverflow.com/questions/1485770/how-to-store-local-variables-in-jquery-click-functions
           */
          // Is this link to an external page?
          if ( type === 1 )
          {
            // Start an anonymous function that receives the target attribute
            // value of this anchor, and the destination URL.
            (function (target, h1) {
              // Set the onclick attribute to send a trackEvent to Google.
              anchor.click(function()
              {
                // Tell Analytics to track an event with 'Category' defined as
                // an external link, and the 'Action' being the destination URL.
                _gaq.push( ["_trackEvent", "External Links", h1] );
                // Are we meant to open this link in a new tab/window?
                if( target === '_blank' )
                {
                  // Tell the browser to continue normally. The current window
                  // stays open, giving _gaq.push() enough time to run.
                  return true;
                }
                else
                {
                  // Delay the new URL to allow the analytics code enough time to run.
                  setTimeout('document.location = "' + h1 + '"', options.timeout);
                  // Stop acting on the click event to allow this code to redirect
                  // manually.
                  return false;
                }
              }); // End of .click().
              // Close anonymous function and run it immediately, passing the target
              // attribute value, and the destination URL.
            })(target, href);
          }
          // Otherwise, this link is to a document.
          else
          {
            // Start an anonymous function that receives the target attribute
            // value of this anchor, the document extension, and the destination
            // URL.
            (function (target, t1, h1) {
              // Set the onclick attribute to send a trackEvent to Google.
              anchor.click(function()
              {
                // Tell Analytics to track an event with the following data.
                _gaq.push( ["_trackEvent", "Download", t1, h1] );
                // Are we meant to open this link in a new tab/window?
                if( target === '_blank' )
                {
                  // Tell the browser to continue normally. The current window
                  // stays open, giving _gaq.push() enough time to run.
                  return true;
                }
                else
                {
                  // Delay the new URL to allow the analytics code enough time to run.
                  setTimeout('document.location = "' + h1 + '"', options.timeout);
                  // Stop acting on the click event to allow this code to redirect
                  // manually.
                  return false;
                }
              }); // End of .click().
              // Close anonymous function and run it immediately, passing the target
              // attribute value, document extension, and the destination URL.
            })(target, type, href);
          } // End if/else
        } // End code to modify an anchor if it is to an external page or document.
      } // End code for an anchor that has the href attribute set.
    } // End for loop over the set.
  }); // End jQuery(document).ready();
} // End function occ_link_tracker_run().
