var BaseController = new Class({
	Implements: [Options, Events],
	
	url: 'index.php',
	commands: {'reset':'r', 'fire':'f', 'moveUp':'dy', 'moveDown':'dy', 'moveLeft':'dx', 'moveRight':'dx'},
	haveCommands: false,
	stack: {},
	modes: {'const':1, 'linearSmooth': 2, 'linear': 3, 'logarithm': 4, 'exponential': 5, 'linearSlow': 6},
	maxShift: 3,
	
	initialize: function(options){
		this.setOptions(options);
		this.isSending = false;
		
		this.onRequestSuccessHandler = jQuery.proxy(this.onRequestSuccess, this);
		this.onRequestErrorHandler = jQuery.proxy(this.onRequestError, this);
		this.activeShiftMode = this.modes.linearSmooth;
	},
	
	sendRequest : function(action, holdCommands) {
		if (!this.isSending) {
			this.isSending =  true;
			
		    var data = this.getData();
			data['action'] = action;
			data['ctx'] = 'web';
			// parameter to bypass caches (browser, proxies, transparent proxies, front-end etc.)
            data['anticache'] = Math.random();
			
			try {
    			$.ajax({
    			    'url': this.url,
    			    'dataType' : "json",
    			    'type': "GET", // GET faster of POST

    			    // WE MUST PREPARE VALUES FOR SENDING FROM FLOAT TO INT WITH FLOOR()
    			    
    			    'data' : data,
    			    success: this.onRequestSuccessHandler,
    			    error: this.onRequestErrorHandler
    			});
    			
    			if (!holdCommands) {
    				this.clearGunCommands();
    			}
    			
			} catch (ex) {
			    this.isSending = false;
			}
		}
	},
	
	addGunCommand: function(cmd, value) {		
	    var isFirstCmd = typeof(this.stack[cmd]) == 'undefined';
	    
	    this.fireBeforeEvent(isFirstCmd, cmd);
    	
    	if (isFirstCmd) {
    	    this.stack[cmd] = value;
    	} else {
    	    this.stack[cmd] = this.getNextShift(cmd, value);
    	}
    	
    	this.haveCommands = true;
	},
	
	getData:function() {
	    var data={};

		for(var cmd in this.stack) {
			if (typeof(this.stack[cmd]) != 'function') {
			    if (this.stack[cmd]) {
    			    var sign = this.stack[cmd] >= 0 ? 1 : -1;
    				data[cmd] = Math.floor(Math.abs(this.stack[cmd])) * sign;
			    } else {
			        throw "this.stack[cmd] invalid";
			    }
			}
		}
	    return data;
	},
	
	getNextShift: function(cmd, value) {
	    if (cmd == this.commands.fire) {
	        return value;
	    }
	    
	    // rule:  value = -1 or 1
	    var stackValue = this.stack[cmd];
	    var shift = Math.floor(Math.abs(stackValue));
	    if (shift >= this.maxShift) {
	        return this.maxShift * value;
	    }
	    
	    switch(this.activeShiftMode) {
            case this.modes.const:
                stackValue = value;
	            break;
	        case this.modes.linearSmooth:
                stackValue += (value * 0.5);
	            break;
	        case this.modes.linearSlow:
    	        stackValue += (value * 0.3);
                break;
	        case this.modes.logarithm:
	            shift = Math.log(1.2 * Math.abs(stackValue));
	            stackValue += value * shift;
	            break;
	        case this.modes.exponential:
                shift = Math.exp(Math.abs(stackValue)) / 10;
                stackValue += value * shift;
	            break;
	        case this.modes.linear:
	        default:
                stackValue += value;
	            break;
	    }
	    
	    return stackValue;
	},
	
	fireBeforeEvent: function(command, isFirstCmd) {
    	switch (command) {
		    case this.commands.reset:
		        if (isFirstCmd) {
		    	    this.fireEvent('beforeReset', command);
	    	    }
		        break;
	        case this.commands.fire:
	            if (isFirstCmd) {
	        	    this.fireEvent('beforeFire', command);
        	    }
	        	break;
        	case this.commands.moveUp:
        	case this.commands.moveDown:
        	case this.commands.moveLeft:
        	case this.commands.moveRight:
        	    if (isFirstCmd) {
        		    this.fireEvent('beforeMove', command);
    		    }
		        break; 
    	}  
	},
	
	clearGunCommands: function() {
		for(var cmd in this.stack) {
			if (typeof(this.stack[cmd]) != 'function') {
				delete this.stack[cmd];
			}
		}
		this.haveCommands = false;
	},
	
	onRequestSuccess: function(eventObj, senderObj) {
		this.isSending = false;
		this.fireEvent('commandSuccess', arguments);
		
		//function (data, textStatus) { 
    	/*if (data.code) {
	    	switch (data.code) {
			    case 0:
			        break;
		        case 1:
		        	break;
	        	case 2:
			        break; 
	    	}
    	}*/
	},
	
	onRequestError: function(eventObj, senderObj) {
		this.isSending = false;
		this.fireEvent('commandError', arguments);
	}
}); 
