/**
  Add a function to be called when the page is loaded. This will append the function
  to any other functions that have already been added.
*/
function addLoadEvent(func) { addEvent(window, 'ondomloaded', func); }
addLoadEvent(function() {
  document.config.debugConsole = false;
  if (document.config.debug) {
    loadJS('lib/debug.js');
  } else {
    if (typeof console == 'undefined') {
      window.console = {
        log: function() { },
        info: function() { },
        warn: function() { },
        error: function() { }
      }
    }
  }
  window.addLoadEvent = function(func) { func(); }
});

/**
  Function to strip JS comments from a string and return the result
*/
function stripComments(str) {
  var nlr = /\n/g;
  str = str.replace(nlr, "");   /* Remove newlines */
  var cr = /^\/\*(.*)\*\/$/i;
  var m = cr.exec(str);
  var ret = false;
  if(m && m.length) {
    var ret = m[1];
  }
  return ret;
}


/**
	Email address format validation function
*/
function echeck(str) {

/*var at="@"
	var dot="."
	var lat=str.indexOf(at)
	var lstr=str.length
	var ldot=str.indexOf(dot)
	
	if (str.indexOf(at)==-1){return false;}
	if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr){return false;}
	if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr){return false;}
	if (str.indexOf(at,(lat+1))!=-1){return false;}
	if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot){return false;}
	if (str.indexOf(dot,(lat+2))==-1){return false;}	
	if (str.indexOf(" ")!=-1){return false;}
	
	return true;*/

    var localFilter=/^(\w|[_.-])+@\w+(\.|-|\w)+$/i;
    var domainFilter=/^.+\.(\w{2}|(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum))$/i;
    var notFilter=/^.+@ovm\.comcast\.net$/i;
    var notFilter2=/\.{2}|-{2}|^\.|\.@/i;

    return !(str.length > 100 || (str.length > 0 && (!domainFilter.test(str) || !localFilter.test(str) || notFilter.test(str) || notFilter2.test(str) )));
		
}

// Setup on DOM loading detection. This will call window.ondomloaded
(function() {
  var domloaded = false;
  var timer;
  
  var init = function() {
    if (domloaded) return;
    domloaded = true;
    if (timer) clearInterval(timer);
    
    if (window.ondomloaded) window.ondomloaded();
  }
  
  // Firefox and Opera
  if (document.addEventListener)
    document.addEventListener('DOMContentLoaded', init, false);
  
  // IE
  // Disabled because it breaks IE. Uncomment the if-statement to re-enable.
  /*@cc_on @*/
  /*@if (@_win32)
    document.write("<script id=\"__ie_onload\" defer=\"defer\" src=\"javascript:void(0)\"><\/script>");
    var script = document.getElementById("__ie_onload");
    script.onreadystatechange = function() {
      //if (this.readyState == "complete") init();
    }
  /*@end @*/
  
  // Safari
  if (is_safari) timer = setInterval(function() {
    if (/loaded|complete/.test(document.readyState)) init();
  }, 10);
  
  // Everything else
  window.onload = init;
})();

/**
  A more generalized version of the addLoadEvent function. Takes three
  arguments:
   - object: DOM object to put the event on
   - eventName: String name of the event to add to ('onclick', 'onload', etc)
   - func: Function to be called when that event is triggered
  See the body of addLoadEvent for an example of this functions usage.
*/
function addEvent(object, eventName, func) {
  var oldevent = object[eventName] || function() { return; }
  object[eventName] = function() { oldevent(); func(); }
}

/**
  Prevent an event from bubbling up the event chain. This method always returns
  false (just as your event handler should if you want this to work). Also, the
  'evt' argument should be watever was passed into your event handler as an argument
*/
function cancelEvent(evt) {
  if (evt === false) return false;
  evt = window.event ? window.event : evt;
  if (!evt) return false;
  evt.cancelBubble = true;
  evt.returnVal = false;
  //if (evt.preventDefault) evt.preventDefault();
  
  return false;
}

/**
  Performs the same functionality as cancelEvent, but will also trigger and
  Omniture SiteCatalyst tracking event.
*/
function cancelTrackEvent(evt) {
  evt = window.event ? window.event : evt;
  if (typeof s != 'undefined') s.bc(evt);
  return cancelEvent(evt);
}

/**
  Returns the current package context. relPath is an option relative path that
  will be merged into the returned package context. 'doc.xml' will always be the
  last element in the package context.
*/
function getPackageContext(relPath) {
  var explodedPC = document.config.dataPackageContext.split('/');
  var explodedPath = (relPath || '').split('/');
  
  explodedPC.pop(); // Remove doc.xml from the package context
  
  for (var i=0; i<explodedPath.length; i++) {
    if (explodedPath[i] == '..') {
      explodedPC.pop();
    } else if (explodedPath[i] == '.') {
      // Do Nothing
    } else if (explodedPath[i] != '') {
      explodedPC.push(explodedPath[i]);
    }
  }
  
  explodedPC.push('doc.xml'); // Add doc.xml onto the end
  
  return explodedPC.join('/');
}

/**
  Controls the visibility of flash and advertisments. 'visible' is a boolean
*/
Object.extend(window, (function() {
  var refCount = {};
  
  function doCount(id, offset) {
    if (typeof refCount[id] == 'undefined') refCount[id] = 0;
    
    var oldCount = refCount[id];
    refCount[id] += offset;
    
    return oldCount == 0 || refCount[id] == 0;
  }
  
  function setVisibility(visible, objects) {
    objects._each(function(o) {
      if (Element.hasClassName(o.parentNode.parentNode, 'ad') && o.nodeName.toLowerCase() == 'iframe') {
        o.style.position = visible ? 'static' : 'relative';
        o.style.left = visible ? '0' : '-9999px';
      } else {
        o.style.visibility = visible ? 'visible' : 'hidden';
      }
    });
  }
  
  return {
    setAdVisibility: function(visible) {
      if (!doCount('ads', visible ? -1 : 1)) return;
      
	  // get all of the iframes that are inside elements with the class ad
      var adIFrames = jQuery("div.ad iframe");
      var objects = $A(adIFrames);
      
      setVisibility(visible, objects);
      
			var objects = $A(document.getElementsByTagName('select')).findAll(function(o) {
				return Element.hasClassName(o, 'hideUnderMore');
			});
			setVisibility(visible, objects);
			
			var objects = $A(document.getElementsByTagName('embed')).findAll(function(o) {
				return (Element.hasClassName(o.parentNode.parentNode, 'ad') || Element.hasClassName(o.parentNode, 'ad_pad') || Element.hasClassName(o.parentNode.parentNode, 'ad_pad'));
			});
			setVisibility(visible, objects);
			
			var objects = $A(document.getElementsByTagName('object')).findAll(function(o) {
				return (Element.hasClassName(o.parentNode.parentNode, 'ad') || Element.hasClassName(o.parentNode, 'ad_pad') || Element.hasClassName(o.parentNode.parentNode, 'ad_pad'));
			});
			setVisibility(visible, objects);
			
			var objects = $A(document.getElementsByTagName('table')).findAll(function(o) {
				return Element.hasClassName(o, 'ad_slug_table');
			});
			setVisibility(visible, objects);
			
			if (objects && objects.length > 0) {
				objects = $A(objects[0].parentNode.getElementsByTagName('object'));
			}
			setVisibility(visible, objects);
    },
    
    setCoverFlashVisibility: function(visible) {
      var cover = $('cover');
      if (!cover) return;
      if (!doCount('cover', visible ? -1 : 1)) return;
      
      var objects = $A(cover.getElementsByTagName('embed'));
      setVisibility(visible, objects);
    },
    
    setVideoVisibility: function(visible) {
      var inlinePlayer = $("inlinePlayerHolder") || $("video-player-holder") || $("videoPlayerContainer") || $("hdplayerdiv") || $("videoChannelPlayerContainer") || $('rss');/*rss is for blogs with video in the feed*/
      if (!inlinePlayer) return;
      if (!doCount('inlinePlayer', visible ? -1 : 1)) return;
      
      var objects = $A(inlinePlayer.getElementsByTagName('embed'));
	  if(objects.length == 0) {
		objects = $A(inlinePlayer.getElementsByTagName('object'));
	  }
      setVisibility(visible, objects);
    },
    
    setArticleFlashVisibility: function(visible) {
        var article = $("article");
        if(!article) return;
        if (!doCount('article', visible ? -1 : 1)) return;
        
        var objects = $A(article.getElementsByTagName('embed'));
        if(objects.length == 0) {
            objects = $A(article.getElementsByTagName('object'));
            if(!objects.length) return;
        }
        setVisibility(visible, objects);
        
    },

    setFlashVisibility: function(visible) {
        setAdVisibility(visible);
        setCoverFlashVisibility(visible);
        setVideoVisibility(visible);
        setArticleFlashVisibility(visible);
    }
  };
})());

/**
  Performs an animated scrollTo to the specified position (x, y). The animation
  will take 'duration' milleseconds to complete. When finished, the 'oncomplete'
  function will be called and passed the same value as easyScrollTo returns.
  
  Returns a function that will call easyScrollTo with the arguments required to
  run the animation in reverse. The function takes an oncomplete argument that
  behaves the same as the argument to easyScrollTo
*/
function easyScrollTo(x, y, duration, oncomplete) {
  var oncomplete = oncomplete || function(returnScroll) { };
  var count = duration * 0.020; // 20 fps
  var frames = Animator.interpolate.linear(0, 1, count);
  var anim = new Animator(frames, duration);
  
  var data = {};
  data.start = { x: window.scrollX, y: window.scrollY};
  if (document.documentElement)
    data.start = { x: document.documentElement.scrollLeft, y: document.documentElement.scrollTop};
  data.factor = { x: x - data.start.x, y: y - data.start.y};
  
  anim.onupdate = function(value) {
    var d = data, s = d.start, f = d.factor;
    window.scrollTo(s.x + value * f.x, s.y + value * f.y);
    return true;
  }
  
  var returnScroll = function(oncomplete) {
    easyScrollTo(data.start.x, data.start.y, duration, oncomplete);
  }
  anim.oncomplete = function() { oncomplete(returnScroll); }
  
  anim.run();
  
  return returnScroll;
}

/**
  Displays the loading overlay, scrolls to the top of the page, and then loads
  and shows an overlay window. 'creator' is the function that will be called to
  load/create the overlay window. It should return an instace of the Window class
  or false on failure. This function is asynchronous and will return immediately
*/
function showOverlay(creator) {
  var loading = new Window('loading');
  loading.onshow = function() {
    easyScrollTo(0, 0, 250, function(returnScroll) {
      if (win = creator()) {
        var _onhide = win.onhide;
        win.onhide = function() {
          _onhide.apply(win);
          returnScroll();
        }
        win.show();
      }
      
      loading.hide();
      if (typeof win == 'undefined' || !win) returnScroll();
    });
  }
  loading.show();
}

/**
	Converts 'ts' into an elapsed format time display. 'vanilla' will be returned
	if the elapsed time is too far off.
*/
function elapsedTimestamp(ts, vanilla) {
  var mn = 60000;
  var hr = mn * 60;
  var dy = hr * 24;
  var render = function(timestamp, units) {
    return [timestamp, ' ', units, (timestamp == 1) ? '' : 's', ' ago'].join('');
  }
  
  var now = new Date(), then = new Date();
  var tsParts = ts.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|([+-]?\d{2}):(\d{2}))/);
  if (!tsParts) return vanilla; // Date is improperly formatted
	
	var hrOffset = tsParts[7] ? parseInt(tsParts[7], 10) : 0;
	var mnOffset = tsParts[8] ? parseInt(tsParts[8], 10) : 0;
  then.setUTCFullYear(tsParts[1]);
  then.setUTCMonth(tsParts[2]-1);
  then.setUTCDate(tsParts[3]);
  then.setUTCHours(parseInt(tsParts[4], 10) - hrOffset);
  then.setUTCMinutes(parseInt(tsParts[5], 10) - mnOffset);
  then.setUTCSeconds(tsParts[6]);
  
  var diff = now.getTime() - then.getTime();
  var diffDy = Math.round(diff/dy);
  var diffHr = Math.round(diff/hr);
  var diffMn = Math.round(diff/mn);
  
  if (diff < 1*mn) return 'Seconds ago';
  if (diffMn < 60) return render(diffMn, 'minute');
  if (diffHr < 24) return render(diffHr, 'hour');
  if (diffDy < 2) return render(diffDy, 'day');
  
  return vanilla;
}

// Defining these functions inside a function to avoid polluting the global
// namespace. Also it makes loadedJS and prefixJS effectively private attributes
Object.extend(window, (function() {
  // Don't define the methods if they're already defined. Doing this would clear
  // out the loadedJS array and break functionality
  if (typeof window.loadJS != 'undefined' || typeof window.includedJS != 'undefined')
    return { };
  
  var loadedJS = [];
  var prefixJS = function() {
    var prefix = '', scripts = document.getElementsByTagName('script');
    
    for (var i=0, l=scripts.length; i<l; i++) {
      if (scripts[i].src == '') continue;
      prefix = scripts[i].src.match(new RegExp("^.*ui/js/"))[0];
      break;
    }
    
    if (prefix == '') return prefix;
    
    prefixJS = function() { return prefix; }
    return prefixJS();
  }
  
  addLoadEvent(function() {
    var scripts = document.getElementsByTagName('script');
    var cleanupRE = new RegExp("^" + prefixJS() + "([^?]*)"); 
    
    for (var i=0, l=scripts.length; i<l; i++) {
      if (scripts[i].src == '') continue;
      var match = scripts[i].src.match(cleanupRE);
      if (match) window.includedJS(match[1]);
    }
  });
  
  return {
    /**
      Loads a JavaScript file into the window's context. If the file has already
      been loaded, then it is not loaded again. Returns true if the file was
      successfully loaded (either now or previously).
      
      js_file is the path of the JavaScript file relative to the ui/js directory
    */
    loadJS: function(js_file, force) {
      for (var i=0, l=loadedJS.length; i<l; i++)
        if (!force && js_file == loadedJS[i]) return true;
      
      var req = new Ajax.Request(
        prefixJS() + js_file,
        {
          method: 'get',
          parameters: Ajax.parameters({ r: document.config.revision }), 
          asynchronous: false
        }
      );
      
      if (req.responseIsFailure()) return false;
      
      var script = req.transport.responseText;
      if (script == '') return false;
      if (window.execScript) {
        window.execScript(script);
      } else {
        var s = document.createElement('script');
        s.appendChild(document.createTextNode(script));
        document.documentElement.appendChild(s);
      }
      
      window.includedJS(js_file);
      return true;
    },
    
    /**
      Marks a JavaScript file as having been included on the page.
    */
    includedJS: function(js_file) { loadedJS.push(js_file); }
  }
})());


/***
 * Fix for IE Flash bug that throws js error when page refreshes - we override 
 * IE's flash clean up function
 */
addLoadEvent(function(){
	window.__flash__removeCallback = function(instance, name){
		if (instance != null) { instance[name] = null; }
	}
});


/*
	Fix images with class "png" is IE. This is a quick hack since the
	pngbehavior doesn't seem to be working for some reason
*/
addLoadEvent(function() {
	if (!is_ie) return;
	
	var pngs = Element.getByTagClass(document.body, "img", "png");
	var blankGif = /\/ui\/images\/lib\/blank\.gif/;
	pngs.each(function(png) {
		if (!blankGif.test(png.src)) {
			png.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + png.src + "',sizingMethod='image')";
			png.src = '/ui/images/lib/blank.gif';
		}
	});
});

/**
Function binding and currying methods
*/
(function($) {
    // jQuery's merge function has a bug causing it to fail when an array
    // element contains a value that evaluates to false. Therefore, I'm writing
    // my own.
    var merge = function(a1, a2) {
            for (var i=0; i<a2.length; i++) {
                    var l = a1.length;
                    a1[l] = a2[i];
            }
            return a1;
    }

    $.extend(Function.prototype, {
            // Returns a function that is permanently bound to the given context.
            // References to 'this' in the function will resolve to 'context'.
            context: function(context) {
                    var f = this;
                    return function() {
                            return f.apply(context, arguments);
                    }
            },
   
            // Returns a function that is partially curried with the given arguments
            // The first arguments to the function will always be the same as the passed
            // in arguments.
            curry: function() {
                    var f = this, args = arguments;
                    return function() {
                            return f.apply(this, merge(args, arguments));
                    }
            }
    });
})(jQuery);


/**
 * As part of removing User PII from cookies, 
 * these functions can be used to get user information
 * from Java service
 */
var UserDataEvent = {
	SUCCESS: "userdata_recieved",
	FAILURE: "userdata_failure"
};

/**
 * Usage: initialize UserData to prefetch user info
 * on document loads and use getEmail() to get
 * Email when needed
 */
 var UserData = function() {
	this._uname = null;
	this._email = null;
	this._isHsi = false;
	this.fetchEmail();
};

jQuery.extend(UserData.prototype, {
	
	getUsername: function() {
		if(this._uname != null &&
		   this._uname.length > 0)
			return this._uname;
		else return null;
	},
	
	getEmail: function() {
		if(this._email != null &&
		   this._email.length > 0)
			return this._email;
		else return null;
	},
	
	isHsi: function() {
		return this._isHsi;
	},
	
	_responseRecieved: function(respText) {
		var respXML= null;
		
		//since the response isn't in xml format
		// convert to xml for IE browsers
		if (jQuery.browser.msie) {
			respXML = new ActiveXObject('Microsoft.XMLDOM');
			respXML.async = false;
			respXML.loadXML(respText);
		}else {
			respXML = respText;
		}

		this._uname = jQuery("userName", respXML).text();
		this._email = jQuery("userEmail", respXML).text();
		var hsiFlag = jQuery("isHsiUser", respXML).text();

		(hsiFlag == "yes")? this._isHsi = true : this._isHsi = false;
		
		jQuery(this).trigger(UserDataEvent.SUCCESS);
	},
	
	_errorRecieved: function(respText) {
		jQuery(this).trigger(UserDataEvent.FAILURE);
	},
	
	fetchEmail: function() {
		jQuery.ajax({
			type: "GET", 
			url: "/user/authkey/service/sessiondecryption/",
			cache : false,
			success: this._responseRecieved.context(this),
			error: this._errorRecieved.context(this)
		});
	
	}
});
