/* Copyright 2009 Palm, Inc.  All rights reserved. */

var AccountloginAssistant = Class.create({
	initialize: function (params) {
		this.acctId = params.acctId;
		this.acctLogin = params.acctLogin;
		this.acctTypeId = params.acctTypeId;
		this.acctDomain = params.acctDomain;
		this.acctName = params.acctName;
		this.iconClass = params.iconClass;
		this.sceneToReturnTo = params.sceneToReturnTo;
		this.pimSyncService = AppAssistant.pimSyncService;
		this.shouldFocus = params.shouldFocus;
		this.numberOfTimesToPopScene = params.numberOfTimesToPopScene;
	},
	
	clearDummyPassword: function (event) {
		// Only clear the contents of the field if we detect that
		// this is the first time the user has changed the password.
		if (!this.passwordChanged) {
			event.target.value = "";
			// Stop listening to the taps in the Password field, since we have cleared
			// the dummy password, and the user is editing the field
			this.passwordTapHandlerStopped = true;
			this.controller.stopListening("Password", Mojo.Event.tap, this.passwordTapHandler);
		}
		this.passwordChanged = true;
	},
	
	setup: function () {
		this.accountModel = {
			username: "",
			password: "",
			usernameDisabled: false
		};
		
		var usernameDefaultFocus = false;
		var passwordDefaultFocus = false;
		
		// Hide the error
		this.controller.get('login_error').hide();
		
		this.buttonAttributes = {
			type: Mojo.Widget.activityButton
		};
		this.buttonModel = {
			buttonLabel : $L("Sign in"),
			buttonClass: 'primary',
			disabled: false
		};
		this.controller.setupWidget("LoginButton", this.buttonAttributes, this.buttonModel);
		this.loginBtn = this.controller.get("LoginButton");
		
		if (this.acctId === 0) {
			// Add New Account
			this.title = $L("Add an account");
			// Put focus in Username field by default
			usernameDefaultFocus = true;
		} else {
			// Edit Account
			this.title = $L("Change login settings");
			// Put the login name in the Username field
			this.accountModel.username = this.acctLogin;
			// Populate the Password field with 6 bullets
			this.accountModel.password = "";
			this.passwordChanged = false;
			// Disable the Username field in Edit case
			this.accountModel.usernameDisabled = true;
			// Put focus in Password field by default
			passwordDefaultFocus = true;
			this.refetchContactCount();
			this.setupDeleteButton();
		}
		
		// Set up the Username and Password TextField widgets
		this.controller.setupWidget("Username", {modelProperty: "username", disabledProperty: 'usernameDisabled', focus: usernameDefaultFocus, textReplacement: false}, this.accountModel);
		
		// If we are editing an account, the Password field should have focus, and
		// all of the Password should be selected so the user can change it upon
		// the first key
		this.controller.setupWidget("Password", {modelProperty: "password", requiresEnterKey: true, focus: passwordDefaultFocus, focusMode: Mojo.Widget.focusSelectMode}, this.accountModel);
		
		// Render the header
		var headerObj = {};
		headerObj.iconClass = this.iconClass;
		headerObj.title = this.title;
		var headerHtml = Mojo.View.render({object: headerObj, template: 'accountlogin/accountlogin-header'});
		this.controller.get('login_header_div').update(headerHtml);
		
		// Render the domain name in the title of the group box
		this.controller.get('login_domain_name').update(this.acctName);
	
		if (this.acctId !== 0) {
			// Only assign these listeners if Editing account
			this.passwordPropertyChangeHandler = this.handlePasswordPropertyChange.bindAsEventListener(this);
			this.controller.listen("Password", Mojo.Event.propertyChange, this.passwordPropertyChangeHandler);
			
			this.passwordTapHandler = this.clearDummyPassword.bindAsEventListener(this);
			this.controller.listen("Password", Mojo.Event.tap, this.passwordTapHandler);
		}
		
		this.passwordField = this.controller.get("Password");
		this.usernameField = this.controller.get("Username");
	},
	
	refetchContactCount: function () {
		AppAssistant.contactsService.countAccountsContacts(this.controller, this.acctId, this.renderNumberOfcontacts.bind(this));
	},
	
	renderNumberOfcontacts: function (resp) {
		var numPeople = resp.contactCount;
		if (0 < numPeople) {
			var template = $L("#{count} Contacts");
			if (numPeople === 1) {
				template = $L("1 Contact");
			}
			var message = template.interpolate({count: numPeople});
			this.controller.get("NumberOfPeople").update(message);
			this.controller.get("PersonCountBlock").show();
		} else {
			this.controller.get("PersonCountBlock").hide();
		}
		
		this.timer = setTimeout(this.refetchContactCount.bind(this), 15000);
	},
	
	setupDeleteButton: function () {
		this.deleteButtonModel = {
			buttonLabel: $L("Remove Account"),
			disabled: false,
			buttonClass: "negative"
		};
		this.controller.setupWidget("setupRemoveAccount", {type: Mojo.Widget.activityButton}, this.deleteButtonModel);
		this.deleteButton = this.controller.get("setupRemoveAccount");
		this.deleteButton.show();
		this.deleteButton.observe(Mojo.Event.tap, this.deleteAccount.bind(this));
	},
	
	deleteAccount: function (e) {
		this.controller.showAlertDialog({
			onChoose: this.handleDeleteAccount.bind(this),
			title: $L("Remove Account"),
			message: $L("Are you sure you want to remove this Contact account, and all linked data, from this device?"),
            choices: [{label: $L("Remove contact account"), value: true, type: 'negative'}, 
			{label: $L("Keep contact account"), value: false}]
		});
	},
	
	handleDeleteAccount: function (toDelete) {
		if (!toDelete) {
			this.deleteButton.mojo.deactivate();
			return;
		}
		this.deleteButton.mojo.activate();
		this.deleteButtonModel.buttonLabel = $L("Removing Account...");
		this.deleteButtonModel.disabled = true;
		this.controller.modelChanged(this.deleteButtonModel);
		AppAssistant.accountsService.removeService(this.controller, this.acctId, function () {
			this.controller.stageController.popScenesTo("prefs");
		}.bind(this));
	},
	
	handleLoginButtonTap: function (event) {
		this.loginHandler();
	},
	
	handleKeyUp: function (event) {
		// If the password field has focus and Enter is pressed then simulate tapping on "Sign In"
		if (event && Mojo.Char.isEnterKey(event.originalEvent.keyCode)) {
			// If the submit button is enabled then create the account
			if (this.buttonModel.disabled === false) {
				this.passwordField.blur();
				this.loginHandler();
				Event.stop(event);
			} else {
				this.usernameField.mojo.focus();
			}
		}
	},
	
	handlePasswordPropertyChange: function () {
		if (this.passwordChanged === false) {
			this.passwordPropertyChangeHandlerStopped = true;
			this.controller.stopListening("Password", Mojo.Event.tap, this.passwordTapHandler);
		}
		this.passwordChanged = true;
	},
	
	activate: function () {
		if (this.focusWindow) {
			this.controller.stageController.activate();
			this.focusWindow = false;
		}
		if (this.acctId === 0) {
			// Add New Account
			this.loginHandler = this.createAccount.bind(this);
		} else {
			// Edit Account
			this.loginHandler = this.updateAccount.bind(this);
		}
		this.loginButtonHandler = this.handleLoginButtonTap.bindAsEventListener(this);
		this.loginBtn.observe(Mojo.Event.tap, this.loginButtonHandler);
		this.keyUpHandler = this.handleKeyUp.bindAsEventListener(this);
		Mojo.Event.listen(this.controller.sceneElement, Mojo.Event.keyup, this.keyUpHandler, true);
	},
	
	deactivate: function () {
		this.loginBtn.stopObserving(Mojo.Event.tap, this.loginButtonHandler);
		Mojo.Event.stopListening(this.controller.sceneElement, Mojo.Event.keyup, this.keyUpHandler, true);
	},
	
	cleanup: function () {
		if (this.acctId !== 0) {
			if (this.passwordPropertyChangeHandlerStopped === undefined) {
				this.controller.stopListening("Password", Mojo.Event.propertyChange, this.passwordPropertyChangeHandler);
			}
		
			if (this.passwordTapHandlerStopped === undefined) {
				this.controller.stopListening("Password", Mojo.Event.tap, this.passwordTapHandler);
			}
		}
	},
	
	cleanup: function () {
		clearTimeout(this.timer);
	},
	
	loginCallbackEas: function (response) {
		// normalize the mail/setEasCredentials response into what pimsync/updateAccountCredentials returns
		var normalized = {};
		if (response.returnValue === true) {
			normalized.success = true;
		} else {
			normalized.success = false;
			normalized.errorMessage = response.errorCode;
		}
		this.loginCallback(normalized);
	},
	
	loginCallback: function (response) {
		Mojo.Log.info("accountlogin-assistant: loginCallback");
		var sController = this.controller.stageController;
		
		// The request has already been executed
		this.request = undefined;
		this.hideSpinner();
		
		if (response.success === true) {
			Form.disable(this.controller.get("AccountLoginForm"));
			for (var i = 0; i < this.numberOfTimesToPopScene; i++) {
				sController.popScene();
			}
		} else {
			// Login failed so we need to display the error message
			var msgStrs = {
				"AcctMgr_Network_Error" : $L("Could not connect to the server. Try again."),
				"AcctMgr_Bad_Username": $L("Username is incorrect. Try again."),
				"AcctMgr_Bad_Password": $L("Password is incorrect. Try again."),
				"AcctMgr_Bad_Authentication": $L("The username or password is incorrect. Try again."),
				"AcctMgr_Generic_Error": $L("Sign in failed. Try again."),
				"AcctMgr_Account_Locked": $L("Account locked."),
				"AcctMgr_Acct_Already_Exists": $L("Account already exists."),
				"AcctMgr_Acct_Not_Created": $L("Account not created."),
				"AcctMgr_No_Setup_Service": $L("No setup service.")    
			};
			
			var errorMsg = $L('Login failed.');
			
			if (response.errorMessage && msgStrs[response.errorMessage]) {
				errorMsg = msgStrs[response.errorMessage];
			}
			//How do we know that this is an error on our side?  It could be that their server is down
			if (response.errorMessage === "AcctMgr_Network_Error") {
                var showWifiManager = function () {
                    var params = {
                        type: "data",
                        onSuccess: function (resp) {}.bind(this),
                        onFailure: function (resp) {}.bind(this)
                    };
                    ConnectionWidget.connect(params, this.controller.stageController);
                }.bind(this);
				
				this.controller.serviceRequest("palm://com.palm.connectionmanager", {
					method: "getstatus",
					onSuccess: function (resp) {
						if (resp.isInternetConnectionAvailable) {
							this.showErrorMessage($L("Unable to connect.  Try again."));
						} else {
							this.showErrorMessage($L("No Internet Connection"));
							showWifiManager();
						}
					}.bind(this)
				});
				return;
				
			}
			this.showErrorMessage(errorMsg);
			
			if (response.errorMessage === "AcctMgr_Bad_Username") {
				// If the username was bad, add error class to Username label
				this.controller.get("UsernameLabel").addClassName("error");
				this.controller.get("PasswordLabel").removeClassName("error");
			} else if (response.errorMessage === "AcctMgr_Bad_Password") {
				// If the password was bad, add error class to Password label
				// Change the label to the button
				this.controller.get("PasswordLabel").addClassName("error");
				this.controller.get("UsernameLabel").removeClassName("error");
			}
		}
	},
	
	hideSpinner: function () {
		this.buttonModel.disabled = false;
		this.buttonModel.buttonLabel = $L("Sign in");
		this.controller.modelChanged(this.buttonModel);
		this.loginBtn.mojo.deactivate();
	},
	
	showSpinner: function () {
		// Disable the Sign In button
		this.buttonModel.disabled = true;
		this.buttonModel.buttonLabel = $L("Signing in...");
		this.controller.modelChanged(this.buttonModel);
		this.loginBtn.mojo.activate();
	},
	
	createAccount: function () {
		// Reset the error message
		this.hideErrorMessage();
		this.showSpinner();
		this.request = this.pimSyncService.saveAccount(this.controller, this.accountModel.username, this.accountModel.password, this.acctTypeId, this.loginCallback.bind(this));
	},
	
	updateAccount: function () {
		// Reset the error message
		this.hideErrorMessage();
		if (!this.passwordChanged) {
			// The password didn't change so we don't need to do anything
			// Call the callback which will pop this scene
			this.loginCallback({success: true});
			return;
		}
		
		if (!this.validateEntry()) {
			this.hideSpinner();
			return;
		}
		
		this.showSpinner();
		
		if (this.acctDomain === 'eas') {
			var cb = this.loginCallbackEas.bind(this);
			this.request = this.controller.serviceRequest('palm://com.palm.mail', {
				method: 'setEasCredentials',
				parameters: { account: this.acctId, login: this.accountModel.username, password: this.accountModel.password },
				onSuccess: cb,
				onFailure: cb
			});
		} else {
            this.request = this.pimSyncService.updateAccountCredentials(this.controller, this.acctId, this.accountModel.username, this.accountModel.password, this.loginCallback.bind(this));
		}
		
	},
	
	showErrorMessage: function (msg) {
		var msgObj = {errorMsg: msg};
		var html = Mojo.View.render({object: msgObj, template: 'accountlogin/accountlogin-error-msg'});
		var login_error_div = this.controller.get('login_error');
		login_error_div.update(html);
		login_error_div.show();
	},
	
	hideErrorMessage: function (msg) {
		var login_error_div = this.controller.get('login_error');
		login_error_div.hide();
	},
	
	validateEntry: function () {
		this.controller.get("UsernameLabel").removeClassName("error");
		this.controller.get("PasswordLabel").removeClassName("error");
		
		var username = this.accountModel.username;
		var password = this.accountModel.password;
		if (!username || !password) {
			if (!username && !password) {
				this.showErrorMessage($L("Please enter a username and password"));
			} else if (!username) {
				this.showErrorMessage($L("Please enter a username"));
			} else if (!password) {
				this.showErrorMessage($L("Please enter a password"));
			}
			
			if (!username) {
				// If the username was bad, add error class to Username label
				this.controller.get("UsernameLabel").addClassName("error");
			}
			if (!password) {
				// If the password was bad, add error class to Password label
				// Change the label to the button
				this.controller.get("PasswordLabel").addClassName("error");
			}
			return false;
		}
		return true;
	},
	
	// *** WIDGET ATTRS AND MODELS ***
	spinnerAttrs: {
		spinnerSize: 'small'
	},

	spinnerModel: {
		spinning: false
	}
});
