/*
 * jQuery.Google v.0.2
 *  Author: Jiang Yio
 *          <http://inportb.com/>
 *    Date: May 24, 2009
 * License: Creative Commons Attribution-Share Alike 3.0 License
 *          <http://creativecommons.org/licenses/by-sa/3.0/>
 */

(function($) {
	function clone(obj) {
		if(obj == undefined) return;
		arguments.callee.prototype = obj;
		return new arguments.callee();
	}
	function chain(base,local) {
		var chain = clone(base);
		for(key in local) chain[key] = local[key];
		return chain;
	}
	$.google = function(params) {
		var params = chain($.google.defaults,params);
		var cb = params.callback;
		var eb = params.errback;
		var url = 'http://ajax.googleapis.com/ajax/services/search/'+params.searcher;
		params.callback = params.errback = params.searcher = undefined;
		var data = {};
		for(key in params) if(params[key] != undefined) data[key] = params[key];
		$.ajax({
			dataType:	'jsonp',
			data:		data,
			jsonp:		'callback',
			url:		url,
			success:	function(json) {
				if(!json.responseData) return cb(null);
				for(var i = 0; i < json.responseData.results.length; i++) {
					var r = json.responseData.results[i];
					json.responseData.results[i] = {
						title:		r.titleNoFormatting,
						titleHtml:	r.title,
						host:		r.visibleUrl,
						url:		r.unescapedUrl,
						cache:		r.cacheUrl,
						content:	r.content
					};
				}
				cb.call(cb,json.responseData?{total:1*json.responseData.cursor.estimatedResultCount,results:json.responseData.results}:null);
			},
			error:		function() {
				if(eb) eb.apply(eb,arguments);
			}
		});
	};
	$.google.buffer = function(params,size,pruneto) {
		var rsz = 8;
		var total = {start:0,count:0};
		var blocks = [];
		var cache = {};
		if(isNaN(size)) size = 32;
		if(isNaN(pruneto)) pruneto = size;
		function refresh(start) {
			if(blocks[blocks.length-1] == start) return;
			for(var i = blocks.length-1; i >= 0; i--) if(blocks[i] == start) blocks.splice(i,1);
			blocks.push(start);
		}
		function get(i,cb) {
			var start = Math.floor(i/rsz)*rsz;
			if(i in cache) {
				refresh(start);
				cb(cache[i]);
			} else block(start,function() { cb(cache[i]); });
		}
		function block(s,cb) {
			if(s in cache) {
				refresh(s);
				var end = s+rsz-1;
				var results = [];
				for(var i = s; i <= end; i++) results.push(cache[i]);
				cb(results);
			} else $.google(chain(params,{start:s,rsz:'large',callback:function(resp) {
				if(s >= total.start) total.count = resp.total;
				for(var i = 0; i < resp.results.length; i++) cache[i+s] = resp.results[i];
				refresh(s);
				cb(resp.results);
				if(blocks.length > size) while(blocks.length > pruneto) for(var start = blocks.shift(), i = start+rsz-1; i >= start; i--) delete cache[i];
			}}));
		}
		function slice(i,len,cb) {
			var data = [];
			if(len <= 0) return data;
			var units = [Math.floor(i/rsz)*rsz];
			while((len -= rsz) > 0) units.push(units[units.length-1]+rsz);
			block(units.shift(),function(results) {
				data = data.concat(results);
				if(units.length > 0) block(units.shift(),arguments.callee);
				else cb(data.slice(i%rsz,i%rsz+data.length+len));
			});
		}
		this.get = get;
		this.slice = slice;
		this.total = function() { return total.count; };
	};
	$.google.defaults = {
		callback:	null,
		searcher:	'web',
		v:			'1.0',
		start:		0,
		cx:			'007126889806553884520:lvciw9yh4ig'
	};
})(jQuery);

