//elements who don't have a display (or their ancestors don't) return null
//when getting their computed style. this is a workaround.

function computedStyleWorkAround(el) {
	var ar = [];
	
	var bod = document.getElementsByTagName("body")[0];
	
	if (el != bod && el.nodeType == 1) {
		do {
			if (document.defaultView.getComputedStyle(el, '') == null) {
				el.style.display = "block";
				ar.push(el);
			}
			el = el.parentNode;
		} while (el != bod);
	}
	
	return ar;
}

function getTheComputedStyle(el) {
	//so you can pass an id of an element, or the element...
	el = (el == new String(el)) ? document.getElementById(el) : el;

	var c_s = document.defaultView.getComputedStyle(el, '');
	if (c_s == null) {
		var els = computedStyleWorkAround(el);
		c_s = document.defaultView.getComputedStyle(el, '');
		//alert(c_s.getPropertyValue("height"));
		//now put them back
		for (var j=0; j < els.length; j++) {
			els[j].style.display = "";
		}
	}
	return c_s;
}

function getComputedStyleValues(el) {
	//so you can pass an id of an element, or the element...
	el = (el == new String(el)) ? document.getElementById(el) : el;
	
	var ar = [];

	var c_s = document.defaultView.getComputedStyle(el, '');
	
	if (c_s != null) {
		for (var i=1; i<arguments.length; i++) {
			var val;
			switch(arguments[i]) {
				case "offsetTop":
					val = el.offsetTop;
					break;
				case "offsetLeft":
					val = el.offsetLeft;
					break;
				case "offsetHeight":
					val = el.offsetHeight;
					break;
				case "offsetWidth":
					val = el.offsetWidth;
					break;
				case "scrollHeight":
					val = el.scrollHeight;
					break;
				case "scrollWidth":
					val = el.scrollWidth;
					break;
				default:
					val = c_s.getPropertyValue(arguments[i]);
			}
			
			ar.push(val);
		}
	} else {
		var els = computedStyleWorkAround(el);
		c_s = document.defaultView.getComputedStyle(el, '');
		
		for (var i=1; i<arguments.length; i++) {
			var val;
			switch(arguments[i]) {
				case "offsetTop":
					val = el.offsetTop;
					break;
				case "offsetLeft":
					val = el.offsetLeft;
					break;
				case "offsetHeight":
					val = el.offsetHeight;
					break;
				case "offsetWidth":
					val = el.offsetWidth;
					break;
				case "scrollHeight":
					val = el.scrollHeight;
					break;
				case "scrollWidth":
					val = el.scrollWidth;
					break;
				default:
					val = c_s.getPropertyValue(arguments[i]);
			}
			
			ar.push(val);
			//ar.push(c_s.getPropertyValue(arguments[i]));
		}
		
		//now put them back
		for (var j=0; j < els.length; j++) {
			els[j].style.display = "";
		}
	}
	return ar;
}



function DraggableElement(what, id, parent, startFunction, controller, endFunction) {
	this.element = (what == new String(what)) ? document.getElementById(what) : what;

	this.instance = "drag_" + id;
	eval(this.instance + " = this"); //<-- mildly minging, but it lets us set up the objects without worry about global vars
	
	this.is_moving = false;
	
	this.parent = parent;
	
	this.startFunction = startFunction;
	this.controller = controller;
	this.endFunction = endFunction;
	
	this.canmove = false;
	this.init_y = 0;
	this.init_x = 0;
	this.init_top = 0;
	this.init_left = 0;
	this.current_tile = 0; //the index of the tile we're dragging

	this.mousemove = function(e) {
		if (this.canmove) {
			this.top = e.clientY - this.init_y;
			this.left = e.clientX - this.init_x;
			this.is_moving = true;
		}			
					
		//so, controller is actually the controlling function. This
		//means we can use this 'class' for multiple things,
		//such as scrollbars or sliders etc.
		
		if (this.controller != null) this.controller(e);
	}
	
	this.mousedown = function(e) {
		this.init_top = this.element.offsetTop + this.element.parentNode.offsetTop + this.element.parentNode.parentNode.offsetTop; //getOffsetTop(this.element); 
		this.init_left = this.element.offsetLeft + this.element.parentNode.offsetLeft;
		
		this.init_y = (e.clientY - this.init_top);
		this.init_x = (e.clientX - this.init_left);
		this.canmove = true;

	//the following seems rather 'hacky' doesn't it?
		cur_drag_obj = this;
		document.body.addEventListener("mousemove", dragging, false);
		document.body.addEventListener("mouseup", finishDragging, false);

		if (this.startFunction != null) this.startFunction(e);
		//document.removeEventListener("mousemove", handleDockMagnify, false);
		e.preventDefault();
	}
	
	this.mouseup = function(e) {
		this.canmove = false;
		this.is_moving = false;
		
		if (this.endFunction != null) this.endFunction();

		//and remove the event listeners:		
		document.body.removeEventListener("mousemove", dragging, false);
		document.body.removeEventListener("mouseup", finishDragging, false);
	}
	
	this.element.setAttribute("onmousedown", this.instance + ".mousedown(event)");
	//this.element.setAttribute("onclick", this.instance + ".click(event)");
}

/*
	note that I had to actually make these to as proper functions for the event
	listeners, otherwise they weren't being removed (when using something like
	function(e){cur_drag_obj.mousemove(e);} instead).
 */
function dragging(e) {
	cur_drag_obj.mousemove(e);
}

function finishDragging(e) {
	cur_drag_obj.mouseup(e);
}

//mouseover stuff for the 'i' button:

var isShown = false, isAnimating = false;

function mouseOver(e) {
	//e.cancelBubble = true;

	if (!isShown && !isAnimating) {
		fade('flipper', 0, 1, function(){isAnimating=false;isShown = true;});
		isAnimating = true;
	}
	
	if (e.target.parentNode.id == "flip" || e.target.id == "flip") {
		document.getElementById("flip_back").style.visibility = "visible";
	}
}

function mouseOut(e) {
	
	//e.cancelBubble = true;
	
	if (e.target.id != "flipper" && e.target.parentNode.id != "flip") {
		document.getElementById("flip_back").style.visibility = "hidden";
	}
	
//had a lot fo trouble with event capturing, so going this route for now...
//we'll see what happens with actual Tiger...
	if (e.clientY < 0 || e.clientX < 0 || e.clientY > chrome.widget_chrome.offsetHeight || e.clientX > (chrome.widget_chrome.offsetWidth+30)) {
		if (!isAnimating) {
			fade('flipper', 1, 0, function(){isAnimating=false;isShown = false;});
			isAnimating = true;
		}
	}
}

function infoMouseUp(e) {
	fade('flipper', 0, 0, function(){isAnimating=false;isShown = false;});
	document.getElementById("flip_back").style.visibility = "hidden";
	toggleSettings();
}

function fade(el, from, to, callBack) {
    if (el == new String(el)) el = document.getElementById(el);
    //so we can pass a string for the id or an element
      
    var dif = Math.abs(to - from);
    
    var pi = Math.PI;
    var theta = 0;
    
    //if (to < from && el.style.opacity > 0) return;
    
	var inter = setInterval(
		function() {
			if (theta < 90) {
				theta += 10;
				if (to > from) 
					var step = Math.sin((theta*pi)/180);
				else 
					var step = Math.cos((theta*pi)/180);
				var opac = dif*step;
				el.style.opacity = Math.max(0.01, opac); //fixing safari glitch
			} else {
				el.style.opacity = to;
				clearInterval(inter);
				if (callBack != null) callBack();
			}
		}, 100);
}


var folder_tree = [];
folder_tree[0] = "";

function cacheImages(folder) {
	if (window.widget) {
		var files = widget.system("/bin/ls -1p " + folder, null).outputString;
		var imgs = [];
		if (folder_tree.length == 1) folder_tree[0] = folder;
		
		//alert(files);
		
		var file_list = files.split("\n");
		for (var j=0; j < file_list.length; j++) {
			if (file_list[j].charAt(file_list[j].length-1) == "/") {
				folder_tree.push(folder_tree[0] + file_list[j]);
				//alert('got a folder: ' + folder_tree[0] + file_list[j]);
			} else {
				if (isImage(file_list[j])) {
				//we want to put it back into encoded form, not unixy form...
					var file = folder_tree[0] + file_list[j]; 
					while (file.indexOf("\\ ") != -1) {
						file = file.replace("\\ "," ");
					}
					file = encodeURI(file);
					//alert('got an image: ' + file);
					imgs[imgs.length] = file;
				}
			}
		}
		
		//alert('about to cache');
		
		if (imgs.length == 0) {
			folder_tree.splice(0,1);
			cacheImages(folder_tree[0]);
		} else {
			var i=0;
			
			//alert('caching image: ' + imgs[i]);
			
			var img = document.createElement("img"); //new Image();    
			img.src = imgs[i];
			img.onload = 
				function() {
					//alert('cached image: ' + imgs[i]);
					if (i < imgs.length-1) {
						i++;
						img.src = imgs[i];
						//alert('caching image: ' + imgs[i]);
					} else {
						folder_tree.splice(0,1);
			
						if (folder_tree.length > 0) {
							//alert('going into folder: ' + folder_tree[0]);
							cacheImages(folder_tree[0]);
						}
					}
				}
		}
	}
}

function isImage(img) {
    var isAnImage = false;
    var extension = img.substring(img.lastIndexOf(".")+1, img.length).toLowerCase();
    
    switch (extension) {
        case "jpg":
        case "jpeg":
        case "gif":
        case "tif":
        case "png":
            isAnImage = true;
            break;
    }
    
    return isAnImage;
}

function Animation(id, what, strip_width, loops, interval) {
	this.inter = null;
	
	this.instance = id; //i suppose this could possibly be done using random numbers instead, but...
	eval(this.instance + " = this"); //giving us a reference to the object - I don't like eval in general, but this is an easy way of getting round this problem
	
	this.element = document.getElementById(what);
	this.left = 0;
	this.cur_loop = 0;
	this.dx = this.element.offsetWidth + 10;
	this.strip_width = strip_width;
	this.loops = loops;
	this.interval = interval;
	this.isPlaying = false;
	
	this.end_point = 0;
	this.init_left;
	
	this.dir = "forward";
	this.callBack = null;
		
	this.play = 
		function(dir, callBack) {
			if (!this.isPlaying) {
				this.isPlaying = true;
				this.dir = dir;
				this.callBack = callBack;
				
				if (this.dir == "back") {
					this.end_point =  this.strip_width * -1;
					this.left = 0;
				} else {
					this.end_point = 0;
					this.left = this.strip_width;
				}
				
				this.init_left = this.left;
				
				this.inter = setInterval(this.instance + ".roll()", this.interval);
			}
		}
	
	this.stop = 
		function () {
			clearInterval(this.inter);
			this.isPlaying = false;
		}
		
	this.roll =
		function() {
			this.left -= this.dx;
			
			if (this.left > this.end_point) {
				var pos = (this.dir == "back") ? this.left * -1 : this.left;
				this.element.style.backgroundPosition = pos + "px 0";
			} else {
				if (this.loops > 0 && ++this.cur_loop >= this.loops) {
					clearInterval(this.inter);
					this.cur_loop = 0;
					this.isPlaying = false;
					if (this.callBack != null) {
						this.callBack();
						this.callBack = null;
					}
				} else {
					this.element.style.backgroundPosition = "0 0";
					this.left = this.init_left;
				}
			}
		}
}

function getUnixFilePath(file) {
    if (file.indexOf("file://localhost") != -1) file = file.substring(new String("file://localhost").length, file.length);
    //seems we have to replace the spaces before the decodeURI....
    while (file.indexOf("%20") != -1) {
        file = file.replace("%20","\\ ");
    }
    file = decodeURI(file);
    return file;
}

function getFileName(file) {
    var tmp = file.split("/");
    
    tmp = tmp[tmp.length-1];
    
    while (tmp.indexOf("\ ") != -1) {
        tmp = tmp.replace("\ "," ");
    }

    return tmp;
}

function folderExists(path) {
	var folders = path.split("/");
	
	var folder = folders[folders.length-2];
	parent_folder = path.substring(0, path.indexOf("/" + folder));
	
	var list = widget.system("/bin/ls " + parent_folder, null).outputString;
	
	var regex = new RegExp("^" + folder + "$", "img");
	
	if (regex.exec(list)) return true;

	return false;
}

function expandTilde(path) {
//find a more full proof method for this

	if (path.charAt(0) == "~") {
		path = path.substring(1, path.length);
		
		var username = widget.system("/usr/bin/whoami", null).outputString.split("\n")[0]; //since we get a newline character too
		
		var full_path = "/Users/" + username + path;	
	} else {
		return path;
	}
	
	return full_path;
}
