/******* A collection of utilities **************/

var undefined;

var utils = {
	mousePosition_x : 0,
	mousePosition_y : 0
};

utils.bindToEvent = function(obj, evt, fnc, useCapture){
	if (! obj) {
		return;
	}
	if (arguments.length < 4) 
		useCapture=false;
	if (obj.addEventListener){
		obj.addEventListener(evt, fnc, useCapture);
	} 
	else if (obj.attachEvent) {
		obj.attachEvent("on"+evt,fnc);
	}
	return true;
}

utils.unbindEvent = function(obj, evt, fnc) {
	if (!obj) {
		return;
	}
	if (obj.removeEventListener){
		obj.removeEventListener(evt, fnc, false);
	} 
	else if (obj.detachEvent) {
		obj.detachEvent("on" + evt, fnc);
	}
}

utils.getObjectPosition = function (obj) {
	if (typeof(obj) == 'string') {
		obj = document.getElementById(obj);
	}
	var ret = { left: 0, top: 0 };
	if (obj) {
		while (obj.offsetParent) {
			ret.left += parseInt(obj.offsetLeft);
			ret.top += parseInt(obj.offsetTop);
			obj = obj.offsetParent;
		}
	}
	return ret;
}

/* utils.isSemitic = function(txt) {
	return txt && txt.match(/[א-ת]/);
} */

/**
 * Setup a function to call a callback with the appropriate context. This is done by hanging
 * the context and the callback on the function object.
 * @param {Function} func the global function that is the intermediate, contextless callback
 * @param {Object} context Optional object which is the context of the real callback
 * @param {Function} callback The real callback to call with the context
 * @map {Object} optional key/value map of properties to hang on the intermediate callback 
 */
utils.setupCallback = function(func, context, callback, map) {
	var cbData = { context : context, callback : callback };
	func.cbData = cbData;
	if (map) {
		for (var key in map) {
			cbData[key] = map[key];
		}
	}
}

utils.getCallback = function(context, callback, map) {
	var cb = function() {
		utils.triggerCallback(arguments.callee, arguments);
	};
	utils.setupCallback(cb, context, callback, map);
	return cb;
}

/**
 * Runs a callback with a context, previously set up in setupCallback
 * @param {Function} func usually arguments.callee, the global function which is the intermediate callback
 * @param {Array} argsArray the array of parameters to be used as arguments for the real callback 
 */
utils.triggerCallback = function(func, argsArray) {
	var cbData = func.cbData;
	if (cbData) {
		//func.cbData = null;
		cbData.callback.apply(cbData.context, argsArray);		
	}
}

utils.triggerRepeatingCallback = function(func, argsArray) {
	var cbData = func.cbData;
	if (cbData) {
		
		if (!argsArray) {
			argsArray = [];
		}
		cbData.callback.apply(cbData.context, argsArray);		
	}
}


utils.getObjectSize = function(obj) {
	if (typeof(obj) == 'string') {
		obj = document.getElementById(obj);
	}
	var ret = {width : 0, height : 0};
	if (obj) {
//			var rect = obj.getBoundingClientRect();
		if (obj.clientWidth) {
			ret.height = obj.clientHeight;
			ret.width = obj.clientWidth;
		}
		else if (obj.style) {
			if (obj.style.width) {
				ret.height = parseInt(obj.style.height);
				ret.width = parseInt(obj.style.width);
			}
		}
	}
	return ret;
}

utils.getPastDate = function (daysAgo) {
	var theDate = new Date();
	
	//set fromDate to daysAgo days ago...
	theDate.setTime(theDate.getTime() - daysAgo*24*60*60*1000);
	theDate.setHours(0);
	theDate.setMinutes(0);
	theDate.setSeconds(0);
	theDate.setMilliseconds(0);
	
	return theDate;
}

	utils.truncateStr = function (string, num, add) {
	    var trunc;
	    if (num == undefined) num = 30;
	    if (add == undefined) add = "…";
	    if (string == undefined)
	      return;
	    else if (string.length <= num)
	            return string;
	         else {
	            trunc = string.substring(0, num)+add;  
	            return trunc;
	    } 
	  }
	  
	  function objectAsString (object, name) {
	  	var strVars = ObjectStringifier.instance.objectToString(object);
	  	return "[" + name + "{" + strVars + "}" + "]";
	  	
	  }
	  
	  function copyDataObject (source, target) {
			for (var key in source) {
				if (typeof(source[key]) != 'function') {
					target[key] = source[key];
				}
			}	
		}
	
  //////////////////////////////////
  
  utils.readParams= function(str) {
	if (! str) {
		return;
	}
	
	var map = {};
	str = str.substring(1);
	var arr = str.split('&');
	for (var i = 0, len = arr.length; i < len; i++) {
		var pair = arr[i];
		if (pair) {
			var ind = pair.indexOf("=");
			if (ind > 0 && ind < pair.length - 1) {
				var key = pair.substring(0, ind);
				var value = pair.substring(ind + 1);
				map[key] = value;
			}
		}		
	}
	return map;
}


  	
////////////////////////////////////////////////////////////////////////////
	
utils.disableElement = function($el) {
	if (! $el.length) {
		return;
	}
	var dis = $(".disabledOverlay", $el)
	if (dis.length) {
		return;
	}
	$('*', $el).unbind();

	var el = $el[0];
	var div = document.createElement('div');
	div.className = 'disabledOverlay';
	el.appendChild(div);
	utils.bindToEvent(el, 'mousedown', utils.eventKiller); 
	utils.bindToEvent(el, 'mouseup', utils.eventKiller); 
	utils.bindToEvent(el, 'keydown', utils.eventKiller); 
	utils.bindToEvent(el, 'click', utils.eventKiller); 
}

utils.cleanupDisabledElements = function() {
	var els = $(".disabledOverlay");
	for (var i = els.length -1; i >= 0; i--) {
		var el = els[i];
		if (el) {
			utils.unbindEvent(el.parentNode, 'mousedown', utils.eventKiller)
			utils.unbindEvent(el.parentNode, 'mouseup', utils.eventKiller); 
			utils.unbindEvent(el.parentNode, 'keydown', utils.eventKiller); 
			utils.unbindEvent(el.parentNode, 'click', utils.eventKiller); 
		}
	}
}

utils.eventKiller = function(evt) {
	if (! evt) {
		evt = window.event;
	}
	if (evt.preventDefault) {
		evt.preventDefault();
	}
	if (evt.stopPropagation) {
		evt.stopPropagation();
	}
	evt.cancelBubble = true;
	evt.returnValue = false;
	return false;
}

/****** Mixin event model ****************/

utils.mixinEventModel = function(proto) {
	
	proto.addListener = function(l) {
		if (! this.listeners) {
			this.listeners = [];
		}
		this.listeners.push(l);
	}
	
	proto.removeListener = function(l) {
		var lst = this.listeners; 
		if (lst) {
			for (var i = lst.length - 1; i >= 0; i--) {
				if (lst[i] == l) {
					lst.splice(i, 1);
				}	
			}
		}	
	}
	
	proto.broadcast = function() {
		var lst = this.listeners;
		if (! lst) {
			return;
		}
		for (var i = 0, len = lst.length; i < len; i++) {
			var l = lst[i];
			if (l && l.listenToMessage) {
				l.listenToMessage.apply(l, arguments);
			}		
		}
	};
}

/*
* The function shows the given image in the given rectangle.
* Parameters: 	URL of the image (string), 
* 				container of the image (jQuery)
* 				noCrop (boolean) - If(true), not to crop the second dimension. By default is "false".
* 				vAlign (string): Currently only "top" works.
* 				link (string): If the image should be clickable, this is the url. 
*   
*/
function showImageInRect(myURL, jContainer, noCrop, vAlign, anc) {
		if (noCrop == undefined) noCrop = false;
		if (vAlign == undefined) vAlign = "";
		
		jContainer.empty();
		var img = document.createElement('img');

		if (!anc) { 
			jContainer.append(img);
		}
		else {
			anc.appendChild(img);
			jContainer.append(anc);			
		}

		var tempImage = new Image();
		var jtemp = $(tempImage);
		jtemp.bind('load', function(e) {
			jtemp.unbind();
			showImageInRectVert(jtemp, jContainer, img, noCrop, vAlign, anc);
		});
		//----------
		jtemp.error(function() {
			jtemp.unbind();
			//jtemp.hide();
			jContainer.empty();
			jContainer.addClass('dfimg');
		});
		//----------
		tempImage.src = myURL;
		 }

	/////////////////////////////////////////////////////////////////////////////////////////////
	  		
		function showImageInRectVert(jqimg, container, imgItem, noCrop, vAlign, anc) {

	        var theImg = jqimg.get(0);      // jqimg - jQuery object of the image, theImg - node element
	        var rWidth=container.width();             // rect width 
	        var rHeight=container.height();            // rect height 
	        if (rWidth <= 0) {
	        	rWidth = parseInt(container[0].style.width);
	        }
	        if (rHeight <= 0) {
	        	rHeight = parseInt(container[0].style.height);
	        }
	        
	        
	        
	        var cTop, cRight, cBottom, cLeft; // variables for css - clip:rect(cTop cRight cBottom cLeft);
	        var dif;                    // difference between wanted and existing width or height
	        var w, h;
	        var cropProc=0; 
	        var cfn, cfnRes; 
	        var clipString;
	        var px = 'px';
	        var rRel=rHeight/rWidth;    // relation between height and width of the rect
	        var imgRel=theImg.height/theImg.width; // relation between height and width of the image
	        rRel=rRel-(rRel % 0.01);
	        imgRel=imgRel-(imgRel % 0.01);
	        var st = imgItem.style;
	        st.position = 'absolute';

	        var resizedWidth, resizedHeight; // width or height of the image as it would be resized
		    if (imgRel == rRel) {
	            cfn=theImg.width/rWidth;       
	            if (cfn>4 && !noCrop) {
	                cropProc=10;
	            } 
	            cLeft=Math.round(theImg.width*cropProc/100);
	            cTop=Math.round(cLeft*rRel);
	            w=rWidth+cLeft*2;
	            st.width = String(w) + px;
			}

		    else if (imgRel < rRel) {
	            cfn=theImg.height/rHeight;
	            if (cfn>4 && !noCrop) {
	                cropProc=10;
	            } 
	            cTop=Math.round(theImg.height*cropProc/100);            
	            h=rHeight+cTop*2;
		        cfnRes=theImg.height/h;
	            resizedWidth=theImg.width/cfnRes;
	            dif=resizedWidth-rWidth;
	            cLeft=Math.round(dif/2);
	            st.height = String(h) + px;
	        }

		    else if (imgRel > rRel) {
		        cfn=theImg.width/rWidth;
	            if (cfn>4 && !noCrop) {
	                cropProc=10;
	            } 
	            cLeft=theImg.width*cropProc/100;  // crop cropProc% from the image widht
	            w=rWidth+cLeft*2;
	            cfnRes=theImg.width/w;           
	            resizedHeight=theImg.height/cfnRes;
	            dif = resizedHeight-rHeight;
	            cTop=Math.round(dif/4);
	            if(vAlign == "top") {
	            	cTop=0;	            	
	            }
	            st.width = String(w) + px;
	        }

	        cRight=cLeft+rWidth;   
	        cBottom=cTop+rHeight;
	        clipString ='rect('+ cTop +'px '+ cRight+'px '+ cBottom+'px '+ cLeft+'px)';
	        st.clip = clipString;
	        st.top = String(-cTop) + px;
	        st.left = String(-cLeft) + px; 
	        imgItem.setAttribute('src', theImg.src);
		
		}		
//////////////////////////////////////////////////////////////////////////////////////////////
		
function ObjectStringifier(delimChar, equalsChar, stringPrefix, stringPostfix) {
		this.delimChar = delimChar;
		this.equalsChar = equalsChar;
		this.stringPrefix = stringPrefix ? stringPrefix : "";
		this.stringPostfix = stringPostfix ? stringPostfix : "";
	}
	
	ObjectStringifier.prototype = new Object;
	
	
	ObjectStringifier.prototype.objectToString = function(obj) {
		var str = this.stringPrefix;
		
		if (obj) {
			for (var key in obj) {
				if (typeof(obj[key]) == 'function') {
					continue;
				}
				str = this.writeStringField(key, obj[key], str);
				
			}
		}
		return this.endString(str);
	}
	
	ObjectStringifier.prototype.writeStringField = function(key, value, str) {
		if (!key) {
			return;
		}
		
		if (!str) {
			str = this.stringPrefix;
		}
		
		if (str != this.stringPrefix) {
			str += this.delimChar;
		}
		
		if (!value && value!=false) {
			value = "";
		}
		
		str += key + this.equalsChar + value;
		return str;
	}
	
	ObjectStringifier.prototype.endString = function(str) {
		if (str.indexOf(this.stringPostfix) != str.length-1) {
			str = str + this.stringPostfix;
		}
		return str;
	}
	
	ObjectStringifier.prototype.emptyString = function() {
		return this.stringPrefix + this.stringPostfix;
	}
	
	
	
	ObjectStringifier.prototype.stringToObject = function(str) {
		var obj = {};
		if (!str) {
			return obj;
		}
		if (str.indexOf(this.stringPrefix) == 0) {
			str = str.substring(1);
		}
		if (str.indexOf(this.stringPostfix) == str.length-1) {
			str = str.substring(0, this.stringPrefix.length-1);
		}
		
		var entries = str.split(this.delimChar);
		for (var i = 0; i< entries.length; i++) {
			var entry = entries[i].split(this.equalsChar);
			if (entry[0] != "") {
				obj[entry[0]] = entry[1];
			}
		}
		
		return obj;
	}
	
	ObjectStringifier.instance = new ObjectStringifier(",", ":");
	
	//////////////////////////////////////////////////////////////////////////////////////////////////
	
	  function getMousePosition(args) {
		    // Checks if the browsers is IE or another.
		  	// document.all will return true or false depending if its IE
		  	// If its not IE then it adds the mouse event

		if (!document.all)
			document.captureEvents(Event.MOUSEMOVE);

		// Gets IE browser position
		if (document.all)
		  {
			  utils.mousePosition_x = event.clientX + document.body.scrollLeft;
			  utils.mousePosition_y = event.clientY + document.body.scrollTop;
		  }

		  // Gets position for other browsers
		  else
		  { 
			  utils.mousePosition_x = args.pageX;
			  utils.mousePosition_y = args.pageY;
		  } 
		//alert(utils.mousePosition_x+" ff "+utils.mousePosition_y);
	}


DataProcessor = {
	m_Date : new Date(),
	MAX_RELATED : 4, // max # of contributing terms to use when constructing the 'related' string
	m_Regexp : {
		siteName : 
			{ 
				from: /^http[s]*:[\/]+([w]{3,3}\.)*/i,	
				to: ""
			},
		removePath : 
			{
				from: /([^\/:]+)[:\/].*/,
				to: "$1"
			}
	},
	DAY_NAMES : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
	MONTH_NAMES : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
}

DataProcessor.processDate = function(nDate, now) {
/* nDate - e.g. 1257930143 
 * now - e.g. Thu Nov 12 2009 15:02:23 GMT+0200 (Jerusalem Standard Time) */
	
	if (typeof(nDate) != 'number') {
		return '[Unknown time]';
	}
	this.m_Date.setTime(nDate);	
	
	var itemDate = this.m_Date.getDate();
	var nowDate = now.getDate();
	//alert("*"+nowDate+"*"+typeOf(nowDate));
	var yester = nowDate - itemDate; 
	
	var diff = now.getTime() - nDate;
	diff = Math.round(diff / 60000);
	if (diff < 2) {
		return '1 minute ago';		
	}
	if (diff < 60) {
		return '' + diff + ' minutes ago';
	}
	diff = Math.round(diff / 60);
	//alert(diff);
	if (diff <= now.getHours()) {
		if (diff == 1) {
			return '1 hour ago';
		}
		else {
			if (yester == 1) {
				return 'Yesterday';	
			}
			else {
				return '' + diff + ' hours ago';
			}
		}	
	}
	
	var itemYear = this.m_Date.getFullYear();
	var nowYear = now.getFullYear();
	var itemMon = this.m_Date.getMonth();
	var nowMon = now.getMonth();

	var dateStr = itemDate + " " + DataProcessor.MONTH_NAMES[itemMon];
	if (itemYear != now.getFullYear()) {
		dateStr += " "+itemYear;
	}

	if (diff <= 24 || yester == 1) {
		return 'Yesterday';	
	}	
	
	if (nowDate == 1 && itemDate == 31 && itemYear==nowYear && nowMon-itemMon == 1) {
		return 'Yesterday';	
	}

	var shm = (itemMon == 3 || itemMon == 5 || itemMon == 8 || itemMon == 10);
	if (nowDate == 1 && shm && itemDate == 30 && itemYear==nowYear && nowMon-itemMon == 1) {
		return 'Yesterday';	
	}

	var feb = (itemMon == 1);
	if (nowDate == 1 && feb && itemDate == 28 && itemYear==nowYear && nowMon-itemMon == 1) {
		return 'Yesterday';	
	}
	
	return dateStr;	
}


