var UserStatus = {
	LOGGED_IN: "loggedIn",
	LOGGED_OUT: "loggedOut"
};

var UserLogInEvent = {
	SUCCESS: "logIn",
	FAIL: "logInFail"
};

var UserLogOutEvent = {
	LOG_OUT: "logOut",
	LOG_OUT_FAIL: "logOutFail"
};

var UserUpdateEvent = {
	SUCCESS: "update",
	FAIL: "updateFail"
};

var UserChangePasswordEvent = {
	SUCCESS: "changePassword",
	FAIL: "changePasswordFail"
};

var UserCreateAccountEvent = {
	SUCCESS: "createAccount",
	FAIL: "createAccountFail"
};

var LoginReturn = {
	SUCCESS: 0,
	INVALID_CREDENTIALS: 1
};

var CreateAccountReturn = {
	SUCCESS: 0,
	INVALID_NAME: 1,
	INVALID_PASS: 2,
	INVALID_MAIL: 4,
	DB_ERROR: 8
};

var UserChangeNameReturn = {
	NO_CHANGE: -1,
	SUCCESS: 0,
	UNKNOWN_REASON: 1,
	NO_LOGIN: 2,
	INVALID_NAME: 4,
	USER_NOT_FOUND: 8,
	NAME_ALREADY_TAKEN: 16
};

var UserChangeEmailReturn = {
	NO_CHANGE: -1,
	SUCCESS: 0,
	UNKNOWN_REASON: 1,
	NO_LOGIN: 2,
	INVALID_EMAIL: 4,
	USER_NOT_FOUND: 8,
	EMAIL_ALREADY_TAKEN: 16
};

var UserChangePasswordReturn = {
	NO_CHANGE: -1,
	SUCCESS: 0,
	UNKNOWN_REASON: 1,
	NO_LOGIN: 2,
	INVALID_PASSWORD: 4,
	USER_NOT_FOUND: 8
};

function User(backendConnection) {

	var userService = new UserService(backendConnection);
	this.verified = false;
	var listeners = {};
	listeners[UserStatus.LOGGED_IN] = [];
	listeners[UserStatus.LOGGED_OUT] = [];
	listeners[UserLogInEvent.SUCCESS] = [];
	listeners[UserLogInEvent.FAIL] = [];
    listeners[UserLogOutEvent.SUCCESS] = [];
    listeners[UserLogOutEvent.FAIL] = [];
    listeners[UserCreateAccountEvent.SUCCESS] = [];
    listeners[UserCreateAccountEvent.FAIL] = [];
    listeners[UserUpdateEvent.SUCCESS] = [];
    listeners[UserUpdateEvent.FAIL] = [];
    listeners[UserChangePasswordEvent.SUCCESS] = [];
    listeners[UserChangePasswordEvent.FAIL] = [];
	var that = this;
	
	var propagateUserInfo = function(user) {
		$(".userID").html(user.id);
		$(".userName").html(user.name);
		$(".userLocale").html(user.locale);
		$(".userImage").html('<img src="' + user.image + '" alt="' + user.name + '" />');
		$(".userVerified").html(user.verified ? "Yes" : "No");
	}
	this.propagateUserInfo = function() {
		propagateUserInfo(that);
	}
	
	var propagateExtendedUserInfo = function(user, callback) {
		userService.getExtendedUser(function(user) {
			propagateUserInfo(that);
			that.email = user.email;
			$(".userEmail").html(user.email);
			if (callback) {
				callback(true);
			}
		}, function() {
			propagateUserInfo(that);
			if (callback) {
				callback(false);
			}
		});
	}
	this.propagateExtendedUserInfo = function(callback) {
		propagateExtendedUserInfo(that, callback);
	}
	
	var onLoggedOut = function() {
		if (that.verified) {
			return;
		}
		var statusListeners = listeners[UserStatus.LOGGED_OUT];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i]();
		}
	}
	
	var onLoggedIn = function(user) {
		$.extend(true, that, user);
		if (!that.verified) {
			onLoggedOut();
			return;
		}
		propagateUserInfo(user);
		
		var statusListeners = listeners[UserStatus.LOGGED_IN];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](user);
		}
	}
	
	this.updateState = function(callback) {
		userService.getCurrentUser(function(user) {
			onLoggedIn(user);
			if (callback) {
				callback();
			}
		}, function() {
			onLoggedOut();
			if (callback) {
				callback();
			}
		});
	}
	
	var onLogInFail = function(message) {
		if (!message) {
			message = "Server moody, didn't answer :(";
		}
		var statusListeners = listeners[UserLogInEvent.FAIL];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](message);
		}
	}
	
	var onLogIn = function(user) {
		if (!user.verified) {
			onLogInFail();
			return;
		}
		$.extend(true, that, user);
		propagateUserInfo(user);
		
		var statusListeners = listeners[UserLogInEvent.SUCCESS];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](user);
		}
	}
		
	this.logIn = function(username, password) {
		userService.login(function(code) {
			if (LoginReturn.SUCCESS == code) {
				userService.getCurrentUser(onLogIn, onLogInFail);
			} else {
				onLogInFail("Username or password incorrect?");
			}
		}, onLogInFail, username, password);
	}
	
	var onLogOutFail = function(message) {
		if (!message) {
			message = "Server moody, didn't answer :(";
		}
		var statusListeners = listeners[UserLogOutEvent.FAIL];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](message);
		}
	}
	
	var onLogOut = function() {
		that.verified = false;
		var statusListeners = listeners[UserLogOutEvent.SUCCESS];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i]();
		}
	}
	
	this.logOut = function() {
		userService.logout(onLogOut, onLogOutFail);
	}
	
	var onCreateAccountFail = function(code) {
		var message = "";
		switch(code) {
			case CreateAccountReturn.INVALID_NAME:
				message += "There's something wrong with your name. Btw, we don't allow @-signs ;)";
				break;
			case CreateAccountReturn.INVALID_PASS:
				message += "There's something wrong with your password.";
				break;
			case CreateAccountReturn.INVALID_MAIL:
				message += "There's something wrong with your email address.";
				break;
			case CreateAccountReturn.DB_ERROR:
				message += "Looks like our data base is having some fun elsewhere ...";
				break;
			default:
				message += "Ooops ... I accidentally ... the whole internet.";
		}
		var statusListeners = listeners[UserCreateAccountEvent.FAIL];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](message);
		}
	}
	
	var onCreateAccount = function(user) {
		var statusListeners = listeners[UserCreateAccountEvent.SUCCESS];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](user);
		}
	}
	
	this.createAccount = function(username, password, email, keepMePosted) {
		userService.createUser(function(code) {
			if (CreateAccountReturn.SUCCESS == code) {
				userService.getCurrentUser(function(user) {
					onCreateAccount(user);
					onLogIn(user);
				}, onCreateAccountFail);
			} else {
				onCreateAccountFail(code);
			}
		}, onCreateAccountFail, username, password, email, keepMePosted);
	}
	
	var onChangeNameFail = function(code) {
		var message = "";
		switch(code) {
			case UserChangeNameReturn.NO_CHANGE:
				message += "Your name didn't change.";
				break;
			case UserChangeNameReturn.UNKNOWN_REASON:
				message += "Server went over board.";
				break;
			case UserChangeNameReturn.NO_LOGIN:
				message += "Server went over board.";
				break;
			case UserChangeNameReturn.INVALID_NAME:
				message += "There was something wrong with your name. Btw, we don't allow @-signs ;)";
				break;
			case UserChangeNameReturn.USER_NOT_FOUND:
				message += "Where are you? Couldn't find you :(";
				break;
			case UserChangeNameReturn.NAME_ALREADY_TAKEN:
				message += "Too late, that name is already taken.";
				break;
		}
		var statusListeners = listeners[UserUpdateEvent.FAIL];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](message);
		}
	}
	
	var onChangeName = function(username) {
		that.name = username;
		propagateUserInfo(that);
		
		var statusListeners = listeners[UserUpdateEvent.SUCCESS];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](that);
		}
	}
	
	var onChangeEmailFail = function(code) {
		var message = "";
		switch(code) {
			case UserChangeEmailReturn.NO_CHANGE:
				message += "You didn't change anything ;)";
				break;
			case UserChangeEmailReturn.UNKNOWN_REASON:
				message += "Server went nuts. Please try again later.";
				break;
			case UserChangeEmailReturn.NO_LOGIN:
				message += "You seem not to be logged in?";
				break;
			case UserChangeEmailReturn.INVALID_EMAIL:
				message += "The email address was invalid.";
				break;
			case UserChangeEmailReturn.USER_NOT_FOUND:
				message += "Server couldn't find you, too much booze.";
				break;
			case UserChangeEmailReturn.EMAIL_ALREADY_TAKEN:
				message += "Too late, your email is already taken ;)";
				break;
		}
		var statusListeners = listeners[UserUpdateEvent.FAIL];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](message);
		}
	}
	
	var onChangeEmail = function(email) {
		that.email = email;
		propagateUserInfo(that);
		
		var statusListeners = listeners[UserUpdateEvent.SUCCESS];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](that);
		}
	}
	
	this.updateAccount = function(username, email) {
		var change = false;
		if (username && this.name != (username = $.trim(username))) {
			change = true;
			userService.changeUsername(function(code) {
				if (UserChangeNameReturn.SUCCESS == code) {
					onChangeName(username);
				} else {
					onChangeNameFail(code);
				}
			}, onChangeNameFail, username);
		}
		if (email && this.email != (email = $.trim(email))) {
			change = true;
			userService.changeEmail(function(code) {
				if (UserChangeEmailReturn.SUCCESS == code) {
					onChangeEmail(email);
				} else {
					onChangeEmailFail(code);
				}
			}, onChangeEmailFail, email);
		}
		if (!change) {
			onChangeNameFail(UserChangeNameReturn.NO_CHANGE);
		}
	}
	
	var onChangePasswordFail = function(code) {
		var message = "";
		switch(code) {
			case UserChangePasswordReturn.NO_CHANGE:
				message += "Your password didn't change.";
				break;
			case UserChangePasswordReturn.UNKNOWN_REASON:
				message += "Yep, another Friday. Server gone for a few minutes.";
				break;
			case UserChangePasswordReturn.NO_LOGIN:
				message += "Your old password was incorrect.";
				break;
			case UserChangePasswordReturn.INVALID_PASSWORD:
				message += "Your password contained invalid values. But what do I know ...";
				break;
			case UserChangePasswordReturn.USER_NOT_FOUND:
				message += "Server couldn't find you. Apparently he's gone crazy.";
				break;
		}
		var statusListeners = listeners[UserChangePasswordEvent.FAIL];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i](message);
		}
	}
	
	var onChangePassword = function() {
		var statusListeners = listeners[UserChangePasswordEvent.SUCCESS];
		for (var i = 0; i < statusListeners.length; ++i) {
			statusListeners[i]();
		}
	}
	
	this.changePassword = function(password, newPassword) {
		if (password != newPassword) {
			userService.changePassword(function(code) {
				if (UserChangePasswordReturn.SUCCESS == code) {
					onChangePassword();
				} else {
					onChangePasswordFail(code);
				}
			}, onChangePasswordFail, this.name, password, newPassword);
		} else {
			onChangePasswordFail(UserChangePasswordReturn.NO_CHANGE);
		}
	}
	
	this.hasListener = function(event, listener) {
		var eventListeners = listeners[event];
		if (!eventListeners) {
			return false;
		}
		for (var i = 0; i < eventListeners.length; ++i) {
			if (eventListeners[event] == listener) {
				return true;
			}
		}
		return false;
	}
	
	this.addListener = function(event, listener) {
		if (!listeners[event] || this.hasListener(event, listener)) {
			return;
		}
		listeners[event].push(listener);
	}
	
	this.removeListener = function(event, listener) {
		var eventListeners = listeners[event];
		if (!eventListeners) {
			return;
		}
		for (var i = 0; i < eventListeners.length; ++i) {
			if (eventListeners[i] == listener) {
				eventListeners.splice(i, 1);
				return;
			}
		}
	}
	
	this.destroy = function() {
		listeners = null;
	}
}
