define(["dojo/_base/lang", "dojo/Deferred", "dojo/promise/all", "dojo/when"], function(lang, Deferred, all, when){
	return function(/*Object*/ config, /*Object*/ parent, /*Object*/ app){
		// summary:
		//		model is called to create all of the models for the app, and all models for a view, it will
		//		create and call the appropriate model utility based upon the modelLoader set in the model in the config
		// description:
		//		Called for each view or for the app.  For each model in the config, it will  
		//		create the model utility based upon the modelLoader and call it to create and load the model. 
		// config: Object
		//		The models section of the config for this view or for the app.
		// parent: Object
		//		The parent of this view or the app itself, so that models from the parent will be 
		//		available to the view.
		// returns: loadedModels 
		//		 loadedModels is an object holding all of the available loaded models for this view.
		var loadedModels = {};
		if(parent.loadedModels){
			lang.mixin(loadedModels, parent.loadedModels);
		}
		if(config){
			var allDeferred = [];
			for(var item in config){
				if(item.charAt(0) !== "_"){
					allDeferred.push(setupModel(config, item, app, loadedModels));
				}
			}
			return (allDeferred.length == 0) ? loadedModels : all(allDeferred);
		}else{
			return loadedModels;
		}
	};

	function setupModel(config, item, app, loadedModels){
		// Here we need to create the modelLoader and call it passing in the item and the config[item].params
		var params = config[item].params ? config[item].params : {};

		var modelLoader = config[item].modelLoader ? config[item].modelLoader : "dojox/app/utils/simpleModel";
		// modelLoader must be listed in the dependencies and has thus already been loaded so it _must_ be here
		// => no need for complex code here
		try{
			var modelCtor = require(modelLoader);
		}catch(e){
			throw new Error(modelLoader+" must be listed in the dependencies");
		}
		var loadModelDeferred = new Deferred();
		var createModelPromise;
		try{
			createModelPromise = modelCtor(config, params, item);
		}catch(e){
			throw new Error("Error creating "+modelLoader+" for model named ["+item+"]: "+e.message);
		}
		when(createModelPromise, lang.hitch(this, function(newModel){
			loadedModels[item] = newModel;
			app.log("in app/model, for item=[",item,"] loadedModels =", loadedModels);
			loadModelDeferred.resolve(loadedModels);
			return loadedModels;
		}), function(e){
			throw new Error("Error loading model named ["+item+"]: "+e.message);
		});
		return loadModelDeferred;
	}
});
