﻿/**
 * Some useful utility functions:
 *	getAllImg()
 *	isImgLoaded(img)
 *	isImgLink(url)
 *	changeZIndex(element)
 *  trim(str)
 *	readEffect(element, effect, propagation)
 */
Utility = Object.extend({
	
	trim: function(str){
		if(str){
			var start = -1, end = str.length;
			while(str.charCodeAt(--end) < 33 );
			while(str.charCodeAt(++start) < 33 );
			return str.slice(start, end + 1);
		}
		else{
			return "";
		}
	},
	
	
	getBGImg: function(element){
		var url = $(element).getStyle('background-image');
		if(url.empty()){
			return null;
		}
		else{
			url = url.indexOf('\"') == -1 ? url.substring(4, url.length-1) : url.substring(5, url.length-2);
			return this.isImgLink(url) ? url : null;
		}
	},
	

	/**
	 * Get all images (including background in style) in the html page that call this function. (checked)
	 */
	getAllImg:function(element){
		var allImg = [];
		Try.these(
			(function(){
				var descendants = element == null ? $$('body')[0].descendants() : $(element).descendants();
				for(var i=0; i<descendants.length; i++){
					if(descendants[i].match("img")){
						allImg.push(descendants[i]);
					}
					else{
						var bg = descendants[i].getStyle('background-image');
						if(bg && bg != "none" && bg != "initial"){
							var formatedBG = bg.indexOf('\"') == -1 ? bg.substring(4, bg.length-1) : bg.substring(5, bg.length-2);
//							alert(descendants[i] + "\n" + descendants[i].identify() + "\n" + "--" + bg + "--\n--" + formatedBG + "--");
							if(this.isImgLink(formatedBG)){
								var img = new Image();
								img.src = formatedBG;
								allImg.push(img);
							}
						}
					}
				}
			}).bind(this)
		);
		return allImg;
	},
	
	
	/**
	 * check if the img link is loaded. (checked)
	 */
	isImgLoaded:function(img){
		if(img && img.src && !img.src.empty()){
			if(!img.complete){
				return false;
			}
			else if(img.naturalWidth && img.naturalWidth == 0){
				return false;
			}
			else if(img.width && img.width == 0){
				return false;
			}
		}
		return true;
	},
	
	
	/**
	 * Check if the url is an image link (ONLY suitable for .jpg, .jpeg, .gif and .png).
	 */
	isImgLink: function(url){
		if(url && !url.empty()){
			var endPos = url.indexOf('?');
			if(endPos < 0){
				endPos = url.length - 4;
			}
			else{
				endPos -= 4;
			}
			if(endPos >= 1 && (url.indexOf(".jpg") == endPos || url.indexOf(".jpeg") == (endPos-1) || url.indexOf(".gif") == endPos || url.indexOf(".png") == endPos)){
				return true;
			}
		}
		return false;
	},
	
	isFlashLink: function(url){
		if(url && !url.empty()){
			var endPos = url.indexOf('?');
			if(endPos < 0){
				endPos = url.length - 4;
			}
			else{
				endPos -= 4;
			}
			if(endPos >= 1 && (url.indexOf(".swf") == endPos || url.indexOf(".fla") == endPos)){
				return true;
			}
		}
		return false;
	},
	
	
	/**
	 * Check if all images in a page is loaded
	 */
	 isAllImgLoaded: function(element){
		var img = this.getAllImg(element);
		for(var i=0; i<img.length; i++){
			if(img[i]){
				if(!this.isImgLoaded(img[i])){
					return false;
				}
			}
		}
		return true;
	 },
	
	
	/**
	 * change the z-index of an element. (checked)
	 */
	changeZIndex:function(layerName, zIndex){
		$(layerName).setStyle({'zIndex': zIndex});
	},


	//-------------------------------------------------------------------------------------------------------------------
	setOpacityLayer: [],
	
	setOpacity: function(layerName, param){
		this.stopSetOpacity(layerName);
		var from = $(layerName).getStyle('display') == 'none' ? 0.0 : $(layerName).getOpacity();
		var to = param.to == "undefined" ? from : param.to;

		if(from != to){
			var duration = param.duration ? param.duration : 1;
		
			// appear
			if(from < to){
				if(param.scaleDuration && param.from){
					duration *= ((to - from) / to);
				}
				
				this.setOpacityLayer[layerName] = new Effect.Appear($(layerName), {
					to: to, 
					duration: duration, 
					afterFinishInternal: (function(){
						this.setOpacityLayer[layerName] = null;
					}).bind(this)
				});
			}
			
			// fade
			else{
				if(param.scaleDuration && param.from){
					duration *= ((from - to) / (1 - to)) * from;
				}
				
				this.setOpacityLayer[layerName] = new Effect.Opacity($(layerName), {
					to: to, 
					duration: duration,
					afterFinishInternal: (function(effect){
						if(to == 0 && param.hide){
							effect.element.hide();
						}
						this.setOpacityLayer[layerName] = null;
					}).bind(this)
				});
			}
		}
	},

	/**
	 * @return "running", "finished"
	 */
	setOpacityState: function(layerName){
		if(this.setOpacityLayer[layerName]){
			return this.setOpacityLayer[layerName].state;
		}
		return "finished";
	},
	
	
	stopSetOpacity: function(layerName){
		if(this.setOpacityLayer[layerName]){
			this.setOpacityLayer[layerName].cancel();
			this.setOpacityLayer[layerName] = null;
		}
	},
	
	//-------------------------------------------------------------------------------------------------------------------
	
	setStyleLayer: [],
	
	setStyle: function(layerName, param){
		this.stopSetStyle(layerName);
		this.setStyleLayer[layerName] = new Effect.Morph($(layerName), {
			style: param.style, 
			duration: param.duration || 1,
			afterFinishInternal: (function(){
				this.layerEffect[layerName] = null;
			}).bind(this)
		});
	},
	
	stopSetStyle: function(layerName){
		if(this.setStyleLayer[layerName]){
			this.setStyleLayer[layerName].cancel();
			this.setStyleLayer[layerName] = null;
		}
	},
	
	/**
	 * @return "running", "finished", or null
	 */
	setStyleState: function(layerName){
		if(this.setStyleLayer[layerName]){
			return this.setStyleLayer[layerName].state;
		}
		return "finished";
	},
	
	//-------------------------------------------------------------------------------------------------------------------
	
	setSizeLayer: [],
	
	setSize: function(layerName, param){
		this.stopSetSize(layerName);
		if(param.width != $(layerName).getWidth() || param.height != $(layerName).getHeight()){
			this.setSizeLayer[layerName] = new Effect.Morph($(layerName), {
				style: 'width: ' + param.width + '; height: ' + param.height, 
				duration: param.duration || 1,
				afterFinishInternal: (function(){
					this.setSizeLayer[layerName] = null;
				}).bind(this)
			});
		}
	},
	
	
	stopSetSize: function(layerName){
		if(this.setSizeLayer[layerName]){
			this.setSizeLayer[layerName].cancel();
			this.setSizeLayer[layerName] = null;
		}
	},
	
	
	/**
	 * @return "running", "finished"
	 */
	setSizeState: function(layerName){
		if(this.setSizeLayer[layerName]){
			return this.setSizeLayer[layerName].state;
		}
		return "finished";
	},
	
	
	/**
	 * Get the minimum size to display the content of a particular element based on the element's width and height setting.
	 * If no element is in there, width=0 and height=0 is returned.
	 */
	getContentDimensions: function(element){
		var offsets = $(element).cumulativeOffset();
		var rDimensions = [];
		rDimensions.width = 0;
		rDimensions.height = 0;
		
		var child = $(element).descendants();
		for(var i=0; i<child.length; i++){
			if(child[i].visible() && !child[i].match('meta') && !child[i].match('link') && !child[i].match('title') && !child[i].match('script') && !child[i].match('head')){
				var cDimensions = child[i].getDimensions();
				var cOffsets = child[i].cumulativeOffset();
			
				cDimensions.width += Math.abs(cOffsets.left - offsets.left);
				cDimensions.height += Math.abs(cOffsets.top - offsets.top);
			
				if(cDimensions.width > rDimensions.width){
					rDimensions.width = cDimensions.width;
				}
				if(cDimensions.height > rDimensions.height){
					rDimensions.height = cDimensions.height;
				}
			}
		}
		return rDimensions;
	},
	

	/**
	 * @return dimension - dimension.width and dimension.height
	 */
    getDocumentDimensions:function(){
    	var dimensions = [];
    	dimensions.width = this.getDocumentWidth();
    	dimensions.height = this.getDocumentHeight();
		return dimensions;
	},
	
    getDocumentHeight: function() { // missing from prototype?
        var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
        return Math.max(scrollHeight, document.viewport.getHeight());
    },

    getDocumentWidth: function() { // missing from prototype?
        var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
        return Math.max(scrollWidth, document.viewport.getWidth());
    },

	/**
	 * Read the effect of a layer.  
	 *
	 * @param element The target element.
	 * @param effect The name of the effect.
	 * @param propagation Whether to check its' parent layers to see whether it has the target effect.
	 *                    By default, it is true.
	 *
	 * @return param - an array
	 */
	 getParam: function(element, keyword, propagation){
		if(propagation==null || propagation==true){
			var param = this.getParam(element, keyword, false);
			if(param){
				return param;
			}
			else{
				var parent = element.ancestors();
				for(var i=0; i<parent.length; i++){
					param = this.getParam(parent[i], keyword, false);
					if(param){
						return param;
					}
				}
				return null;
			}
	 	}
	 	else{
			var param = element.readAttribute(keyword);
			if(param == ""){
				param = [];
				param.trigger = element;
				return param;
			}
			else if(param == null){
				return null;
			}
			else{
				return Try.these(
					(function(){
						param = param.evalJSON();
						param.trigger = element;
						return param;
					}).bind(this)
				) || null;
			}
	 	}
	},
	 
	 
	//---------------------------------------------------------------------------
	// browser detection
	//
	dataBrowser: [{string: navigator.userAgent, subString: "Chrome", identity: "Chrome"},
		{string: navigator.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb"},
		{string: navigator.vendor, subString: "Apple", identity: "Safari", versionSearch: "Version"},
		{prop: window.opera, identity: "Opera"},
		{string: navigator.vendor, subString: "iCab", identity: "iCab"},
		{string: navigator.vendor, subString: "KDE", identity: "Konqueror"},
		{string: navigator.userAgent, subString: "Firefox", identity: "Firefox"},
		{string: navigator.vendor, subString: "Camino", identity: "Camino"},
		{string: navigator.userAgent, subString: "Netscape", identity: "Netscape"},
		{string: navigator.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE"},
		{string: navigator.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv"},
		{string: navigator.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla"}
	],
	
	dataOS : [{string: navigator.platform, subString: "Win", identity: "Windows"},
		{string: navigator.platform, subString: "Mac", identity: "Mac"},
		{string: navigator.platform, subString: "Linux", identity: "Linux"}
	],
	
	getBrowser: function(){
		return this.searchString(this.dataBrowser) || "An unknown browser";
	},
	
	getBrowserVersion: function(){
		return this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version";
	},
	
	getOS: function(){
		return this.searchString(this.dataOS) || "an unknown OS";
	},
	 
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	}
	
	//---------------------------------------------------------------------------
	 

},window.Utility || {});



String.prototype.tokenize = tokenize;
function tokenize(){
     var input             = "";
     var separator         = " ";
     var trim              = "";
     var ignoreEmptyTokens = true;

     try {
       String(this.toLowerCase());
     }
     catch(e) {
       window.alert("String.tokenize wrong usage");
       return;
     }

     if(typeof(this) != "undefined")
       {
          input = String(this);
       }

     if(typeof(tokenize.arguments[0]) != "undefined")
       {
          separator = String(tokenize.arguments[0]);
       }

     if(typeof(tokenize.arguments[1]) != "undefined")
       {
          trim = String(tokenize.arguments[1]);
       }

     if(typeof(tokenize.arguments[2]) != "undefined")
       {
          if(!tokenize.arguments[2])
            ignoreEmptyTokens = false;
       }

     var array = input.split(separator);

     if(trim)
       for(var i=0; i<array.length; i++)
         {
           while(array[i].slice(0, trim.length) == trim)
             array[i] = array[i].slice(trim.length);
           while(array[i].slice(array[i].length-trim.length) == trim)
             array[i] = array[i].slice(0, array[i].length-trim.length);
         }

     var token = new Array();
     if(ignoreEmptyTokens)
       {
          for(var i=0; i<array.length; i++)
            if(array[i] != "")
              token.push(array[i]);
       }
     else
       {
          token = array;
       }

     return token;
}
