var errorMode ='log';
// TODO check fore framework
var MVC = Base.extend({
    controller: function(controller) {
        try {
            if(!isTypeof(Controller, controller)) {
                throw 'MVC.controller(): controller is not a valid Controller';
            }
            
            if(exists(this[controller.name])) {
                throw 'MVC.controller(): "'+controller.name+'" is already defined';
            }
            
            this[controller.name] = controller;
        }
        catch(error) {
            handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
        }
	},
	
	model: function(model) {
	    try {
	        if(!isTypeof(Model, model)) {
                throw "MVC.model(): model is not a valid Model";
            }
	        if(exists(this[model.name+'Model'])) {
	            throw 'MVC.model(): "'+model.name+'" is already defined';
	        }
	        
	        this[model.name+'Model'] = model;
	    }
	    catch(error) {
	        handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
	    }
	}
});

var Model = Base.extend({
    constructor: function(options) {
        var settings = {
            url: false,
            dataType: 'json',
            ajax: false,
            data: false
        };
        
        try {
            this.requiredArgumentSanityCheck(options);
            
            for(var option in options) {
                settings[option] = options[option];
            }

            for(var setting in settings) {
                this[setting] = settings[setting];
            }
            
            (this.url) ? this.ajaxSanityCheck() : this.localDataSanityCheck();
        }
        catch(error) {
            handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
        }
    },
    
    requiredArgumentSanityCheck: function(options) {
        if(!exists(options)) {
            throw "Model(): options is undefined";
        }

        if(!isTypeof(Object, options)) {
            throw "Model() options is not a valid Object";
        }

        if(!exists(options['name'])) {
            throw "Model(): name is undefined";
        }

        if(!isTypeof(String, options['name'])) {
            throw "Model(): name is not a valid String"; 
        }
    },
    
    localDataSanityCheck: function() {
        if(!exists(this.data)) {
            throw "Model(): data is undefined";
        }
        
        var allowedTypes = {
            "json": Object,
            "text": String,
            "number": Number,
            "array": Array,
            "bool": Boolean,
            "date": Date
        };
        
        var modelObj = this;
        var type;
        for(type in allowedTypes) {
            if(modelObj.dataType === type) {
                if(isTypeof(allowedTypes[type], modelObj.data)) {
                    throw "Model(): dataType of "+type+" requires a valid "+allowedTypes[type];
                }
                return true;
            }
        }
    },
    
    ajaxSanityCheck: function() {
        if(this.ajax === true && this.url === false) {
            throw "Model(): url is undefined";
        }
    
        if(!isTypeof(String, this.url)) {
            throw "Model(): url is not a valid String";
        }
        
        this.ajax = true;
    },

    // TODO need errors in get for trying to use callbacks with non ajax calls
    get: function(callback) {
        var self = this;
        if(this.ajax === true) {
            var data = framework.ajax({
                url: this.url,
                dataType: this.dataType,
                callback: function(response) {
                    self.data = response;
                    callback.call(self, response);
                }
             });
        }
        else {
            return this.data;
        }
    }
});

var View = Base.extend({
    templates: [],
    constructor: function(name, selector) {
        if(!exists(selector)) {
            selector = '#'+name;
        }
        
        try {
            if(!exists(name)) {
                throw "View(): name is undefined";
            }

            if(!isTypeof(String, name)) {
                throw "View(): name is not a valid String";
            }

            this.selector = selector;
            this.name = name.replace(/-/g, '_');
        }
        catch(error) {
            handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
        }
        
        this.load();
    },
    
    load: function() {
        var selection = framework.select(this.selector);
	    try {
	        if(!exists(selection)) {
        		throw "View.load(): invalid selector";
        	}
        	
        	this.element = selection;
        	this.tagName = framework.getTagName(this.element).toLowerCase();
        	this.id = framework.getId(this.element);
        	this.className = framework.getClassName(this.element);
        	return this.element;
	    }
	    catch(error) {
	        handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
	    }
	},
	
	loadTemplate: function(name) {
   	    var self = this;
   		try {
   		    if(!exists(name)) {
       			throw "View.loadTemplate(): name is undefined";
       		}

       		if(!isTypeof(String, name)) {
       		    throw "View.loadTemplate(): name is not a valid String";
       		}

       		if(exists(this.templates[name])) {
       		    throw 'View.loadTemplate(): there is already a template named "'+name+'"';
       		}
       		else {
           		this.templates[name] = new Template(name);
       		}
   		}
   		catch(error) {
   		    handleError({
                   error: error,
                   mode: errorMode,
                   filename: 'mvc.js'
               });
   		}
	}
});

var Controller = Base.extend({
    constructor: function(name) {
        try {
            if(!exists(name)) {
        		throw "Controller(): name is undefined";
        	}
        }
        catch(error) {
            handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
        }

    	this.name = name;
    	this.models = [];
    	this.views = [];
    },
	
	ready: function() {
	    var self = this;
		framework.ready(function() {	    
			self.actions();
		});
	},
	
	actions: function() {
	    
	},
		
	addView: function(view) {
		try {
		    if(!exists(view)) {
    			throw "Controller.addView(): view is undefined";
    		}

    		if(!isTypeof(View, view)) {
    		    throw "Controller.addView(): view is not a valid View";
    		}
    		
    		if(exists(this[view['name']])) {
    		    throw 'Controller.addView(): there is already a view named "'+view.name+'"';
    		}
    		else {
    		    var length = this.views.length;
        		this.views[view.name] = view;
        		this[view.name] = view.load();
    		}
		}
		catch(error) {
		    handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
		}
	},
	
	addModel: function(model) {
		try {
		    if(!exists(model)) {
		        throw "Controller.addModel(): model is undefined";
    		}
    		
    		if(!isTypeof(Model, model)) {
    		    throw "Controller.addModel(): model is not a valid Model";
    		}
		}
		catch(error) {
		    handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
		}
		
		var length = this.models.length;
		
		this[model.name+'Model'] = model.data;
		this.models[length++] = model;
	}
});

var Template = Base.extend({
    constructor: function(name) {
        try {
            if(!exists(name)) {
                throw 'Template(): name is undefined';
            }
            if(!isTypeof(String, name)) {
                throw 'Template(): name is not a valid String';
            }
            
            this.tmpl = new EJS({url: '../application/templates/'+name+'.ejs'});
        }
        catch(error) {
            handleError({
                error: error,
                mode: errorMode,
                filename: 'mvc.js'
            });
        }
    },
    
    render: function(data) {
        return this.tmpl.render(data);
    }
});