define(["dojo", "dojox", "dojox/data/JsonRestStore"], function(dojo, dojox) {

// Contains code donated by Travis Tilley under CLA
return dojo.declare("dojox.data.RailsStore", dojox.data.JsonRestStore, {
	constructor: function(){
		// summary:
		//		RailsStore is a data store for interacting with RESTful Rails controllers
	},
	preamble: function(options){
		if(typeof options.target == 'string' && !options.service){
			var target = options.target.replace(/\/$/g, '');

			// Special getRequest handler for handling content type negotiation via
			// the Rails format extension, as well as properly setting the ID param
			// in the URL.
			var getRequest = function(id, args){
				args = args || {};
				var url = target;
				var query;
				var ident;

				if(dojo.isObject(id)){
					ident = '';
					query = '?' + dojo.objectToQuery(id);
				}else if(args.queryStr && args.queryStr.indexOf('?') != -1){
					ident = args.queryStr.replace(/\?.*/, '');
					query = args.queryStr.replace(/[^?]*\?/g, '?');
				}else if(dojo.isString(args.query) && args.query.indexOf('?') != -1){
					ident = args.query.replace(/\?.*/, '');
					query = args.query.replace(/[^?]*\?/g, '?');
				}else{
					ident = id ? id.toString() : '';
					query = '';
				}

				if(ident.indexOf('=') != -1){
					query = ident;
					ident = '';
				}

				if(ident){
					url = url + '/' + ident + '.json' + query;
				}else{
					url = url + '.json' + query;
				}

				var isSync = dojox.rpc._sync;
				dojox.rpc._sync = false;

				return {
					url : url,
					handleAs : 'json',
					contentType : 'application/json',
					sync : isSync,
					headers : {
						Accept : 'application/json,application/javascript',
						Range : args && (args.start >= 0 || args.count >= 0)
								? "items="
										+ (args.start || '0')
										+ '-'
										+ ((args.count && (args.count
												+ (args.start || 0) - 1)) || '')
								: undefined
					}
				};
			};

			options.service = dojox.rpc.Rest(this.target, true, null,
					getRequest);
		}
	},
	fetch: function(args){
		args = args || {};
		function addToQueryStr(obj){
			function buildInitialQueryString(){
				if(args.queryStr == null){
					args.queryStr = '';
				}
				if(dojo.isObject(args.query)){
					args.queryStr = '?' + dojo.objectToQuery(args.query);
				}else if(dojo.isString(args.query)){
					args.queryStr = args.query;
				}
			}
			function separator(){
				if(args.queryStr.indexOf('?') == -1){
					return '?';
				}else{
					return '&';
				}
			}
			if(args.queryStr == null){
				buildInitialQueryString();
			}
			args.queryStr = args.queryStr + separator() + dojo.objectToQuery(obj);
		}
		if(args.start || args.count){
			// in addition to the content range headers, also provide query parameters for use
			// with the will_paginate plugin if so desired.
			if((args.start || 0) % args.count){
				throw new Error("The start parameter must be a multiple of the count parameter");
			}
			addToQueryStr({
				page: ((args.start || 0) / args.count) + 1,
				per_page: args.count
			});
		}
		if(args.sort){
			// make the sort into query parameters
			var queryObj = {
				sortBy : [],
				sortDir : []
			};

			dojo.forEach(args.sort, function(item){
				queryObj.sortBy.push(item.attribute);
				queryObj.sortDir.push(!!item.descending ? 'DESC' : 'ASC');
			});

			addToQueryStr(queryObj);
			delete args.sort;
		}

		return this.inherited(arguments);
	},
	_processResults: function(results, deferred){
		var items;

		/*
		 * depending on the ActiveRecord::Base.include_root_in_json setting,
		 * you might get back an array of attribute objects, or an array of
		 * objects with the attribute object nested under an attribute having
		 * the same name as the (remote and unguessable) model class.
		 *
		 * 'Example' without root_in_json: [{'id':1, 'text':'first'}]
		 * 'Example' with root_in_json: [{'example':{'id':1, 'text':'first'}}]
		 */
		if((typeof this.rootAttribute == 'undefined') && results[0]){
			if(results[0][this.idAttribute]){
				this.rootAttribute = false;
				console.debug('RailsStore: without root_in_json');
			}else{
				for(var attribute in results[0]){
					if(results[0][attribute][this.idAttribute]){
						this.rootAttribute = attribute;
						console.debug('RailsStore: with root_in_json, attribute: ' + attribute);
					}
				}
			}
		}

		if(this.rootAttribute){
			items = dojo.map(results, function(item){
				return item[this.rootAttribute];
			}, this);
		}else{
			items = results;
		}

		// index the results
		var count = results.length;
		// if we don't know the length, and it is partial result, we will guess that it is twice as big, that will work for most widgets
		return {totalCount:deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: items};
	}
});

});
