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

// Table of Contents:
// PinAssistant (entry point)
// SetPinAssistant
// PasswordAssistant
// SetPasswordAssistant

var PinAssistant = Class.create({
	MAX_PIN_LENGTH: 29, // max length of the PIN
	KEY_MAP: {
		e:'1',r:'2',t:'3',
		d:'4',f:'5',g:'6',
		x:'7',c:'8',v:'9',
			'@':'0',
		
		1:'1',2:'2',3:'3',
		4:'4',5:'5',6:'6',
		7:'7',8:'8',9:'9',
			  0:'0'
	},
	// utility helper
	numberToWord : function(number){
		return [$L('Zero'),$L('One'),$L('Two'), $L('Three'),$L('Four'),$L('Five'),$L('Six'),$L('Seven'),$L('Eight'),$L('Nine')][number];
	},
	initialize: function() {
		this.appControl = Mojo.Controller.getAppController();
		this.appAssistant = this.appControl.assistant;
		this.saveCurrentState = null;
		this.pinSceneSetup = false;
		this.onPinKeyPress = this.onPinKeyPress.bindAsEventListener(this);
	},
  	setup: function() {
		this.pinModel = {
			pin: '',
			disabled: true
		};
		
		this.controller.setupWidget('pinfield', {
			modelProperty: 'pin'
		}, this.pinModel);
		
		// listen for changes to the lock mode
		this.deviceModeRq = TelephonyCommands.deviceLockModeSubscribe(this.onDeviceLockModeChanged.bind(this));
  	},
	cleanup: function() {
		if (this.deviceModeRq) {
			this.deviceModeRq.cancel();
			delete this.deviceModeRq;
		}
	},
	setupPinScene: function() {
		if ( this.pinSceneSetup ) {
			return;
		}
		this.pinSceneSetup = true;
		
		this.controller.get('pin-scene-wrapper').show();
		
		Mojo.listen(this.controller.sceneElement, Mojo.Event.keypress, this.onPinKeyPress);
				
		if (this.retriesLeft === 1) {
			this.controller.get('pin-title-small').innerHTML = $L("Entering an incorrect PIN will erase your phone");
			this.controller.showAlertDialog({
				choices:[
					{label:$L("OK"), type:'affirmative', value:'ok'}
				],
				title: $L("Warning"),
				message: $L("If you enter an incorrect PIN now your phone will be erased."),
				preventCancel: true
			});
		}
		
		this.controller.get('keypad_buttons').observe(Mojo.Event.tap, this.onButtonPress.bindAsEventListener(this));
		this.controller.get('done_pin').observe(Mojo.Event.tap, this.testPin.bindAsEventListener(this));
		this.controller.get('emergency').observe(Mojo.Event.tap, this.emergency.bind(this));
		
		// repeat delete action when button is held
		this.controller.get('delete_button')
			.observe(Mojo.Event.tap, function(event) {
				this.clearPinField(true);
			}.bindAsEventListener(this))
			.observe(Mojo.Event.hold, function(event) {
				this.deleteHoldTimer = this.controller.window.setInterval(function() {
					// WORKAROUND for bug when Mojo.Event.holdEnd never gets called
					if ( ! this.pinModel || this.pinModel.pin.length == 0 ) {
						this.controller.window.clearInterval(this.deleteHoldTimer);
					} else {
						this.clearPinField(true);
					}
				}.bind(this), 30);
			}.bindAsEventListener(this))
			.observe(Mojo.Event.holdEnd, function(event) {
				this.controller.window.clearInterval(this.deleteHoldTimer);
			}.bindAsEventListener(this));
	},
	cleanupPinScene: function() {
		if ( this.pinSceneSetup ) {
			Mojo.stopListening(this.controller.sceneElement, Mojo.Event.keypress, this.onPinKeyPress);
			this.controller.get('pin-scene-wrapper').hide();
		}
	},
	onButtonPress: function(event) {
		var digit = Mojo.View.findParentByAttribute(event.element(), this.controller.get('keypad_buttons'), "x-phone-digit");
		if (digit) {
			this.addToPinField(digit.readAttribute("x-phone-digit"));
		}
	},
	onPinKeyPress: function(event) {
		var code = event.originalEvent.keyCode;
		if (Mojo.Char.isDeleteKey(code)) {
			this.clearPinField(true);
		}
		else if (Mojo.Char.isEnterKey(code)) {
			this.testPin();
		}
		else {
			var translated_key = this.KEY_MAP[String.fromCharCode(code).toLowerCase()];
			if (translated_key) {
				this.addToPinField(translated_key);
			}
		}
	},
	clearPinField: function(only_delete_last) {
		this.pinModel.pin = only_delete_last === true ? this.pinModel.pin.replace(/.$/,'') : '';
		this.controller.modelChanged(this.pinModel, this);
	},
	addToPinField: function( digit ) {
		if (this.pinModel.pin.length < this.MAX_PIN_LENGTH) {
			this.pinModel.pin += digit;
			this.controller.modelChanged(this.pinModel, this);
		}
	},
	onDeviceLockModeChanged: function(response) {		
		//DEBUG
		//Object.extend(response,{"retriesLeft": 1}); // {"returnValue": true, "subscribed": true, "lockMode": "password", "policyState": "active", "retriesLeft": 1}
		//response.policyState = "pending"
		
		Mojo.Log.info("PinAssistant#onDeviceLockModeChanged: %j",response);
		
		try {
			var handleLockMode = function(response) {
				this.retriesLeft = response.retriesLeft;
				
				switch (response.lockMode) {
					case "pin":
						this.mode = "pin";						
						this.setupPinScene();
						this.appAssistant.screenLockSecured = this.appAssistant.screenLocked = true;
						break;
						
					case "password":
						this.mode = "password";
						this.cleanupPinScene();
												
						this.controller.stageController.pushScene({
							name: 'password',
							transition: Mojo.Transition.none,
							sceneTemplate: 'pin/password-scene',
							assistantConstructor: PasswordAssistant
						}, this);
						this.appAssistant.screenLockSecured = this.appAssistant.screenLocked = true;
						break;
						
					case "none":
						this.mode = "none";
						if (this.appAssistant.securityPolicyState === "pending") {
							this.showDevicePasswordRequiredDialog();
						}
						break;
						
					default:
						this.mode = "";
						this.appAssistant.screenLockSecured = false;
						break;
				}
			}.bind(this,response);
			
			// Get the Security Policy Status
			if (response.policyState) {
				this.appAssistant.securityPolicyState = response.policyState;
				
				if (this.appAssistant.securityPolicyState === "pending") {
					//Screen is locked due to Pending Security Policy.
					this.appAssistant.screenLocked = true;
					//Get the Security Policy
					this.getSecurityPolicyReq = new Mojo.Service.Request('palm://com.palm.systemmanager', {
						method: 'getSecurityPolicy',
						onSuccess: function(policy_response) {
							this.pendingSecurityPolicy = policy_response.policy;
							handleLockMode(response);
						}.bind(this),
						onFailure: function() {
							Mojo.Log.error("getSecurityPolicy called when no policy exists");
						}
					});
				}
			}
			
			if ( ! this.getSecurityPolicyReq ) {
				handleLockMode(response);
			}
		} catch (e) {
			Mojo.Log.error( "PhoneApp: PinAssistant#onDeviceLockModeChanged CAUGHT EXCEPTION: %j" , e);
		}
	},
	// Guaranteed to be called only when a more restrictive security policy is pending (and this.pendingSecurityPolicy is populated)
	showDevicePasswordRequiredDialog: function() {
		this.saveCurrentState = this.showDevicePasswordRequiredDialog.bind(this);
		
		//DEBUG
		//this.pendingSecurityPolicy = {"password": {"enabled": true, "minLength": 2, "maxRetries": 0, "alphaNumeric": false}, "inactivityInSeconds": 600, "id": "", "status": {"enforced": true, "retriesLeft": 0}};
		
		// if active call, show dialog instead
		if (this.appAssistant.telephonyEventListener.callExists()) {
			this.controller.showAlertDialog({
				choices:[
					{label:$L("OK"), type:'affirmative', value:'ok'}
				],
				onChoose: function(value) {
					this.appAssistant.showLockScreenActiveCall();
				}.bind(this),
				message: $L("A new security policy has been implemented for your Exchange ActiveSync account.  When you end the call, you will be able to change your password."),
				preventCancel: true
			});
			return;
		}
		
		var choices = [];
		choices.push({label:$L('Set Password'), value:"set_password", type:'affirmative'});
		// offer PIN only when EAS policy allows for it
		if ( this.pendingSecurityPolicy.password.alphaNumeric === false ) {
			choices.push({label:$L("Set PIN"), value:"set_pin", type:'affirmative'});
		}
		choices.push({label:$L("Emergency Call"), value:"emergency"});
		
		this.controller.showAlertDialog({
			onChoose: function(value) {
				if ("set_password" === value) {
					this.showSetPasswordScene();
				}
				else if ("set_pin" === value) {
					this.showSetPinScene();
				}
				else if ("emergency" === value) {
					this.emergencyDial();
				}
			}.bind(this),
			title: (this.mode === "none" ? $L("Device Password Required") : $L("Device Password Upgrade Required")),
			message: (this.pendingSecurityPolicy.password.alphaNumeric === false 
						? $L("A security policy has been implemented for your Exchange ActiveSync account. You must set a password or PIN to continue using it.")
						: $L("A security policy has been implemented for your Exchange ActiveSync account. You must set a password to continue using it.")),
			choices: choices,
			preventCancel: true
		});
	},
	showSetPasswordScene: function() {
		//this.saveCurrentState = this.showSetPasswordScene.bind(this);	
		this.controller.stageController.pushScene({
			name: 'SetPassword',
			transition: Mojo.Transition.none,
			sceneTemplate: 'pin/setpassword-scene',
			automaticFocusAdvance: false // so we can capture the 'return' key using Mojo.Event.keypress on the sceneElement
		}, this);
	},
	showSetPinScene: function() {
		var subtitle = SetPinAssistant.defaultMessageForPolicy(this.pendingSecurityPolicy);		
		this.controller.stageController.pushScene({
			name: "SetPin",
			sceneTemplate: "pin/pin-scene",
			transition: Mojo.Transition.none,
			automaticFocusAdvance: false // so we can capture the 'return' key using Mojo.Event.keypress on the sceneElement
		}, this, $L("Enter PIN"), subtitle);
	},
	aboutToActivate: function(callback) {
		if (this.saveCurrentState) {
			this.saveCurrentState();
		}
		
		callback();
	},
	activate: function(cb) {
		if ( Object.isFunction(cb) ) {
			cb();
		}
	},
	// tells systemmanager to cancel attempt; if there's an active call, we pop to it
	cancel: function(event) {
		this.clearPinField();
		if (this.appAssistant.telephonyEventListener.callExists()) {
			this.appAssistant.showLockScreenActiveCall();
		}
		else {
			new Mojo.Service.Request('palm://com.palm.systemmanager', {
				method: 'updatePinAppState',
				parameters: {state: 'cancel'}
			});
		}
		
		if ( event ) {
			event.stop();
		}
	},
	emergency: function() {
		this.controller.popupSubmenu({
  			onChoose: function(value) {
				if ( "emergency" === value ) {
					this.emergencyDial();
				}
			},
  			placeNear: this.controller.get('emergency_menu_anchor'),
			items: [
				{label: $L('Emergency call'), command: 'emergency'}, 
				{label: $L('Cancel'), command: 'cancel'}
			]
		});
	},
	emergencyDial: function() {
		this.appAssistant.showLimitedDialpad(this.controller.stageController, {
			"action": "fill",
			"number": PlatformType.getDefaultEmergencyNumber()
		});
	},
	testPin: function() {
		if ( ! this.testPinRequest && this.pinModel.pin !== '' ) {		
			// we will only allow 3 bad attempts before placing a lock
			this.testPinRequest = new Mojo.Service.Request('palm://com.palm.systemmanager', {
				method: 'matchDevicePasscode',
				parameters: {
					passCode: this.pinModel.pin
				},
				onSuccess: this.onTestPinSuccess.bind(this),
				onFailure: this.onTestPinFailure.bind(this),
				onComplete: function() {
					delete this.testPinRequest;
				}.bind(this)
			});
		}
	},
	onTestPinSuccess: function(response) {
		this.cleanupPinScene();
		
		if (this.appAssistant.securityPolicyState === "pending") {
			//Show Device Password Required Dialog.
			this.showDevicePasswordRequiredDialog();
		}
		else {
			this.unlock();
		}
	},
	onTestPinFailure: function(response) {
		this.clearPinField();
		
		if (this.appAssistant.securityPolicyState === "active" && response.retriesLeft > 0) {
			this.controller.get('pin-title-big').innerHTML = $L('PIN Incorrect');
			// Show Last Chance Warning Message
			if (response.retriesLeft === 1) {
				this.controller.get('pin-title-small').innerHTML = $L("Entering an incorrect PIN will erase your phone");
				this.controller.showAlertDialog({
					choices:[
						{label:$L("OK"), type:'affirmative', value:'ok'}
					],
					title: $L("Warning"),
					message: $L("Password incorrect. If you enter an incorrect PIN now your phone will be erased."),
					preventCancel: true
				});
			}
			else {
				this.controller.get('pin-title-small').innerHTML = Mojo.Format.formatChoice(response.retriesLeft, $L("1##{num} try remaining.|##{num} tries remaining."), {
																		num: this.numberToWord(response.retriesLeft)
																	});
			}
		}
		else {
			if (response.lockedOut) {
				this.controller.get('pin-title-big').innerHTML = $L('Phone Locked');
				this.controller.get('pin-title-small').innerHTML = $L('Try Again Later');
			}
			else {
				this.controller.get('pin-title-big').innerHTML = $L('PIN Incorrect');
				this.controller.get('pin-title-small').innerHTML = $L('Try Again');
			}
		}
	},
	unlock: function() {
		new Mojo.Service.Request('palm://com.palm.systemmanager', {
			method: 'updatePinAppState',
			parameters: {state: 'unlock'}
		});
		
		this.appAssistant.screenLocked = false;
		
		/*if (this.appAssistant.telephonyEventListener.callExists()) {
			this.appAssistant.popLockScreenActiveCall();
		}*/
	},
	// Prevent Back Swipe when there is an active call and password/pin scene launched from Active call - unlock button.
	handleCommand: function(event) {
		if (event.type == Mojo.Event.back && ! this.appAssistant.telephonyEventListener.callExists() ) {
			event.stop();
			this.cancel();
		}
	}
});


var PasswordAssistant = Class.create({
	initialize: function(sceneAssistant) {
		this.sceneAssistant = sceneAssistant;
	},
	setup: function() {		
		this.controller.setupWidget('password_input', {
			autoFocus: true,
			requiresEnterKey: true,
			enterSubmits: true,
			preventResize: true
     	}, {});
		this.controller.setupWidget('emergency', {}, {
			buttonLabel : $L("Emergency Call")
		});
		this.controller.setupWidget('done', {}, {
			buttonLabel : $L("Done"),
			buttonClass: "affirmative"
		});
				
		// widget handlers
		this.controller.get('password_input').addEventListener(Mojo.Event.propertyChange, this.passwordPropertyChanged.bindAsEventListener(this));
   		this.controller.get('done').addEventListener(Mojo.Event.tap, this.testPassword.bindAsEventListener(this));
		this.controller.get('emergency').addEventListener(Mojo.Event.tap, this.emergency.bind(this));
		
		if (this.sceneAssistant.retriesLeft === 1) {
			this.controller.get('password-error').show();
			this.controller.get('error-text').innerHTML = $L("If you enter an incorrect password now your phone will be erased.");
		}
	},
	activate: function() {
		// focus when coming back from emergency call scene (workaround for NOV-90567)
		this.controller.get('password_input').mojo.focus();
	},
	passwordPropertyChanged: function(event) {
		if ( Mojo.Char.isEnterKey(event.originalEvent.keyCode) ) {
			this.testPassword(event);
		}
	},
	emergency: function() {
		this.controller.popupSubmenu({
  			onChoose: function(value) {
				if ( "emergency" === value ) {
					this.sceneAssistant.appAssistant.showLimitedDialpad(this.controller.stageController, {
						"action": "fill",
						"number": PlatformType.getDefaultEmergencyNumber()
					});
				}
			},
  			placeNear: this.controller.get('emergency_menu_anchor'),
			items: [
				{label: $L('Emergency call'), command: 'emergency'}, 
				{label: $L('Cancel'), command: 'cancel'}
			]
		});
	},
	testPassword: function(event) {	
		if (! this.testPasswordRequest) {
			this.testPasswordRequest = new Mojo.Service.Request('palm://com.palm.systemmanager', {
				method: 'matchDevicePasscode',
				parameters: {
					passCode: this.controller.get('password_input').mojo.getValue()
				},
				onSuccess: this.onTestPasswordSuccess.bind(this),
				onFailure: this.onTestPasswordFailure.bind(this),
				onComplete: function() {
					this.controller.get('password_input').mojo.setText('');
					delete this.testPasswordRequest;
				}.bind(this)
			});
		}
	},
	onTestPasswordSuccess: function(response) {
		if (this.sceneAssistant.appAssistant.securityPolicyState === "pending") {
			this.controller.stageController.popScene(this.sceneAssistant.showDevicePasswordRequiredDialog.bind(this.sceneAssistant));
		}
		else {
			this.controller.get('password-error').hide();
			this.sceneAssistant.unlock();
		}
	},
	onTestPasswordFailure: function(response) {
		
		// CASE: active policy and not locked out
		if (this.sceneAssistant.appAssistant.securityPolicyState === "active" && response.retriesLeft > 0) {
			
			// CASE: last chance, show warning dialog
			if (response.retriesLeft === 1) {
				this.controller.get('error-text').innerHTML = $L("Password incorrect. If you enter an incorrect password now your phone will be erased.");
				this.controller.showAlertDialog({
					choices:[
						{label:$L("OK"), type:'affirmative', value:'ok'}
					],
					title: $L("Warning"),
					message: $L("Password incorrect. If you enter an incorrect password now your phone will be erased."),
					preventCancel: true
				});
			}
			// CASE: (n) retries left
			else {
				this.controller.get('error-text').innerHTML = $L("Password incorrect. ") + Mojo.Format.formatChoice(response.retriesLeft, 
																$L("1##{num} try remaining.|##{num} tries remaining."),{ num: this.sceneAssistant.numberToWord(response.retriesLeft) });
			}
		}
		// CASE: No Active Policy or locked out
		else {
			this.controller.get('error-text').innerHTML = response.lockedOut ? $L('Device Locked, Try Again Later') : $L('Wrong Password');
		}
		
		this.controller.get('password-error').show();
		this.controller.get('password_input').mojo.focus();
	},
	handleCommand: function(event) {
		if (event.type == Mojo.Event.back) {	
			event.stop();
			this.sceneAssistant.cancel();
		}
	}
});



var SetPinAssistant = Class.create({
	MAX_PIN_LENGTH: 29, // max length of the PIN
	KEY_MAP: {
		e:'1',r:'2',t:'3',
		d:'4',f:'5',g:'6',
		x:'7',c:'8',v:'9',
			'@':'0',
		
		1:'1',2:'2',3:'3',
		4:'4',5:'5',6:'6',
		7:'7',8:'8',9:'9',
			  0:'0'
	},
	initialize: function(sceneAssistant, title, subtitle, activeSubtitle, prevPin /*internal*/) {
		this.sceneAssistant = sceneAssistant;
		this.title = title;
		this.subtitle = subtitle;
		this.activeSubtitle = (! Object.isUndefined(activeSubtitle) ? activeSubtitle : this.subtitle); // subtitle when a number has been entered
		this.prevPin = prevPin;
		this.onPinKeyPress = this.onPinKeyPress.bindAsEventListener(this);
	},
	setup: function() {
		Mojo.listen(this.controller.sceneElement, Mojo.Event.keypress, this.onPinKeyPress);
		
		this.controller.get('pin-scene-wrapper').show();
		this.controller.get('pin-title-big').innerHTML = this.title;
		this.controller.get('pin-title-small').innerHTML = this.subtitle;
		
		this.pinModel = {
			pin: '',
			disabled: true
		};
		
		this.controller.setupWidget('pinfield', {
			modelProperty: 'pin'
		}, this.pinModel);
		
		this.controller.get('keypad_buttons').observe(Mojo.Event.tap, this.onButtonPress.bindAsEventListener(this));
		this.controller.get('done_pin').observe(Mojo.Event.tap, this.handleDone.bind(this));
		this.controller.get('emergency').observe(Mojo.Event.tap, this.emergency.bind(this));
		
		// repeat delete action when button is held
		this.controller.get('delete_button')
			.observe(Mojo.Event.tap, function(event) {
				this.clearPinField(true);
			}.bindAsEventListener(this))
			.observe(Mojo.Event.hold, function(event) {
				this.deleteHoldTimer = this.controller.window.setInterval(function() {
					// WORKAROUND for bug when Mojo.Event.holdEnd never gets called
					if ( ! this.pinModel || this.pinModel.pin.length == 0 ) {
						this.controller.window.clearInterval(this.deleteHoldTimer);
					} else {
						this.clearPinField(true);
					}
				}.bind(this), 30);
			}.bindAsEventListener(this))
			.observe(Mojo.Event.holdEnd, function(event) {
				this.controller.window.clearInterval(this.deleteHoldTimer);
			}.bindAsEventListener(this));
	},
	cancel: function() {
		this.controller.stageController.popScene();
	},
	emergency: function() {
		this.controller.popupSubmenu({
  			onChoose: function(value) {
				if ( "emergency" === value ) {
					this.sceneAssistant.appAssistant.showLimitedDialpad(this.controller.stageController, {
						"action": "fill",
						"number": PlatformType.getDefaultEmergencyNumber()
					});
				}
			},
  			placeNear: this.controller.get('emergency_menu_anchor'),
			items: [
				{label: $L('Emergency call'), command: 'emergency'}, 
				{label: $L('Cancel'), command: 'cancel'}
			]
		});
	},
	handleDone: function () {
		if ( this.pinModel.pin !== '' ) {
			// first time entering PIN: send to 'Enter PIN Again' scene
			if ( ! this.prevPin ) {
				SetPinAssistant.swapSceneWithParams(this.controller.stageController, this.sceneAssistant, $L("Enter PIN Again"), "", "", this.pinModel.pin);
			}
			// has been called before: verify
			else {
				// PINs don't match: start over
				if ( this.prevPin !== this.pinModel.pin ) {
					var activesubtitle = SetPinAssistant.defaultMessageForPolicy(this.sceneAssistant.pendingSecurityPolicy);
					SetPinAssistant.swapSceneWithParams(this.controller.stageController, this.sceneAssistant, $L("Enter PIN"), $L("PIN doesn't match"), activesubtitle);
				}
				// unlock
				else {
					new Mojo.Service.Request('palm://com.palm.systemmanager', {
						method: 'setDevicePasscode',
						parameters: {
							passCode: this.pinModel.pin,
							lockMode: "pin"
						},
						onSuccess: this.sceneAssistant.unlock.bind(this.sceneAssistant),
						onFailure: function() {
							var activesubtitle = SetPinAssistant.defaultMessageForPolicy(this.sceneAssistant.pendingSecurityPolicy);
							SetPinAssistant.swapSceneWithParams(this.controller.stageController, this.sceneAssistant, $L("Enter PIN"), $L("PIN does not match security requirements"), activesubtitle);
						}.bind(this)
					});
				}
			}
		}
	},
	cleanup: function() {
		Mojo.stopListening(this.controller.sceneElement, Mojo.Event.keypress, this.onPinKeyPress);
	},
	onButtonPress: function(event) {
		var digit = Mojo.View.findParentByAttribute(event.element(), this.controller.get('keypad_buttons'), "x-phone-digit");
		if (digit) {
			this.addToPinField(digit.readAttribute("x-phone-digit"));
		}
	},
	clearPinField: function(only_delete_last) {
		this.pinModel.pin = only_delete_last === true ? this.pinModel.pin.replace(/.$/,'') : '';
		this.controller.modelChanged(this.pinModel, this);
	},
	addToPinField: function( digit ) {
		if (this.pinModel.pin.length < this.MAX_PIN_LENGTH) {
			this.pinModel.pin += digit;
			this.controller.modelChanged(this.pinModel, this);
			this.controller.get('pin-title-small').innerHTML = this.activeSubtitle;
		}
	},
	onPinKeyPress: function(event) {
		var code = event.originalEvent.keyCode;
		if (Mojo.Char.isDeleteKey(code)) {
			this.clearPinField(true);
		}
		else if (Mojo.Char.isEnterKey(code)) {
			this.testPin();
		}
		else {
			var translated_key = this.KEY_MAP[String.fromCharCode(code).toLowerCase()];
			if (translated_key) {
				this.addToPinField(translated_key);
			}
		}
	},
	handleCommand: function(event) {
		if (event.type == Mojo.Event.back) {	
			event.stop();
			this.cancel();						
		}
	}
});

// static method returns the default subtitle given a security policy
SetPinAssistant.defaultMessageForPolicy = function(policy) {
	return Mojo.Format.formatChoice(policy.password.minLength, $L("1>#PIN must be at least #{minLength} numbers|#"), policy.password);
};

// static method creates a new SetPinAssistant scene
SetPinAssistant.swapSceneWithParams = function(stageController, sceneAssistant, title, subtitle, activesubtitle, prevPin) {
	stageController.swapScene({
		name: "SetPin",
		sceneTemplate: "pin/pin-scene",
		transition: Mojo.Transition.none,
		automaticFocusAdvance: false // so we can capture the 'return' key using Mojo.Event.keypress on the sceneElement
	}, sceneAssistant, title, subtitle, activesubtitle, prevPin);
};


var SetPasswordAssistant = Class.create({
	initialize: function(sceneAssistant) {
		this.sceneAssistant = sceneAssistant;
		this.policy = this.sceneAssistant.pendingSecurityPolicy;
		this.settingPassword = false;
	},
	setup: function() {
		this.controller.setupWidget('password_input', {
			changeOnKeyPress: true,
			hintText: $L('enter password...')
		},{});
		this.controller.setupWidget('password_confirm', {
			changeOnKeyPress: true,
			requiresEnterKey: true,
			hintText: $L('confirm password...')
		},{});
		this.controller.setupWidget('done', {}, this.donebuttonmodel = {
			buttonLabel : $L("Done"),
			buttonClass: "affirmative"
		});
		this.controller.setupWidget('cancel', {}, this.cancelbuttonmodel = {
			buttonLabel: $L('Cancel')
		});
		
		this.controller.get('password_input').addEventListener(Mojo.Event.propertyChange, this.passwordPropertyChanged.bindAsEventListener(this));
		this.controller.get('password_confirm').addEventListener(Mojo.Event.propertyChange, this.confirmPasswordPropertyChanged.bindAsEventListener(this));
   		this.controller.get('done').addEventListener(Mojo.Event.tap, this.verifyPassword.bindAsEventListener(this));
		this.controller.get('cancel').addEventListener(Mojo.Event.tap, this.cancel.bindAsEventListener(this));
		
		if ( this.policy.password.alphaNumeric === true ) {
			this.controller.get('passwordhint').innerHTML = Mojo.Format.formatChoice(this.policy.password.minLength, $L("1>#Password must be #{minLength} or more characters long and contain both numbers and letters.|#Password must contain both numbers and letters."), this.policy.password);
		}
		else {
			this.controller.get('passwordhint').innerHTML = Mojo.Format.formatChoice(this.policy.password.minLength, $L("1>#Password must be #{minLength} or more characters long.|#"), this.policy.password);
		}
		this.controller.get('setpassword-title').innerHTML = (this.sceneAssistant.mode === "password" ? $L("Change Password") : $L("Set Password"));
	},
	verifyPassword: function(event) {
		event.stop();
		
		var password1 = this.controller.get('password_input').mojo.getValue();
		var password2 = this.controller.get('password_confirm').mojo.getValue();
		if (password1 == password2) {
			this.settingPassword = true;
			this.donebuttonmodel.disabled = true;
			this.cancelbuttonmodel.disabled = true;
			this.controller.modelChanged(this.donebuttonmodel);
			this.controller.modelChanged(this.cancelbuttonmodel);
			
			new Mojo.Service.Request('palm://com.palm.systemmanager', {
				method: 'setDevicePasscode',
				parameters: {
					passCode: password1,
					lockMode: "password"
				},
				onSuccess: function() {
					this.sceneAssistant.unlock();
				}.bind(this),
				onFailure: function() {
					this.controller.get('error-text').innerHTML = $L("Password does not match security requirements.");
					this.controller.get('password-error').show();
				}.bind(this),
				onComplete: function() {
					this.clearFields();
					this.settingPassword = false;
					this.donebuttonmodel.disabled = false;
					this.cancelbuttonmodel.disabled = false;
					this.controller.modelChanged(this.donebuttonmodel);
					this.controller.modelChanged(this.cancelbuttonmodel);
				}.bind(this)
			});
		}
		else {
			this.clearFields();
			this.controller.get('error-text').innerHTML = $L("Passwords do not match.");
			this.controller.get('password-error').show();
		}
	},
	passwordPropertyChanged: function(event) {
		if ( Mojo.Char.isEnterKey(event.originalEvent.keyCode) ) {
			this.controller.get('password_confirm').mojo.focus();
		}
	},
	confirmPasswordPropertyChanged: function(event) {
		if ( Mojo.Char.isEnterKey(event.originalEvent.keyCode) ) {
			this.verifyPassword(event);
		}
	},
	cancel: function(event) {
		this.controller.stageController.popScene();
	},
	clearFields: function() {
		this.sceneAssistant.controller.get('password_input').mojo.setText('');
		this.sceneAssistant.controller.get('password_input').mojo.focus();	
		this.sceneAssistant.controller.get('password_confirm').mojo.setText('');
	},
	handleCommand: function(event) {
		if (event.type == Mojo.Event.back) {	
			if (! this.settingPassword ) {
				this.cancel(event);
			}
			else {
				event.stop();
			}
		}
	}
});