var App = function(remote, aCanvas, model) {
	var app = this;
  var id;
	
	var mouse = {x: 0, y: 0, worldx: 0, worldy: 0, tadpole:null},
			keyNav = {x:0,y:0},
			messageQuota = 5
	;

  var runLoop = function() {
    app.update();
    app.draw();
  }

  app.start = function () {
    app.id = setInterval(runLoop, 30);
  }

  app.stop = function() {
    clearInterval(app.id);
  }

  app.sign_in = function(username, password) {
    model.username = username;
    model.password = password;
    remote.signIn(username, password);
  };

  app.sign_up = function(username, password, password_confirmation) {
    model.username = username;
    model.password = password;
    model.password_confirmation = password_confirmation;
    remote.signUp(username, password, password_confirmation);
  };
  
  app.update = function() {
	  if (messageQuota < 5 && model.userTadpole.age % 50 == 0) { messageQuota++; }
	  
		// Update usertadpole
    if(keyNav.x != 0 || keyNav.y != 0) {
			model.userTadpole.userUpdate(model.tadpoles, model.userTadpole.x + keyNav.x,model.userTadpole.y + keyNav.y);
		}
		else {
			var mvp = getMouseWorldPosition();
			mouse.worldx = mvp.x;
			mouse.worldy = mvp.y;
			model.userTadpole.userUpdate(model.tadpoles, mouse.worldx, mouse.worldy);
		}
				
		if(model.userTadpole.age % 6 == 0 && model.userTadpole.changed > 1){//TODO && webSocketService.hasConnection) {
			model.userTadpole.changed = 0;
			remote.update(model.userTadpole);
		}
		
		model.camera.update(model);
		
		// Update tadpoles
		for(id in model.tadpoles) {
			model.tadpoles[id].update();
		}
		
		// Update waterParticles
		model.waterParticles.forEach(function(p) {
			p.update(model.camera.getOuterBounds(), model.camera.zoom);
		})
		
		// Update arrows
		for(i in model.arrows) {
			var cameraBounds = model.camera.getBounds();
			var arrow = model.arrows[i];
			arrow.update();
		}
	};
  
  var updateMomentum = function(){
    model.userTadpole.momentum = model.userTadpole.targetMomentum = model.userTadpole.maxMomentum;
    // var dist = distance(canvas.width/2, canvas.height/2, mouse.x, mouse.y);
    // var maxDist = distance(canvas.width/2, canvas.height/2, 0,0);
    // tadPole.momentum = tadPole.targetMomentum = map(dist/maxDist, 0, tadPole.maxMomentum);
  };
	
	app.sendMessage = function(msg) {
	  if (messageQuota>0) {
	    messageQuota--;
	    remote.say(msg);
	  }
	}
	  
  app.display_sign_in_success = function() {
    $('.link_container').hide();
    $('.sign_in_container').hide();
    $('.sign_up_container').hide();
    $('.profile_container').show();
    $('.profile_username').html(model.userTadpole.name);
  };
  
  app.display_sign_in_failure = function() {
    $('.link_container').show();
    $('.sign_up_container').hide();
    $('.sign_in_container').show();
    $('.profile_container').hide();
    //TODO show error messages
    $('.form_errors').show()
    $('.form_errors').html("Wrong username/password")
  };
  
  app.display_sign_up_success = function() {
    $('.link_container').hide();
    $('.sign_in_container').hide();
    $('.sign_up_container').hide();
    $('.profile_container').show();
    $('.profile_username').html(model.userTadpole.name);
  };
  
  app.display_sign_up_failure = function() {
    $('.sign_in_container').hide();
    $('.sign_up_container').show();
    $('.profile_container').hide();
    //TODO show error messages
    message = '';
    if(document.sign_up_form.password.value != document.sign_up_form.password_confirmation.value){
      message = "Password and password confirmation should be same"
    } else {
      message = "This username is already taken"
    }
    
    $('.form_errors').html(message)
  };
  
  app.get_model = function() {
    return model;
  };
  
  app.change_color = function(color) {
    model.userTadpole.color = color;
  }
  
	app.draw = function() {
		model.camera.setupContext();
		
		// Draw waterParticles
		for(i in model.waterParticles) {
			model.waterParticles[i].draw(context);
		}
		
		// Draw tadpoles
		for(id in model.tadpoles) {
			model.tadpoles[id].draw(context);
		}
		
		// Start UI layer (reset transform matrix)
		model.camera.startUILayer();
		
		// Draw arrows
		for(i in model.arrows) {
			model.arrows[i].draw(context, canvas);
		}
	};
		
	app.mousedown = function(e) {
		mouse.clicking = true;
    mouse.pressed = true;
		
		if(model.userTadpole && e.which == 1) {
			//model.userTadpole.momentum = model.userTadpole.targetMomentum = model.userTadpole.maxMomentum;
      updateMomentum();
		}
	};
	
	app.mouseup = function(e) {
    mouse.pressed = false;
		if(model.userTadpole && e.which == 1) {
			model.userTadpole.targetMomentum = 0;
		}
	};
	
	app.mousemove = function(e) {
		mouse.x = e.clientX;
		mouse.y = e.clientY;
    if (mouse.pressed){
      updateMomentum();
    }
	};
	
	app.keydown = function(e) {
		if(e.keyCode == keys.up) {
			keyNav.y = -1;
			//model.userTadpole.momentum = model.userTadpole.targetMomentum = model.userTadpole.maxMomentum;
      updateMomentum();
			e.preventDefault();
		}
		else if(e.keyCode == keys.down) {
			keyNav.y = 1;
			//model.userTadpole.momentum = model.userTadpole.targetMomentum = model.userTadpole.maxMomentum;
      updateMomentum();
			e.preventDefault();
		}
		else if(e.keyCode == keys.left) {
			keyNav.x = -1;
			//model.userTadpole.momentum = model.userTadpole.targetMomentum = model.userTadpole.maxMomentum;
      updateMomentum();
			e.preventDefault();
		}
		else if(e.keyCode == keys.right) {
			keyNav.x = 1;
			//model.userTadpole.momentum = model.userTadpole.targetMomentum = model.userTadpole.maxMomentum;
      updateMomentum();
			e.preventDefault();
		}
	};
	
	app.keyup = function(e) {
		if(e.keyCode == keys.up || e.keyCode == keys.down) {
			keyNav.y = 0;
			if(keyNav.x == 0 && keyNav.y == 0) {
				model.userTadpole.targetMomentum = 0;
				model.userTadpole.momentum = 0;
			}
			e.preventDefault();
		}
		else if(e.keyCode == keys.left || e.keyCode == keys.right) {
			keyNav.x = 0;
			if(keyNav.x == 0 && keyNav.y == 0) {
				model.userTadpole.targetMomentum = 0;
				model.userTadpole.momentum = 0;
			}
			e.preventDefault();
		}
	};
	
	app.touchstart = function(e) {
	  e.preventDefault();
	  mouse.clicking = true;		
		
		if(model.userTadpole) {
			model.userTadpole.momentum = model.userTadpole.targetMomentum = model.userTadpole.maxMomentum;
		}
		
		var touch = e.changedTouches.item(0);
    if (touch) {
      mouse.x = touch.clientX;
  		mouse.y = touch.clientY;      
    }    
	}
	app.touchend = function(e) {
	  if(model.userTadpole) {
			model.userTadpole.targetMomentum = 0;
		}
	}
	app.touchmove = function(e) {
	  e.preventDefault();
    
    var touch = e.changedTouches.item(0);
    if (touch) {
      mouse.x = touch.clientX;
  		mouse.y = touch.clientY;      
    }		
	}
	
	app.resize = function(e) {
		resizeCanvas();
	};
	
	var getMouseWorldPosition = function() {
		return {
			x: (mouse.x + (model.camera.x * model.camera.zoom - canvas.width / 2)) / model.camera.zoom,
			y: (mouse.y + (model.camera.y * model.camera.zoom  - canvas.height / 2)) / model.camera.zoom
		}
	}
	
	var resizeCanvas = function() {
		canvas.width = window.innerWidth;
		canvas.height = window.innerHeight;
	};
	
	// Constructor
	(function(){
		canvas = aCanvas;
		context = canvas.getContext('2d');
		resizeCanvas();
	})();
}

