// ----------------------------------------
//
// Slide Async out-of-band RPC code
// Written by Donovan Preston
// Copyright 2005, Slide Inc.
//
// ----------------------------------------


var disconnectListeners = []


var createRequest = function() {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	} else {
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
}


// this code does the simplest thing that could possibly work right now;
// it doesn't try to be reusable in any way. If more code is added and
// reuse is desired, refactoring should occur.


// TODO use mochikit.async.deferred instead of whenDone callback

var remoteAction = function(method, action, params, whenDone, sendRequest) {
	if (action.charAt(0) == '/') {
		var theURL = action
	} else {
		var theURL = '/'+action
	}
	var postdata = '';
	if (params) {
		postdata = queryString(params);
		if (postdata && (method == "GET")) {
			theURL = theURL + "?" + postdata;
			postdata = "";
		}
	}

	var req = createRequest();
	req.onreadystatechange = function() {
		if (req.readyState == 4) {
			if (whenDone) whenDone(req.responseText);
		}
	}
	sendRequest(req, theURL, postdata);
}

var getViewName = function() {
	return window.location;
};

var asyncCommand = function(commandType) {
	return function(action, params, whenDone) {
		params.referrer = getViewName();
		remoteAction(commandType, action, params, whenDone, 
			function(req, theURL, theData) {
				req.open(commandType, theURL, true);
				req.setRequestHeader('HTTP-Command-Equiv', commandType);
				req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
				req.send(theData);
			})
	}
}

var asyncAction = asyncCommand("POST");
var asyncPut = asyncCommand("PUT");

var asyncView = function(action, params, whenDone) {
	remoteAction("GET", action, params, whenDone, 
		function(req, theURL, theData) {
			if (theData) {
				var sep = ( theData.indexOf("?") > 0) ? "&" : "?";
				req.open("GET", theURL + sep + theData, true);
			} else {
				req.open("GET", theURL, true);
			}
			req.send(null);
		})
}

var asyncJson = function(method, action, params, whenDone) {
	remoteAction(method, action, params, whenDone, 
		function(req, theURL, theData) {
			if (theURL.charAt(0) != '/') {
				theURL = '/' + theURL;
			}
			theURL = '/accept/application/x-json' + theURL;
			req.open(method, theURL, true);
			req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			req.setRequestHeader('x-http-command-equiv', method);
			req.send(theData);
		});
}

function $(theId) {
	return document.getElementById(theId);
}

function isPass(theResponse) {
	return theResponse.substring(0,4) != 'FAIL';
}

function isUnauthenticated(theResponse) {
	return theResponse == "FAIL: Unauthenticated";
}


/* From Skins */
var fill = function(node, fillers) {
	if (node) {
		if (node.getAttribute) {
			var slot = getNodeAttribute(node, 'x:slot');
			if (slot) {
				var filler = fillers[slot];
				if (filler) {
					replaceChildNodes(node, filler);
				}
			}
			var visible = getNodeAttribute(node, 'x:visible');
			if (visible && (false == fillers[visible])) {
				// alert(visible);
				node.parentNode.removeChild(node);
				return;
			}

			var attrs = getNodeAttribute(node, 'x:attr');
			while (attrs) {
				var colonPos = attrs.indexOf(':');
				var key = attrs.substring(0, colonPos);
				key = key.replace("_", ":");
				var commaPos = attrs.indexOf(',');
				if (commaPos != -1) {
					var value = attrs.substring(colonPos+1, commaPos);
					attrs = attrs.substring(commaPos+1);
				} else {
					var value = attrs.substring(colonPos+1);
					attrs = '';
				}
				if (fillers[value]) {
					node.setAttribute(key, fillers[value]);
				}
			}
			var attrs = getNodeAttribute(node, 'x:text');
			if (attrs) {
				var text = fillers[attrs];
				if (undefined != text) {
					replaceChildNodes(node, text);
				}
			}
		}
		for (var i = 0; i < node.childNodes.length; i++) {
			fill(node.childNodes[i], fillers);
		}
	}
}

var AllObservers = {}
var AllModelData = {}
var obkeyIndex = 0;
var observe = function(key, observer, nostartup) {
	if (! AllObservers[key]) {
		AllObservers[key] = {};
	}
	var obkey = String(obkeyIndex++) + ":" + key;
	if (observer) {
		AllObservers[key][obkey] = observer;
	}
	if (AllModelData[key]) {
		if (observer) {
			observer(AllModelData[key]);
		}
	} else if (!nostartup) {
		execute(key);
	}
	return obkey;
}

var unobserve = function(obkey) {
	if (obkey) {
		var colonPos = obkey.indexOf(':');
		var key = obkey.substring(colonPos+1);
		delete AllObservers[key][obkey];
	}
}

var reobserve = function(key, observer) {
	delete AllModelData[key];
	observe(key, observer);
}

var _patterns = null;

var walk = function(node, prefix) {
	if (node.nodeType == 1) {
		try {
			var pattern = getNodeAttribute(node, 'x:pattern');
			if (pattern) {
				prefix += (prefix ? ':' : '') + pattern;
				_patterns[pattern] = node;
			}
			if (getNodeAttribute(node, 'x:dummy')) {
				node.parentNode.removeChild(node);
			}
		} catch (e) { }
	}
	for (var i = 0; i < node.childNodes.length; i++) {
		walk(node.childNodes[i], prefix);
	}
}
var getPatternMap = function() {
	if (_patterns == null) {
		_patterns = {};
		walk(document.documentElement, '');
	}
	return _patterns;
}

var getPattern = function(patternName) {
    var patterns = getPatternMap();
	return patterns[patternName].cloneNode(true);
}

var pattern = function(patternName, fillers) {
	var pat = getPattern(patternName);
	if (fillers) {
		fill(pat, fillers);
	}
	return pat;
}


var tkeys = function(d) {
   var r = [];
   for (var k in d) {
	   if (k[d]) {
		   r.push(k);
	   }
   }
   return r;
}

var _pendingExecute = {}
var execute = function(key) {
	if ( ! _pendingExecute[key]) {
		_pendingExecute[key] = true;
		asyncJson("GET", key, {}, function(results) {
			delete _pendingExecute[key];
			if (results) {
				results = evalJSON(results);
			}
			if (results.length) {
				for (var i=0; i < results.length; i++) {
					var row = results[i];
					if (row.url && (row.url != key) ) {
						updateModel(row.url, row);
					}
				}
			}
			updateModel(key, results);
		});
	} 
}

var updateModel = function(key, results) {
	AllModelData[key] = results;
	var key_observers = AllObservers[key];
	for (var i in key_observers) {
		var observer = key_observers[i];
		if (observer) {
			observer(results);
		}
	}
};


var postURL = function(command, params, observer) {
	asyncJson("POST", command, params, observer);
}

var logWebEvent = function(event_id, foreign_id) {
	// postURL("/event", { event_id : event_id ,foreign_id : foreign_id }, null);
};


