var DialpadAssistant = Class.create({
	
	DIAL_PREFIX_DELAY: 750, // ms to wait before adding dialing prefix when typing numbers
	
	dialFailureNoService: 3,
	dialFailureFDNRestricted: 4,
	dialFailurePIN1Lock: 7,
	dialFailurePUK1Lock: 8,
	dialFailureSIMlock: 9,
	dialFailureOTASP: 10,
	
	mslFailures: 0,
	mslFailuresMax: 15,
	
		// keys without opt
	
	keyMaps :{
		QWERTY: {
			normal: $H({
				'U+0065':'1',
				'U+0072':'2',
				'U+0074':'3',
				'U+0064':'4',
				'U+0066':'5',
				'U+0067':'6',
				'U+0078':'7',
				'U+0063':'8',
				'U+0076':'9',
				'U+0040':'0',
				'U+0077':'+', // send w as +  
				'U+007A':'*',
				'U+0062':'#',
				'U+0070':'p'
			}),
			opt: $H({
				'U+0031':'1',
				'U+0032':'2',
				'U+0033':'3',
				'U+0034':'4',
				'U+0035':'5',
				'U+0036':'6',
				'U+0037':'7',
				'U+0038':'8',
				'U+0039':'9',
				'U+0030':'0',
				'U+002A':'*',
				'U+0023':'#', 
				'U+002B':'+'
			})
		},
		QWERTZ: {
			normal: $H({
				'U+0065':'1',
				'U+0072':'2',
				'U+0074':'3',
				'U+0064':'4',
				'U+0066':'5',
				'U+0067':'6',
				'U+0078':'7',
				'U+0063':'8',
				'U+0076':'9',
				'U+0040':'0',
				'U+0077':'+', // send w as +  
				'U+0079':'*',
				'U+0062':'#',
				'U+0070':'p'
			}),
			opt: $H({
				'U+0031':'1',
				'U+0032':'2',
				'U+0033':'3',
				'U+0034':'4',
				'U+0035':'5',
				'U+0036':'6',
				'U+0037':'7',
				'U+0038':'8',
				'U+0039':'9',
				'U+0030':'0',
				'U+002A':'*',
				'U+0023':'#', 
				'U+002B':'+'
			})
			
		},
		
		AZERTY: {
			normal: $H({
				'U+0065':'1',
				'U+0072':'2',
				'U+0074':'3',
				'U+0064':'4',
				'U+0066':'5',
				'U+0067':'6',
				'U+0078':'7',
				'U+0063':'8',
				'U+0076':'9',
				'U+0040':'0',
				'U+007A':'+', // send z as +  
				'U+0077':'*',
				'U+0062':'#',
				'U+0070':'p'
			}),
			opt: $H({
				'U+0031':'1',
				'U+0032':'2',
				'U+0033':'3',
				'U+0034':'4',
				'U+0035':'5',
				'U+0036':'6',
				'U+0037':'7',
				'U+0038':'8',
				'U+0039':'9',
				'U+0030':'0',
				'U+002A':'*',
				'U+0023':'#', 
				'U+002B':'+'
			})
			
		}
	},
	
	keyMap: $H({
		'U+0065':'1',
		'U+0072':'2',
		'U+0074':'3',
		'U+0064':'4',
		'U+0066':'5',
		'U+0067':'6',
		'U+0078':'7',
		'U+0063':'8',
		'U+0076':'9',
		'U+0040':'0',
		'U+0077':'+', // send w as +  
		'U+007A':'*',
		'U+0062':'#',
		'U+0070':'p'
	}),

	// keys with orange-blob held down
	keyMapOpt: $H({
		'U+0031':'1',
		'U+0032':'2',
		'U+0033':'3',
		'U+0034':'4',
		'U+0035':'5',
		'U+0036':'6',
		'U+0037':'7',
		'U+0038':'8',
		'U+0039':'9',
		'U+0030':'0',
		'U+002A':'*',
		'U+0023':'#', 
		'U+002B':'+'
	}),
    
	initialize: function(params) {
		QDLogger.log( "DialpadAssistant#initialize");
		this.redialContactParams = {};

		this.appControl = Mojo.Controller.getAppController();
		this.appAssistant = this.appControl.assistant;
		this.telListener = this.appAssistant.telephonyEventListener;
		this.announcer = this.appAssistant.announcer;
		this.contacts = this.appAssistant.contacts;
		this.stageController = Mojo.Controller.getAppController().getStageController("PhoneApp");
		this.speedDialString = "";
		this.dialString = "";
		// check for on-launch actions

        if (params && params.action) {
			this.launchParams = params;
		}
		
		this.inputNecessaryButtonsVisible = true;
		this.pickerVisible = false;
		
		this.handleKeyDown = this.handleKeyDown.bind(this);
		this.handleKeyUp = this.handleKeyUp.bind(this);
		this.handleTapWhenPickerOpen = this.handleTapWhenPickerOpen.bindAsEventListener(this);
		this.handleMousedownWhenPickerOpen = this.handleMousedownWhenPickerOpen.bindAsEventListener(this);
		this.onBlur =  this.onBlur.bind(this);
		this.hidePicker = this.hidePicker.bind(this);
		
		this.abridged = this.appAssistant.firstuse || (params && params.limited);
		this.dialingStopPrevent = this.dialingStopPrevent.bind(this);
		this.showOTASPRebootDelegate = this.showOTASPRebootDelegate.bind(this);
		this.initializeKeymap() ;
		
    },
    
	initializeKeymap: function() {
		var keymaps = this.keyMaps.QWERTY;
		var devInfo = Mojo.Environment.DeviceInfo;
		
		if (devInfo && devInfo.keyboardType) {
			switch (devInfo.keyboardType) {
				case Mojo.Environment.QWERTZ:
				case Mojo.Environment.QWERTZ_ACC:
					keymaps = this.keyMaps.QWERTZ;
					break;
				case Mojo.Environment.AZERTY:
				case Mojo.Environment.AZERTY_ACC:
					keymaps = this.keyMaps.AZERTY;
					break;
			}
		}
				
		this.keyMap = keymaps.normal;
		this.keyMapOpt = keymaps.opt;
	},
	
	handleSceneArgs: function(params) {
		if (!params)
			return;
		
		// dial number
		if (params.action == "dial") {
			QDLogger.log( "DialpadAssistant#handleSceneArgs", "dial: " , params.number);
			if (params.number) {
				this.dial(params.number)
			}
		// fill number
		} else if (params.action == "fill") {
			QDLogger.log( "DialpadAssistant#handleSceneArgs", "fill: " , params.number);
			// TODO: can't immediately set it if setup hasn't been finished since
			// formatAndUpdateDialString will change visibility only to have it undone by the rest of setup
			if (this.setupComplete) {
				this.clear();
				this.formatAndUpdateDialString(params.number);
			} else {
				this.prefill = params.number;
			}
		// call voicemail
		} else if (params.action == "voicemail") {
			QDLogger.log( "DialpadAssistant#handleSceneArgs", "voicemail");
			this.voicemailClick();
		} else if (params.action == "dialfail") {
			QDLogger.log( "DialpadAssistant#handleSceneArgs", "dialfail");
			this.dialFailure(params.result, params.number);
		}
		
	},
	
    setup: function(){
		QDLogger.log( "DialpadAssistant#setup");


		// if first use, change background, register this as a controller for dialogs
		if (this.appAssistant.firstuse === true) {
			this.controller.document.body.className = "firstuse";
		}  
		// any launch parameters hanging around? handle them and clear them
		if (this.launchParams) {
			this.handleSceneArgs(this.launchParams);
			this.launchParams = undefined;
		}
		
		// subscribe to lookup status changes
		this.telListener.lookupOnKeyPrefChangedCallback = this.hintTextUpdate.bind(this);
		this.hintTextUpdate();
		
		// hide buttons we need input for
    	this.disableInputNecessaryButtons();
		
		// bind to dialpad number buttons
		var that = this;
		['b_1', 'b_2', 'b_3', 'b_4', 'b_5', 'b_6', 'b_7', 
			'b_8', 'b_9', 'b_0', 'b_*', 'b_#'].each(function(key) {
			var button = that.controller.get(key);
			button.observe('mousedown', that.numberClick.bindAsEventListener(that, key.charAt(2)));
            button.observe(Mojo.Event.hold, that.handleHeldKey.bindAsEventListener(that, key.charAt(2)));
		});
		
		// other dialpad area buttons
		this.controller.get('dial_button').observe(Mojo.Event.tap, this.dialClick.bindAsEventListener(this));
        this.controller.get('delete_button').observe(Mojo.Event.tap, this.back.bindAsEventListener(this));
	    this.controller.get('delete_button').observe(Mojo.Event.hold, this.clear.bindAsEventListener(this));
				
		// bind menu buttons
		// bind only cancel in first use; everything else otherwise
		if (this.abridged === true) {
			this.controller.get('emergency_cancel_button').observe(Mojo.Event.tap, this.abridgedCancelClick.bindAsEventListener(this));
		} else {
			this.controller.get('lookup_button').observe(Mojo.Event.tap, this.contactLookupClick.bindAsEventListener(this));
			this.controller.get('dial_hinttext').observe(Mojo.Event.tap, this.contactLookupClick.bindAsEventListener(this));
			this.controller.get('voicemail_button').observe(Mojo.Event.tap, this.voicemailClick.bindAsEventListener(this));
			this.controller.get('call_log_button').observe(Mojo.Event.tap, this.callLogClick.bindAsEventListener(this));
			this.controller.get('contact_add_button').observe(Mojo.Event.tap, this.contactAddClick.bindAsEventListener(this));
			this.controller.get('dial_textfield').observe(Mojo.Event.tap, this.redialContactClick.bindAsEventListener(this));
		}

		// respond to call log & vm buttons while picker open
		this.controller.listen(this.controller.sceneElement, "mouseup", this.handleTapWhenPickerOpen);
		this.controller.listen(this.controller.sceneElement, "mousedown", this.handleMousedownWhenPickerOpen);
				
		// add ringtone menu item
		var appMenuModel = {
			visible: true,
			items: [
				{label: $L('Sounds & Ringtones'), command:'ringtones'}
			]
		}; 
		this.controller.setupWidget(Mojo.Menu.appMenu, {omitDefaultItems: false}, appMenuModel);
		
		// update voicemail count
		this.voicemailBadgeUpdate(this.telListener.lastVoicemail);
		
		// keyboard and document listeners
		this.controller.listen(this.controller.sceneElement, Mojo.Event.keyup, this.handleKeyUp);
		this.controller.listen(this.controller.sceneElement, Mojo.Event.keydown, this.handleKeyDown);
		// TODO: switch to activate/deactivate on stage controller?
		
		if (!this.abridged)
			this.controller.listen(this.stageController.document, Mojo.Event.deactivate, this.onBlur);
		
		// if launched with prefill argument, stuff digits in
		if (this.prefill !== undefined) {
			this.formatAndUpdateDialString(this.prefill);
			this.prefill = undefined;
		} else {
			this.dialString = "";
		}
		
		this.setupComplete = true;
	},
	
	activate: function(args) {
		
		QDLogger.log( "dialpad::activate");
		
		this.pressedKey = undefined;
		
		if (args) {
			this.handleSceneArgs(args);
		}
		
		// pushing a scene on this will prevent badge from updating, so query again
		this.voicemailBadgeUpdate(this.telListener.lastVoicemail);
		this.telListener.voicemailBadgeCallback = this.voicemailBadgeUpdate.bind(this);
	},

	incomingDialogLaunch: function() {
		this.announcer.remoteDialogScene = this.controller;
		this.announcer.dupeIncomingPopupToDialog();
	},
	
	deactivate: function() {
		QDLogger.log( "dialpad::deactivate");
	
		// clear out pressed key
		this.pressedKey = undefined;
		
		// hide picker
		// FIXME: see if there's some way to keep this up?
		this.hidePicker();
	},
	
	cleanup: function() {
		QDLogger.log( "dialpad::cleanup");
		// clear listeners
		if (!this.abridged) {
			this.controller.stopListening(this.stageController.document, Mojo.Event.deactivate, this.onBlur);
		}
		this.clearSetDialString();		
		this.telListener.lookupOnKeyPrefChangedCallback = undefined;
		this.telListener.voicemailBadgeCallback = undefined;
	},
		
	resetOnHide: function() {
		QDLogger.log( "dialpad#resetOnHide");
		
		this.closeDialogBox();
		this.clear();
		this.continuePendingOperation = false;
		if (this.messageDialog && this.messageDialog.mojo) {
			this.messageDialog.mojo.close();
			this.messageDialog = null;
		}
	},
		
	onBlur: function(event) {
		QDLogger.log( "DialpadAssistant::onBlur");
		
		if (event.target !== this.controller.document) {
			QDLogger.log( "DialpadAssistant::onBlur", "scene event bubbled");
			return;
		}
		
		var topScene = this.appAssistant.topScene();
		// don't close the stage if we're just changing scenes
		if (topScene !== "dialpad")
			return;
			
		if (this.dialString.length == 0 && !this.poundpoundAppsDialed) {
			if (this.telListener.callExists() == true || this.mmiDialogBox !== undefined || this.appAssistant.stickyDialpad === true) {
				QDLogger.log( "onBlur", "no digits, but there's an active call or dialog box, or sticky dialpad on");
				//this.appAssistant.showActiveCall();
			} else {
				if (this.cancelClose === true) {
					this.cancelClose = false;
					QDLogger.log( "onBlur", "no digits, but cancelling close once");
				} else {
					QDLogger.log( "onBlur", "no digits, so closing");
					this.appAssistant.closePhoneStage();
				}
			}
		} 
	},
	
	
	handleCommand: function(event) {
		if (event.type == Mojo.Event.back) {
			// manually deal with back if there's an active call
			// return to active call scene
			QDLogger.log( "DialpadAssistant#handleCommand", "back!");
			var ignoreBack = false;
			if (this.pickerVisible == true) {
				this.hidePicker();
				ignoreBack = true;
			} else if (this.pickerHiddenByKey === true) {
				this.pickerHiddenByKey = false;
				ignoreBack = true;
			} else if (this.dialString.length > 0) {
				this.clear();
				ignoreBack = true;
			} else if (this.telListener.callExists() == true) {
				this.appAssistant.showActiveCall();
				ignoreBack = true;
			} 
			
			if (ignoreBack) {
				event.stopPropagation();
				Event.stop(event);
			}
			
		} else if (event.type == Mojo.Event.command) {
			switch (event.command) {
				case 'ringtones':
					MenuController.showRingtones(this.controller.stageController);
					break;
				case 'logging-verbose-cmd':
					TelephonyCommands.loggingVerboseSet(true);
					break;
					
				case Mojo.Menu.prefsCmd:
					MenuController.showPrefs(this.controller.stageController);
					break;
					
				case Mojo.Menu.helpCmd:
					MenuController.showHelp();
					break;
				case Mojo.Menu.copyCmd:
				case Mojo.Menu.cutCmd:
					var tempTextArea = document.createElement('input');
					tempTextArea.value = this.dialString;
					this.controller.stageController.activeScene().sceneElement.appendChild(tempTextArea);
					tempTextArea.select();
					this.controller.document.execCommand('cut');
					tempTextArea.remove();
					if (event.command == Mojo.Menu.cutCmd) {
						this.dialString = '';
						this.controller.get('dial_textfield').innerHTML = this.dialString;
					}
					if (event.command == Mojo.Menu.cutCmd)
						this.disableInputNecessaryButtons();

					break;
				case Mojo.Menu.pasteCmd:
					if(PalmSystem && PalmSystem.paste && this.pickerVisible !== true) {
						var tempTextArea = document.createElement('textarea');
						tempTextArea.setAttribute('class','text-hidden');
						this.controller.stageController.activeScene().sceneElement.appendChild(tempTextArea);
						tempTextArea.select();
						PalmSystem.paste();
						this.tempTextArea = tempTextArea;
						if (this.pasteTimeout)
							clearInterval(this.pasteTimeout);
						this.pasteTimeout = setTimeout(this.getPasteValue.bind(this), 1);
						event.stopPropagation();
					}
					break;
			}
		}
		// Enable prefs & help menu items
		else 
			if (event.type == Mojo.Event.commandEnable &&
			(event.command == Mojo.Menu.prefsCmd || event.command == Mojo.Menu.helpCmd 
			|| event.command == Mojo.Menu.cutCmd || event.command == Mojo.Menu.copyCmd 
			|| event.command == Mojo.Menu.pasteCmd)) {
				event.stopPropagation();
			}
	},

	getPasteValue: function(){
		clearInterval(this.pasteTimeout);
		this.pasteTimeout = undefined;
		this.dialString = this.tempTextArea.value;
		this.tempTextArea.remove();
		this.controller.get('dial_textfield').innerHTML = FormatPhoneNumber(this.dialString);
		if (this.dialString.length > 0) {
			this.enableInputNecessaryButtons();
		}
		this.controller.sceneScroller.mojo.setState({'top':0,'left':0})
	},
	
	/** contact picker **/
	
	setupPicker: function() {
		if ( ! this.pickerSetup ) {
			this.pickerSetup = true;
			
			this.contactPickerModel = {
	  	  		"property" : "contacts$A", 
	      		"includeEmails": false,
	      		"includeIMs": false,
	      		"includePhones": true,
				"showGAL": true,  // wanted: something plausible that GUY could stand for 
	      		"hintText" : $L('Enter name or number...'),
		  		"labelText": $L("call:"),
	      		"focus": true,
	      		_commitLimited: true,
				focusMode: Mojo.Widget.focusInsertMode
	  		};
			
			this.controller.setupWidget('contact_widget', null, this.contactPickerModel);
			this.controller.listen('contact_widget', Mojo.Event.addressingRecipientAdded, this.contactAdded.bind(this)); 
			
			// listen for addressing widget closes
			this.controller.listen('contact_widget', Mojo.Event._addressingWidgetBlur, this.hidePicker);
			
			this.controller.get('contact_widget').setAttribute('x-mojo-element',"AddressingWidget");
			this.controller.instantiateChildWidgets(this.controller.get('picker_form'));
		}
	},
	
	// refocus picker if tapped outside it when visible
	handleTapWhenPickerOpen: function(event) {
		if (this.pickerVisible && event.target) {
			var id = event.target.id || event.target.parentElement.id;
			if (this.lastPickerMousedownId == id) {
				switch (id) {
					case "voicemail_button":
						this.voicemailClick();
						break;
					case "call_log_button":
						this.callLogClick();
						break;
					default:
						break;
				}
			}
			
		} 
		
		this.lastPickerMousedownId = '';
	},
	
	handleMousedownWhenPickerOpen: function(event) {
		if (this.pickerVisible && event.target) {
			this.lastPickerMousedownId = event.target.id || event.target.parentElement.id;
		} 
	},
	
	// if addressingwidget is showing, hide it. vice-versa.
	togglePicker: function() {
		if ( this.pickerVisible) {
			this.hidePicker();
		} else {
			this.showPicker();
		}
	},
	
	// hides divs that draw in dialstring area; show addressing widget
	showPicker: function(firstKey) {
		this.setupPicker();
				
		this.pickerVisible = true;
		this.controller.get('dialpad_input').hide();
		
		this.controller.get('numbers').hide();
		this.controller.get('phone-menu').addClassName("fixed");
        // this.controller.get('keypad_buttons').hide();
		this.controller.get('lookup_button').hide();
		
		this.controller.get('picker_form').show();
		this.controller.showWidgetContainer(this.controller.get('contact_widget'));
		
		firstKey = (firstKey || "");
		
		this.contactPickerModel.initialSearch = firstKey;
		this.controller.modelChanged(this.contactPickerModel);
	},
	
	// reshows divs in dialstring area
	hidePicker: function() {
		if (this.pickerVisible == false)
			return;
			
		QDLogger.log( "DialpadAssistant#hidePicker");		
		this.pickerVisible = false;
		
		this.controller.get('contact_widget').mojo.close();
		this.controller.hideWidgetContainer(this.controller.get('contact_widget'));
		this.controller.get('picker_form').hide();
		
		this.controller.get('dialpad_input').show();
		this.controller.get('numbers').show();
		this.controller.get('phone-menu').removeClassName("fixed");
        // this.controller.get('keypad_buttons').show();
		this.controller.get('lookup_button').show();
	},
	
	// on adding a contact, grab phone number and call it
	contactAdded: function() {
		QDLogger.log( "DialpadAssistant#contactAdded", "recipient!");
		var contacts = Mojo.View.serializeMojo(this.controller.get('picker_form'), true)['contacts$A'];
		var number, personId, label, name;
		if (contacts) { 
			for(var i=0; i<contacts.length && !number; i++) {
				if (contacts[i].value.length > 0) {
					number = contacts[i].value;
					personId = contacts[i].personId;
					label = contacts[i].formattedLabel;
					name = contacts[i].contactDisplay;
				}
			}
		}	
	
		//this.controller.modelChanged(this.contactPickerModel);
		this.controller.get('contact_widget').mojo.updateRecipients();
		this.hidePicker();	
		if (number && number.length > 0) {
			number = TelephonyCommands.normalizeNumber(number);
			if (number.length > 0) {
				this.redialSetup(number, personId, name, label);
				this.dialClick();
			}
		}
	},
	
	/** DIALPAD BUTTONS **/
	numberClick: function(event, key){
		
		if (key) {
			TelephonyCommands.sendDTMF(key, true);
			this.formatAndUpdateDialString(key,event);
			if (this.dialString.length == 1 && this.speedDialString.length == 0) {
				QDLogger.log( "DialpadAssistant#numberClick", "about to lookup speed dial");
				this.ContactBySpeeddialReq = new Mojo.Service.Request('palm://com.palm.contacts', {
					method: 'getQuickDials',
					parameters: {},
					onSuccess: this.onGetContactBySpeeddial.bind(this, this.translateToChar(key)),
					onFailure: function() {
						QDLogger.log( "DialpadAssistant#numberClick", "getQuickDials failed");		
					}
				});
			}
		}
    },

	handleHeldKey: function(event, key){
		// push various views.  this is for UI design
		if (MockTelephony.useMock == 1) {
			switch (key) {
				case '2':
					this.appAssistant.mockTelephony.toggleNetworkType();
					return;
				case '3':
					this.appAssistant.mockTelephony.pushActive();
					return;
				case '4':
					this.appAssistant.mockTelephony.pushActiveHeld();
					return;
				case '5':
					//this.announcer.announceEmergencyMode();
					//this.appAssistant.mockTelephony.pushHeldActive();
//					this.announcer.announceDialFail(4242, "you're riding the failboat.");
                    
                    this.announcer.announceMissed("4158675309", {
                        name: "Zooey Glass"
                        // new Date.getTime()
                    })
                    
					//this.appAssistant.mockTelephony.pushHeldActive();
					return;
				case '6':
					this.appAssistant.mockTelephony.pushConferenceHeld();
					return;
				case '7':
					//this.appAssistant.mockTelephony.pushSingleHeld();
					
					this.announcer.announceDisconnectAbnormal({
						causeCode: 4242,
						causeErrorText: "BAC too high.  Go sleep.",
						number: "4158675309",
						cnapName: "Zooey Glass"
					});
					
					//this.showAKEYDialog();
					return;
				case '8':
					this.appAssistant.mockTelephony.pushConferenceAndActive();
					return;
				case '9':
					this.appAssistant.mockTelephony.pushCDMAMergeable();
					return;
				case '*':
					this.appAssistant.mockTelephony.togglePicture();
					return;
				case '#':
					this.appAssistant.mockIncomingCall();
					return;
			}
			return;
		}
				
		switch (key) {
			case Mojo.Char.backspace:
				this.clear();
				return;
			case '0':
				if (PlatformType.isGSM() == true) {
					this.back();
					this.formatAndUpdateDialString('+');
				}
				else {
					if (this.dialString.length == 1) {
						this.back();
						this.formatAndUpdateDialString('+');
					}
				}
				Event.stop(event);
				return;
			case '1': {
				if (this.controller.stageController.topScene().sceneName == "dialpad"
					&& this.dialString.length < 2){
					QDLogger.log( "DialpadAssistant::doPressAndHold", "len: " , this.dialString.length);
					this.voicemailClick();
					
				}
				return;
			}
			case '*':
				this.back();
				if (PlatformType.isGSM() == true)
					this.formatAndUpdateDialString('p');
				else
					this.formatAndUpdateDialString('t');
				Event.stop(event);
				return;
			case '#':
				this.back();
				if (PlatformType.isGSM() == true)
					this.formatAndUpdateDialString('w');
				else
					this.formatAndUpdateDialString('p');
				Event.stop(event);
				return;
			default:
				if(this.speedDialString && this.speedDialString.length>0){
					if(this.speedDialString.length>=4 && this.speedDialString.length<=7 && this.appAssistant.getQuickdialPrefix(this.speedDialString) !== undefined)
						this.appAssistant.launchDial(this.appAssistant.getQuickdialPrefix(this.speedDialString) +this.speedDialString, null, this.speedDialContact);
					else
						this.appAssistant.launchDial(this.speedDialString, null, this.speedDialContact);
				}
				return;		
		}
		
//		this.formatAndUpdateDialString(key);
	
    },
	translateToChar: function(digit) {
		var keymapping = {1:'e', 2:'r', 3:'t', 4:'d', 5:'f', 6:'g', 7:'x', 8:'c', 9:'v'};
		
		if ((digit >= "1") && (digit <= "9")) 
			return keymapping[digit];
		else 
			return digit;
	},

	onGetContactBySpeeddial:function(key, payload){
		// translate + to w
		if (key == "+")
			key = "w";
		
		if (payload && payload.list) {
			QDLogger.log( "DialpadAssistant::getContactBySpeedDial", "len: " , payload.list.length);
		} else {
			QDLogger.log( "DialpadAssistant::getContactBySpeedDial", "NO RESULT");
		}
		
		var resultKeys = "";
		
		for (var i = 0; i < payload.list.length; i++) {
			resultKeys += payload.list[i].quickDial;
			if (key.toUpperCase() === payload.list[i].quickDial) {
//comment out following comments for now, in case the feature (show speed dial at first key down) come back in future
//remove them later when it won't come back for sure, also can remove the speeddial service requres for key press&hold only
//				this.controller.get('dial_textfield_name').innerHTML = (payload.list[i].firstName ? payload.list[i].firstName+ " ":"")  +(payload.list[i].lastName?payload.list[i].lastName + " ":"") + Messages.phoneLabel[payload.list[i].label];
				if (this.dialString.length > 0) //use digit if can
					this.controller.get('dial_textfield').innerHTML = this.dialString;
/*				else{ //show speed dial key
					this.enableInputNecessaryButtons();
					this.controller.get('dial_textfield').innerHTML = key;
				}*/
				this.speedDialString = payload.list[i].value;
				this.speedDialContact = {};
				this.speedDialContact.id = payload.list[i].Person_id;
				if (payload.list[i].lable == 2 && payload.list[i].customLabel)
					this.speedDialContact.label = payload.list[i].customLabel;
				else
					this.speedDialContact.label =Messages.phoneLabel[payload.list[i].label] 
//				this.controller.get('contact_add_button').hide();
				break;
			}
		}
		QDLogger.log( "DialpadAssistant::getContactBySpeedDial", "key: " , key , " matches: " , resultKeys , " string: " , this.speedDialString);
		
	},	
	
	handleKeyEventPicker: function(evt) {
		
		var oe = evt.originalEvent
		switch (oe.keyCode) {
			case Mojo.Char.comma:
			case Mojo.Char.semiColon:
				Event.stop(evt);
				return;
			case Mojo.Char.escape:
				this.pickerHiddenByKey = true;
				this.hidePicker();
				return;
		}
	},
	
	handleKeyDown: function(event) {
		
		if (this.appAssistant.blockKeyboard === true) {
			QDLogger.error("keyboard input blocked");
			return;
		}
		
		var evt = event.originalEvent;
		
		// don't execute if contact picker is up
		if (this.pickerVisible) {
			this.handleKeyEventPicker(event);
			return;
		}
	
		// ignore the back key
		if (evt.keyCode == Mojo.Char.escape) {
			return;
		}
		
		// treat enter as press on dial key
		if (evt.keyCode == Mojo.Char.enter) {
			this.dialClick();
			Event.stop(evt);
			return;
		}
		
		// don't allow repeating characters
		if (this.pressedKey && (this.pressedKey == String.fromCharCode(evt.keyCode)||this.pressedKey ==this.translateKey(evt.keyIdentifier))) {
			Event.stop(evt);
			return;
		}
		
		// handle delete
		if (evt.keyCode == Mojo.Char.backspace) {
			this.back();
			//Event.stop(evt);
		}
		
		var lastPressedKey = this.pressedKey;
		
		// w not allowed on CDMA -- it's a t
		var c = this.translateKey(evt.keyIdentifier);
		if (PlatformType.isGSM() !== true && c=='w')
			c=undefined;
		 
		//check for speeddial if this is first input and contact lookup isn't on
		if (this.dialString.length == 0 
			&& this.appAssistant.screenLocked == false
//			&& this.appAssistant.lookupOnKeyPress !== true 
			&& this.isValidSpeedDialChar(evt.keyCode) 
			&& this.speedDialString.length == 0){
			
			if (c) {
				this.formatAndUpdateDialString(c)
				this.pressedKey = c;
			} else {
				this.pressedKey = String.fromCharCode(evt.keyCode);
			}
			QDLogger.log( "DialpadAssistant::handleKeyDown", "abou to lookup speed dial");
			this.ContactBySpeeddialReq = new Mojo.Service.Request('palm://com.palm.contacts', {
				method: 'getQuickDials',
				parameters: {},
				onSuccess: this.onGetContactBySpeeddial.bind(this, this.translateToChar(this.pressedKey)),
				onFailure: function() {
					QDLogger.log( "DialpadAssistant#handleKeyDown", "getQuickDials lookup failed");
				}
			});
		} else if (c) { //following digit input
			this.pressedKey = c;
			// display character if it's not the first, if contact lookup isn't on,
			// or if it's on and it's entered with opt
			// always display when screenlock on
			// displaying here blocks contact picker from opening later (it opens only when len == 0)
			if (this.dialString.length > 0 
				|| this.appAssistant.lookupOnKeyPress !== true 
				|| this.appAssistant.screenLocked == true
				|| this.abridged
				|| (this.appAssistant.lookupOnKeyPress === true && !(this.keyMap.get(evt.keyIdentifier)))) {
				this.formatAndUpdateDialString(this.pressedKey);
			}
		} else if (evt.keyCode == Mojo.Char.backspace) {
			this.pressedKey = Mojo.Char.backspace;
		} else {
			this.pressedKey = String.fromCharCode(evt.keyCode);
		}
		
		// if the user is holding down backspace, don't clear timeout
		if (this.keyPressTimeout                                                                                                               
			&& this.pressedKey === Mojo.Char.backspace                                                                                     
			&& lastPressedKey === Mojo.Char.backspace) {                                                                                   
           	Event.stop(evt);                                                                                                               
			return;                                                                                                                        
		}   
		
		if (this.keyPressTimeout) {
			clearInterval(this.keyPressTimeout);
			this.keyPressTimeout = undefined;
		}	
		
		var holdTimeout = 500;
		if (this.pressedKey === Mojo.Char.backspace) {
			holdTimeout = 1500
		}
		
		this.keyPressTimeout = setTimeout(this.doPressAndHold.bind(this), holdTimeout);
	
		if (this.isValidToneKey(this.pressedKey)
			&& this.pressedKey !== Mojo.Char.backspace
			&& (!this.appAssistant.lookupOnKeyPress || this.keyMapOpt.get(evt.keyIdentifier))) {
			TelephonyCommands.sendDTMF(this.pressedKey, true);
		}
		
		Event.stop(evt);
	},
	
	isValidSpeedDialChar: function(keyCode) {
		var s = String.fromCharCode(keyCode);
		var valid="acdfghijklmnopqrstuvwxyACDFGHIJKLMNOPQRSTUVWXY23456789";
		
		if( valid.indexOf(s) >= 0 ) {
			return s;
		}
		return null;
	},
	
	translateKey: function(keyIdentifier) {
		return this.keyMapOpt.get(keyIdentifier) || this.keyMap.get(keyIdentifier);
	},
	
	doPressAndHold: function(){
		//QDLogger.log( "DialpadAssistant::doPressAndHold", this.pressedKey);
		if (this.keyPressTimeout) {
			clearInterval(this.keyPressTimeout);
			this.keyPressTimeout = undefined;
		}
		this.handleHeldKey(null, this.pressedKey);
		
	},
	
	handleKeyUp: function(event) {
		
		if (this.appAssistant.blockKeyboard === true) {
			QDLogger.error("keyboard input blocked");
			return;
		}
		
		// use alternate event handler if picker is up
		if (this.pickerVisible) {
			this.handleKeyEventPicker(event);
			return;
		}
		
		var evt = event.originalEvent;
		
		// ignore the back and enter keys
		if (evt.keyCode == Mojo.Char.escape) {
			return;
		}
		
		if (evt.keyCode == Mojo.Char.enter) {
			Event.stop(evt);
			return;
		}
		
		if (this.keyPressTimeout) {
			clearInterval(this.keyPressTimeout);
			this.keyPressTimeout = undefined;
		}
		this.pressedKey = undefined;
		
		this.handleContactPickerOnKeyUp(evt);
		
		Event.stop(evt);
	},
	
	handleContactPickerOnKeyUp: function(evt) {
		// decide if we should jump to contact picker
		if (this.appAssistant.lookupOnKeyPress 			// enabled?
			&& this.appAssistant.screenLocked == false		// not locked
			&& this.dialString.length < 2				// no other input?
			&& ! this.abridged
			&& Mojo.Char.isPrintableChar(evt.keyCode, false)
			&& !(this.keyMapOpt.get(evt.keyIdentifier))) {	// keycode isn't via opt?
			this.dialString="";	
			this.disableInputNecessaryButtons();
			this.showPicker(String.fromCharCode(evt.keyCode));
			return;
		}
	},

	isValidDialKey: function(key){
		if (PlatformType.isGSM() == true) {
			for (i = 0; i < key.length; i++) {
				if (!((key[i] >= '0' && key[i] <= '9') ||
				key[i] == '*' ||
				key[i] == '#' ||
				key[i] == 'w' ||
				key[i] == 'p' ||
				key[i] == '+')) 
					return false;
			}
			return true;
		}
		else{
			for (i = 0; i < key.length; i++) {
				if (!((key[i] >= '0' && key[i] <= '9') ||
				key[i] == '*' ||
				key[i] == '#' ||
				key[i] == 't' ||
				key[i] == 'p' ||
				key[i] == '+')) 
					return false;
			}
			return true;
		}
	},
	
	
	isValidToneKey: function(key) {
		
		if (!((key >= '0' && key <= '9') 
				|| key == '*' || key == '#')) 
	            return false;
		
		return true;
	},
 	
	// helper sets the dialstring with optional delay
	setDialString: function(string, delayed) {
		if ( delayed === true ) {
			this.setDialStringTimeout = this.controller.window.setTimeout(arguments.callee.bind(this,string,false), this.DIAL_PREFIX_DELAY);
		} else {
			this.controller.get('dial_textfield').innerHTML = FormatPhoneNumber(string);
			this.resizeDialString(string.length);
		}
	},
	
	// helper clears any pending delayed setDialString()
	clearSetDialString: function() {
		if ( this.setDialStringTimeout ) {
			this.controller.window.clearTimeout(this.setDialStringTimeout);
			this.setDialStringTimeout = undefined;
		}
	},
	
	formatAndUpdateDialString: function(keyIn,evt) {
		this.clearSetDialString();
		
		if (!this.controller)
			return;
		
		if (this.isValidDialKey(keyIn)) {
			
			// don't allow any more taps on dial textfield
			this.clearTapDialStringToOpenContacts();

			if (this.speedDialString && this.speedDialString.length > 0){//for speed dial
				this.controller.get('dial_textfield_name').innerHTML = "";
				this.speedDialString = "";
			}
			// if we're on CDMA, don't let the user put a + anywhere but at the beginning
			// GSM needs + anywhere to do MMI with international numbers
			if (!(PlatformType.isGSM())
				&& keyIn == "+"
				&& this.dialString.length > 0) {
					return;
			}
			
			if (this.dialString.length > 0) {
				this.dialString = this.dialString + keyIn;
			} else {
				this.dialString = keyIn;
			}
			
			var prefix = this.appAssistant.getQuickdialPrefix(this.dialString);
			if (prefix !== undefined) {
				this.setDialString(prefix + this.dialString, true);
			}
			this.setDialString(this.dialString);
			
			// enable buttons that act on an input number
			if (this.dialString.length > 0) {
				this.enableInputNecessaryButtons();
			}
			
			// CDMA: ## apps need to treat a final # as press of the dial button 
			if(!PlatformType.isGSM() // don't do it on GSM because ##xxx# does cancel forwarding 
				&& this.dialString.length > 3) {
				if((this.dialString.startsWith('##') || this.dialString.startsWith('#*#'))
					&& this.dialString.endsWith('#')) {
					//Stop the Event otherwise, the dialog box doesn't get the focus(##APPS#)
					if(evt)
						Event.stop(evt);
					this.poundpoundAppsDialed = true;
					//0.2 seconds delay is required to get the Key up event on the last typed number to avoid handleHeldKey is getting called.
					this.dial.bind(this).delay(0.2,this.dialString);
					this.clear();
				}				
			}	

						
		}
	},

	clear: function(event){
		this.clearSetDialString();
		
		this.dialString = "";
		this.speedDialString = "";
        if (this.controller.get('dial_textfield')) {
			this.controller.get('dial_textfield').innerHTML = "";
			this.disableInputNecessaryButtons();
		}
        if (this.controller.get('dial_textfield_name')) 
			this.controller.get('dial_textfield_name').innerHTML="";
		
		// don't allow any more taps on dial textfield
		this.clearTapDialStringToOpenContacts();
    },
	
	back: function(event) {
		this.clearSetDialString();
		
        if (this.controller.get('dial_textfield_name')) {
			this.controller.get('dial_textfield_name').innerHTML="";
		}
		
		// hitting delete when there's a contact displayed clears it
		if (this.redialContactParams && this.redialContactParams.contactId) {
			this.clear();
			return;
		}
		
		// don't allow any more taps on dial textfield
		this.clearTapDialStringToOpenContacts();
		
		var length = this.dialString.length;
        if (length > 0) {
			this.dialString = this.dialString.substring(0, length - 1);
			
			// CASE: Truncated dialstring: change dialstring without changing display
			if (length > 19 && this.controller.get('dial_textfield').innerHTML.indexOf("...") == 0) {
				this.resizeDialString(length);
				
			// CASE: Normal dialstring: set (and delay set prefix if needed)
			} else {
				var prefix = this.appAssistant.getQuickdialPrefix(this.dialString);
				if (prefix !== undefined) {
					this.setDialString(prefix + this.dialString, true);
				}
				this.setDialString(this.dialString);
			}
		}
		
		if (length == 1 || length == 0) {
			this.speedDialString = "";
			this.disableInputNecessaryButtons();
		}		
    },
	
	resizeDialString: function(length) {
		if(length <= 9) {
			this.controller.get('dial_textfield').className = "truncating-text text-input"; 
		} else if (length >= 10 && length <= 13) {
			this.controller.get('dial_textfield').className = "truncating-text text-input small1";
		} else if (length >= 14 && length <= 15){
			this.controller.get('dial_textfield').className = "truncating-text text-input small2";
		} else if (length >= 16 && length <= 17){
			this.controller.get('dial_textfield').className = "truncating-text text-input small3";
		} else if (length >= 18 && length <= 19){
			this.controller.get('dial_textfield').innerHTML = this.dialString;
			this.controller.get('dial_textfield').className = "truncating-text text-input small4";
		} else {
			//this.controller.get('dial_textfield').className = "truncating-text text-input small5";
			this.leftTruncatedDialString = "..."+this.dialString.slice(this.dialString.length-17, this.dialString.length) 
			this.controller.get('dial_textfield').innerHTML = this.leftTruncatedDialString;
		}
	},

	setTapDialStringToOpenContacts: function(params) {
		this.redialContactParams = params;
	},
	
	clearTapDialStringToOpenContacts: function() {
		this.redialContactParams = {};
		this.controller.get('dial_textfield').removeClassName("add-glass");
	},
	
	dialClick: function(event){
        QDLogger.log( "DialpadAssistant::dialClick", this.dialString);
        
		
		// Parse the dial string, comment out for now in case this feature(show speed dial in first key down) back in the future
/*		if (this.speedDialString && this.speedDialString.length > 0) {
			this.dial(this.speedDialString);
			this.clear();
		}
		else */
		if (this.dialString.length > 0) {
			// don't process repeat clicks for 1.25 secs when this is tapped
			if (this.dialingPrevent === true) {
				return;
			} else {
				this.dialingPrevent = true;
				this.dialingStopPrevent.delay(1.25);
			}

			var prefix = this.appAssistant.getQuickdialPrefix(this.dialString);
			if (prefix !== undefined && this.abridged !== true) 
				this.dial(prefix + this.dialString);
			else 
				this.dial(this.dialString);
			
		} else if (this.abridged !== true) {//need to fill out text filed with last dialed number
			if (this.contacts.lastDialedNumber) {
				this.redialSetup(this.contacts.lastDialedNumber.number,
								this.contacts.lastDialedNumber.contactId, 
								this.contacts.lastDialedNumber.displayName,
								this.contacts.lastDialedNumber.label)
			} else {
				this.redialQuery();
			}
		}
		
	},
	
	dialingStopPrevent: function() {
		this.dialingPrevent = false;
	}, 
	
	redialQuery: function() {
		if (this.redialRequest)
			return;
			
		this.redialRequest = new Mojo.Service.Request("palm://com.palm.superlog", {
				method: 'logQuery',
				parameters: {
					offset: 0,
					limit: 1,
					type: 'outgoing'
				},
				onSuccess:function(response){
					this.redialRequest = null;
					if (response && response.list && response.list.length > 0) {
						var result = response.list[0]
						var number = result.number;
						var label = result.label;
						if (this.contacts.isNumberValid(number)) {
							// format phone number label
							if (label == -1) {
								label = '';
							} else {
								var newLabel = Messages.phoneLabel[label];
								if(newLabel) {
									label = newLabel;
								}
							}
							this.redialSetup(number,result.contactId, result.displayName, label)
						}
					}
				}.bind(this),
				onFailure: function() {
					QDLogger.error("REDIAL QUERY FAILED");
					this.redialRequest = null;
				}.bind(this)
				
			});
	},
	
	redialSetup: function(number, contactId, displayName, label) {
		this.clearSetDialString();
		
		if ( PlatformType.isEmergencyNumber(number) || PlatformType.isOtaspNumber(number) ) {
			return;
		}
		this.dialString = number;
		this.resizeDialString(this.dialString.length);
		if (contactId !== "-1") {
			this.controller.get('dial_textfield').innerHTML = displayName;
			this.controller.get('dial_textfield').addClassName("add-glass");
			this.setTapDialStringToOpenContacts({"contactId": contactId, "label": label});
		} else {
			this.controller.get('dial_textfield').innerHTML = FormatPhoneNumber(this.dialString);
			this.setTapDialStringToOpenContacts({"number": number});
		}
		this.controller.get('delete_button').show();
		this.enableInputNecessaryButtons(contactId !== "-1");
	}, 
	
	voicemailClick: function(event) {
		QDLogger.log( "DialpadAssistant::voicemailClick");
		
		if (this.telListener.voicemailNumber) {
			this.dial(this.telListener.voicemailNumber);
		} else {
			// if we're not powered, then prompt.  otherwise assume
			// we don't have the number because we couldn't get it.
			if (!this.telListener.powered) {
				
				ConnectionWidget.connect({
					'type':'voice',
					'onSuccess': this.onConnectionWidgetResponse.bind(this, this.voicemailOnNetworkAvailable.bind(this), this.telListener.voicemailNumber)
				},this.stageController)
				

			} else {
				//Requery the voicemail number one more time before showing up the error message.
				TelephonyCommands.voicemailNumberQuery(this.onVoicemailNumberQueryReturn.bind(this),false);
			}
		}
	},
	
	onVoicemailNumberQueryReturn: function(status, number) {
		QDLogger.log( "DialpadAssistant::onVoicemailNumberQueryReturn", "number: " , number);
		if(status && number != "") {
			this.telListener.voicemailNumber = number;
			this.voicemailClick();
		}
		else 
			this.voicemailNumberErrorMessage(Messages.voicemailNumberNotFound);
	},
	
	callLogClick: function(event) {
        var stageController = this.controller.stageController;
        QDLogger.log( "DialpadAssistant::callLogClick");
		this.appAssistant.showCallLog();
	},

	contactLookupClick: function(event) {
        var stageController = this.controller.stageController;
        QDLogger.log( "DialpadAssistant::contactLookupClick");
		event.stop();
		this.togglePicker();
	},
	
	redialContactClick: function(event) {
		event.stop();
		if (this.redialContactParams) {
			if (this.redialContactParams.contactId) {
				this.openContactClick(null, this.redialContactParams.contactId)
			} else if (this.redialContactParams.number) {
				this.openPseudocardClick(null, this.redialContactParams.number);
			}
		}
	},
	
	contactAddClick: function(event) {
		if (this.controller.get('dial_textfield').innerHTML) {
			TelephonyCommands.contactPromptToAdd(this.controller, this.controller.get('dial_textfield').innerHTML)
		}
	},
	
	abridgedCancelClick: function(event) {

		if (this.appAssistant.emergencyMode) 
			this.appAssistant.showEmergencyCallback();
		else if (this.appAssistant.firstuse) 
			this.firstUseCancel();
		else if (this.appAssistant.screenLocked) {
			if (this.telListener.callExists()) { 
				this.appAssistant.showActiveCall();
			} else {
				this.appAssistant.showLockScreen();
			} 
		} else {
			QDLogger.log("DialpadAssistant#abridgedCancelClick", "UNKNOWN EXIT");
		} 
			
	},
	
	openContactClick: function(event, id) {
		TelephonyCommands.contactsLaunchWithId(id);
	},
	
	openPseudocardClick: function(event, number) {
		TelephonyCommands.contactsLaunchWithPseudocard(number);
	},
	
	firstUseCancel: function(event) {
		this.appAssistant.closePhoneStage();
	},
	
	disableInputNecessaryButtons: function() {
		if (this.abridged === true) {
			return this.disableInputNecessaryButtonsAbridged();
		}
		
		if (this.inputNecessaryButtonsVisible) {
			this.inputNecessaryButtonsVisible = false;
			QDLogger.log( "DialpadAssistant::disableInputNecessaryButtons");
			if (this.controller.get('contact_add_button')) {
				this.controller.get('contact_add_button').hide();
				this.controller.get('voicemail_button').show();
				this.controller.get('call_log_button').show();
				
				this.controller.get('delete_button').hide();
				this.controller.get('lookup_button').show();
				this.controller.get('dial_hinttext').show();
				this.controller.get('dial_textfield').hide();
			}
		}
		
	},
	
	disableInputNecessaryButtonsAbridged: function() {
		if (this.inputNecessaryButtonsVisible) {
			this.inputNecessaryButtonsVisible = false;
			QDLogger.log( "DialpadAssistant::disableInputNecessaryButtonsAbridged");
			if (this.controller.get('emergency_cancel_button')) {
				this.controller.get('emergency_cancel_button').show();
				this.controller.get('contact_add_button').hide();
				this.controller.get('voicemail_button').hide();
				this.controller.get('call_log_button').hide();
				
				this.controller.get('delete_button').hide();
				this.controller.get('lookup_button').hide();
				this.controller.get('dial_hinttext').hide();
				this.controller.get('dial_textfield').show();
			}
		}
		
	},
	
	enableInputNecessaryButtons: function(isContact) {
		if (this.abridged === true) {
			return this.enableInputNecessaryButtonsAbridged();
		}
		
		if (!this.inputNecessaryButtonsVisible) {
			this.inputNecessaryButtonsVisible = true;
			QDLogger.log( "DialpadAssistant::enableInputNecessaryButtons");
			this.controller.get('voicemail_button').hide();
			this.controller.get('call_log_button').hide();

			this.controller.get('delete_button').show();
 			this.controller.get('lookup_button').hide();
			this.controller.get('dial_hinttext').hide();
			this.controller.get('dial_textfield').show();
   		}
//following button was hide when speed dial was shown
		if(!isContact)
			this.controller.get('contact_add_button').show();
	},
	
	enableInputNecessaryButtonsAbridged: function() {
			
		if (!this.inputNecessaryButtonsVisible) {
			this.inputNecessaryButtonsVisible = true;
			QDLogger.log( "DialpadAssistant::enableInputNecessaryButtonsAbridged");
			this.controller.get('emergency_cancel_button').show();
			this.controller.get('voicemail_button').hide();
			this.controller.get('call_log_button').hide();

			this.controller.get('delete_button').show();
 			this.controller.get('lookup_button').hide();
			this.controller.get('dial_hinttext').hide();
			this.controller.get('dial_textfield').show();
   		}
	},
	
	// update hint text for type-to-search
	hintTextUpdate: function() {
		if (this.appAssistant.lookupOnKeyPress) {
			this.controller.get('dial_hinttext').textContent = Messages.dialpadHintAutoLookup;
		} else {
			this.controller.get('dial_hinttext').textContent = Messages.dialpadHint;
		}
	},
	
	// update voicemail badge
	voicemailBadgeUpdate: function(count) {
		if (count > 0) {
			if (count == this.announcer.kUnknownVoicemailCount) {
				count = Messages.newVoicemailUnknownCount;
			}
			this.controller.get('voicemail_badge').show();
			this.controller.get('voicemail_count').textContent = count;
		} else {
			this.controller.get('voicemail_badge').hide();
		}
	},
	
	/** DIALING **/
	
	// if dialing should proceed, returns true
	dialAllowed: function(number) {
		QDLogger.log( "DialpadAssistant#dialAllowed");
		
		// never dial when locked if it's not an emergency number
		if (this.appAssistant.screenLocked === true 
			&& !(PlatformType.isEmergencyNumber(number)))
			return false;
		
		// always dial 
		// ...if we have service, or if it's CDMA and we have power
		if (this.telListener.serviced || 
			(PlatformType.isGSM() !== true && this.telListener.powered))
			return true;
		
		// ...emergency numbers on GSM 
		if (PlatformType.isGSM() == true 
			&& this.telListener.powered
			&& PlatformType.isEmergencyNumber(number))
			return true;
	
		
		// always allow 
		// ...##/#*# apps to execute
		if (DialStringParser.isLaunchcode(number))
			return true;
		
		// ...IMEI and PIN operations
		if (PlatformType.isGSM() == true 
			&& DialStringParser.isMMIAllowedInLimited(number))
			return true;
		
		
		if (this.telListener.lock
			&& this.telListener.powered) {
			this.pinRequest(this.telListener.lock);
			return false;
		}
		
		// otherwise you shall not pass
		QDLogger.log( "DialpadAssistant#dialAllowed", 
				 	"prompt because powered: " + this.telListener.powered 
					+ " limited: " + this.telListener.limited);
				
		return false;		
	},
	
	// looks at dial string, decides what to do with it, then does it.
	// this could call a number, or execute an MMI code or launchcode (e.g. ## on CDMA)
	// checks if call should proceed; if so, hands it off for parsing
	// and then carries out parsing result
	dial: function(number){
        QDLogger.log( "DialpadAssistant#dial");
		
		if (!number)
			return;
		
		// remove invalid characters and numbers that start with p/w
		number = TelephonyCommands.normalizeNumber(number);
		
		if (number.length < 1) 
			return;
		
		number = this.applyInternationalDialing(number);
		
		// if dialing shouldn't proceed, prompt for poweron or network selection
		// if we're locked and powered-off, just power on by default
		// TODO: I picked a bad name.  lock = SIM lock; screenLock = ibid
		if (!this.dialAllowed(number)) {
			if (!(this.telListener.powered) 
						&& PlatformType.isEmergencyNumber(number) ) {
				// pretend that the user tapped to turn radio on
				QDLogger.error("EMERGENCY CALL WITH POWER OFF!");
				TelephonyCommands.setPower(true, 
					this.onConnectionWidgetResponse.bind(this, 
						this.dialOnNetworkAvailable.bind(this, number), number, "PhoneNetwork-StartingUp"))
				this.controller.serviceRequest("palm://com.palm.systemservice/", {
					method: 'setPreferences', 
					parameters: {"airplaneMode":false},
				});	

			} else if (!(this.abridged) 
				&& !(this.telListener.lock)) {
				QDLogger.log("PROMPT FOR POWER");
				ConnectionWidget.connect({
					'type': 'voice',
					'onSuccess': this.onConnectionWidgetResponse.bind(this, this.dialOnNetworkAvailable.bind(this, number), number)
				}, this.stageController)
	
			} else {
				Mojo.Log.error("Unknown state ", this.telListener.powered, this.abridged, this.telListener.lock);
			}
			return;
		} 
		
		// on CDMA, if this is an emergency number, and we're already in emergency mode
		// exit it before dialing
		if (this.appAssistant.emergencyMode && PlatformType.isEmergencyNumber(number)) {
			TelephonyCommands.exitEmergencyMode();
			this.appAssistant.closeEmergencyStage();
		}
		
        // Parse the dial string
		var handleAction = this.handleAction.bind(this);
        var result = DialStringParser.interpretDialString(number, PlatformType.isGSM(), this.dialFailure.bind(this), 
			this.displayMessage.bind(this), handleAction);

		// TODO: this probably isn't necessary anymore...just return probably covers everything
		// intepretDialString returns an action to take immediately AND can call handleAction as a callback to
		// do an additional action
		this.handleAction(result, number);
    }, 
	
	// handles response from connection widget.  if success, queues dial 
	// for when network is available
	onConnectionWidgetResponse: function(callback, number, response) {
		QDLogger.log( "DialpadAssistant::onConnectionWidgetResponse", response);
		
		switch (response) {
			case "PhoneManualNetwork-StartingUp":
			case "PhoneNetwork-StartingUp":
				callback();
				break;
			case "PhoneNetwork-Manual Selection Not Selected":
				// we didn't dial, but use error code for no service
				if (number) {//log failed call here
					var startTime = new Date().getTime();
					CallLogList.addEntry(0, number, "outgoing", startTime, 0);
				}
				this.announcer.announceDialFail(this.dialFailureNoService, "");
				break;
			default:
				QDLogger.log( "DialpadAssistant::onConnectionWidgetResponse", "cancelled");
				break;
		}
	},
	
	// queues a dial request for when we have an available network connection
	// TODO: determine how to timeout
	dialOnNetworkAvailable: function(number) {
		QDLogger.log( "DialpadAssistant::dialOnNetworkAvailable", number);
		// maybe we went on before this was called
		if (this.telListener.serviced === true) {
			this.dial(number);
		} else {
			// raise dialog which will be killed on pop or error
			this.telListener.setDialOnService(number);
			this.showDialPending()
		}
	},
	
	voicemailOnNetworkAvailable: function() {
		if (this.telListener.serviced === true && this.telListener.voicemailNumber) {
			this.dial(this.telListener.voicemailNumber);
		} else {
			this.telListener.voicemailOnService = true;
		} 
		
	},
	
	handleAction: function (parseResult, number) {
		QDLogger.log( "DialpadAssistant::handleAction", parseResult.action);
		switch (parseResult.action) {
			case DialAction.DIAL:
				this.launchActiveCallScreen(number, parseResult.pauseWaitDigits);
				break;
			case DialAction.VPON:
				TelephonyCommands.setVoicePrivacy(true, this.displayMessage.bind(this));
				break;
			case DialAction.VPOFF:
				TelephonyCommands.setVoicePrivacy(false, this.displayMessage.bind(this));
				break;
			case DialAction.TTY:
				this.showTTYDialog();
				break;
			case DialAction.AKEY:
				this.showAKEYDialog();				
				break;
			case DialAction.OMADM:
				this.showOMADMDialog();				
				break;
			case DialAction.EVDO:
				this.controller.stageController.pushScene('poundEvdo');
				break;
			case DialAction.PREV:
				this.showPREVDialog();
				break;
			case DialAction.GPS:
				this.controller.stageController.pushScene('poundGPS');
				break;
			case DialAction.MSL:
				this.handleMSL(parseResult.msl);				
				break;
			case DialAction.MMI:
				this.clear();
				this.showMmiPending();
				break;
			case DialAction.RTN:
				this.controller.stageController.pushScene('poundRtn');
				break;
			case DialAction.DEBUG:
				this.controller.stageController.pushScene('poundDebug');
				break;
			case DialAction.DATA:
				this.controller.stageController.pushScene('poundData');
				break;
			case DialAction.CROTEST:
				TelephonyCommands.launchCroTest();
				break;
			case DialAction.LAUNCHEXTERNAL:
				TelephonyCommands.launchExternalProgram(parseResult.app);
				break;
			case DialAction.PPTEST:
			case DialAction.CDTEST:
				this.appAssistant.experimentalMode = !(this.appAssistant.experimentalMode);
				this.displayMessage("experimental mode: " + this.appAssistant.experimentalMode);
				break;
			case DialAction.VOICEMAIL:
				this.voicemailClick();
				break;
			case DialAction.STICKYDIALPAD:
				this.toggleStickyDialpad();
				this.poundpoundAppsDialed = false;
				break;
			case DialAction.DEBOUNCED:
				// NOP
				break;
			case DialAction.UNKNOWN:
				// first use requires us to close when we try something invalid
				if (this.appAssistant.firstuse === true) {
					this.appAssistant.closePhoneStage();
				}
				break;
			case DialAction.ODD:
				TelephonyCommands.getOnDeviceDemoState((function(result) {
  	              	var title = $L("Are you sure you want to enable the Palm demo?");
    	            var message = $L("Enabling the Palm demo will erase all of your personal settings and enable an instructional demo.  Are you sure you want to enable the Palm demo?");
  					if(result.state == "on"){
                        title = $L("Are you sure you want to disable the Palm demo?")
                        message = $L("Disabling the Palm demo will erase all the current settings. Are you sure you want to disable the Palm demo?");
  					}
					this.controller.showAlertDialog({
						title: title,
						message: message,
						choices:[ 
							{label:$L("OK"), type:'primary', value:'ok'},
							{label:$L("Cancel"), type:'negative', value:'cancel'},
						],
						onChoose: function(value) {
							if(value == "ok") {
								TelephonyCommands.toggleOnDeviceDemo();
							}
						}
					});
				}).bind(this));
				break;
			case DialAction.RADIO:
				TelephonyCommands.versionFirmwareQuery(function(version){
					this.displayMessage("Telephony radio firmware version: " + version);
				}.bind(this));
				break;
			case DialAction.OFF:
				TelephonyCommands.setPower(false, function() {
					this.displayMessage("Telephony radio off.");
				}.bind(this));
				break;
			case DialAction.MASK:
				var state = !(this.appAssistant.getNumberMaskEnabled())
				this.appAssistant.setNumberMaskEnabled(state);
				this.displayMessage("Number masking " + (state ? "enabled" : "disabled"));
				break;
			case DialAction.AUDEQON:
				TelephonyCommands.setAudEq(true);
				this.displayMessage("AUDEQ headset ON");
				break;
			case DialAction.AUDEQOFF:
				TelephonyCommands.setAudEq(false);
				this.displayMessage("AUDEQ headset OFF");
				break;
			
			default:
				break;
		}
	},
	
	dialFailure: function(result, number){
		QDLogger.log( "DialpadAssistant::dialFailure", result.errorCode  , result.errorText);
		// clear dial debounce
		DialStringParser.clearDebounceTimeout();
		
		// remove pending call
		this.telListener.clearDialPending();
		
		// remove dial pending dialog box, if it exists
		this.closeDialogBox();
		
		// don't close the stage if there's another call active
		// (besides the failed dial attempt)
	    if (this.telListener.isConnected() == false && this.telListener.callCount() < 2) {
			this.appAssistant.closeActiveCallOnError();
			// turn proximity sensor off next time the display goes on
			this.telListener.proxOff();
		} else {
			QDLogger.log( "DialpadAssistant::dialFailure", "not closing activecall: there's another call active");
		}
		
		switch (result.errorCode) {
			case this.dialFailureFDNRestricted:
				TelephonyCommands.displayPin2Lock(number);
				this.cancelClose = true;
				break;
			case this.dialFailurePIN1Lock:
				TelephonyCommands.displayPin1Lock();
				this.cancelClose = true;
				break;
			case this.dialFailurePUK1Lock: 
				TelephonyCommands.displayPuk1Lock();
				this.cancelClose = true;
				break;
			case this.dialFailureSIMlock:  
				TelephonyCommands.displaySimLock();
				this.cancelClose = true;
				break;
			case this.dialFailureOTASP:  
				this.cancelClose = true;
				this.showOTASPRebootDelegate.delay(3);
				break;
			default:
				//log here for failed call
				var startTime = new Date().getTime();
				CallLogList.addEntry(0, number, "outgoing", startTime, 0);

				this.announcer.announceDialFail(result.errorCode, result.errorText);
        		break;
		}
   },
	 
   pinRequest: function(lockType) {
  		switch (lockType) {
			case "pin":
				TelephonyCommands.displayPin1Lock();
				break;
			case "puk":
				TelephonyCommands.displayPuk1Lock();
				break;
			case "sim":
				TelephonyCommands.displaySimLock();
				break;
			case "devicelock":
				TelephonyCommands.displayDeviceLock(this.telListener.locktype, this.telListener.unblock);
				break;
			default:
				break;
		}
   },
	 
   launchActiveCallScreen: function(number, pauseWaitDigits){
   		var dialParams;
		if (this.redialContactParams && this.redialContactParams.contactId) {
			dialParams = {
				id: this.redialContactParams.contactId,
				label: this.redialContactParams.label
			};
		}
		this.appAssistant.focusOnActiveCallSceneCreation = false;
		this.telListener.conjureDialingMessage(number, pauseWaitDigits, dialParams);
	},
    
	// if enabled, mod north american numbers to dial 'correctly' for the currently
	// selected country
	applyInternationalDialing: function(number) {
		var prefix = this.appAssistant.internationalDialingPrefix;
		// only do this if it's enabled, it has a valid prefix, the current region
		// uses north american dialing, and number to be dialed is likely
		// to be a north american number
		if (!this.appAssistant.internationalDialingEnabled
			|| !this.appAssistant.nanpRegion 
			|| !this.appAssistant.internationalDialingPrefix
			|| !(DialpadAssistant.kInternationalDialingValidNumber.test(number))) {
			return number
		}
		
		// if it's a 12-digit number starting with +1, convert the + to the correct
		// international dialing prefix
		if (number.length == 12 && number.substr(0,2) === '+1') {
			return prefix + number.substr(1);
		// for an 11-digit number starting with a 1, add the idd
		} else if (number.length == 11 && number.charAt(0) === '1'){
			return prefix + number; 
		// 10-digit numbers get the idd and a 1 added
		} else if (number.length == 10 && number.charAt(0) !== '+') {
			return prefix + "1" + number; 
		// if we know the phone's area code, and it's a 7 digit number
		// add idd, 1, and the area code
		} else if (number.length == 7 && this.appAssistant.homeAreaCode) {
			return prefix + "1" + this.appAssistant.homeAreaCode + number;
		}
		
		// otherwise just return the number
		return number;
	},
	
	showMmiPending: function() {
		this.showPendingMessage(Messages.mmiPending, Messages.mmiTimeout, 65000);
	},
	
	showDialPending: function() {
		this.showPendingMessage(Messages.dialOnPowerPending, Messages.dialOnPowerFail,20000);
	},
	
	showPendingMessage: function(message, timeoutMessage, timeout) {
   		
		if (this.mmiDialogBox) {
			this.mmiDialogBox.updateMessage(message, timeoutMessage, timeout);
			return;
		}
		
		this.mmiDialogBox = new MmiAssistant(this, message, timeout,
				timeoutMessage, false);
		
		var dialogBox = this.controller.showDialog({
			template: 'template/mmi-pending',
			assistant: this.mmiDialogBox,		
			preventCancel: true	
		});
		
	},
	
	clearMmiPending: function() {
		this.closeDialogBox();
	},
	
	clearDialPending: function() {
		this.closeDialogBox();
	},
	
	showMSLVerifyPending: function() {
		this.mmiDialogBox = new MmiAssistant(this, Messages.mslVerify, 0,
				null, true);
		
		var dialogBox = this.controller.showDialog({
			template: 'template/mmi-pending',
			assistant: this.mmiDialogBox,
			preventCancel: true			
		});
	},
	
	clearMslPending: function() {
		this.closeDialogBox();
	},
	
	verifyMSLDone: function(success) {
		// don't show if user flicked card off screen
		if ( ! this.continuePendingOperation ) {
			TelephonyCommands.exitProgramMode();
			this.closeDialogBox();
			return;
		}
		
		if(success) {
			this.mslFailures = 0;
			this.clearMslPending();
			this.controller.stageController.pushScene('poundMsl');
		}			
		else {
			
			if (++(this.mslFailures) === this.mslFailuresMax) {
				this.clearMslPending();
				this.showOTASPRebootDelegate.delay(3);
			} else {
				if (this.mmiDialogBox) {
					this.mmiDialogBox.updateMessage(Messages.mslVerifyError);
				}
			}
			TelephonyCommands.exitProgramMode();
		}
	},
	
	showOTASPReboot: function() {
			if (this.controller && Object.isFunction(this.controller.showAlertDialog)) {
				this.controller.showAlertDialog({
					onChoose: function() { TelephonyCommands.rebootPhone();  },
					title: $L("Dialing Disabled"),
					message: $L("The number you are trying to call cannot be tried again until you restart your phone."),
					choices: [
						{
							label: $L("Restart"),
							type: 'negative',
							value: 'OK'
						},
					],
					preventCancel: true
				});
			} else {
				Mojo.Log.error("no controller to show OTASP error");
			}
	},
	
	// TODO: this is a workaround for dialpad scene not being fully created.  
	// this should go away.
	showOTASPRebootDelegate: function() {
		Mojo.Controller.getAppController().getStageProxy("PhoneApp").delegateToSceneAssistant("showOTASPReboot");
	},
	
	displayMessage: function(msg) {
		QDLogger.log( "DialpadAssistant::displayMessage", msg);
		this.clearMmiPending();
		this.messageDialog = this.controller.showAlertDialog(
			{
				title: "", 
				message: msg, 
				onChoose: function() { this.messageDialog = null}.bind(this),
				choices: [{label: Messages.messageDialogOk}],
				preventCancel: true
			}
		);
	},
	
	voicemailNumberErrorMessage: function(msg) {
		QDLogger.log( "DialpadAssistant::voicemailNumberErrorMessage", msg);
		
		var choiceslist = [];
		
		if(this.telListener.voicemailNumberEditable)
			choiceslist = [{label: $L("Set Voicemail Number"), value: "setVoicemail", type:'affirmative'},{label: Messages.messageDialogOk, value: "close",}];
		else
			choiceslist = [{label: Messages.messageDialogOk, value: "close"}];
			
	    this.controller.showAlertDialog(
			{
				title: "", 
				message: msg, 
				onChoose: function(value) {
					if(value === "setVoicemail") {
						MenuController.showPrefs(this.controller.stageController);
					}
				}.bind(this),
				choices: choiceslist,
				preventCancel: true
			}
		);
	},
	/*** CDMA ACTIVATION DIALOGS ***/
    
	
	showAKEYDialog: function() {
		this.dialogBox = this.controller.showDialog({
			template: 'template/phone-akey-dialog',
			assistant: new AkeyAssistant(this)			
		});
	},
	
	showOMADMDialog: function() {
		this.dialogBox = this.controller.showDialog({
			template: 'template/phone-omadm-dialog',
			assistant: new OmadmAssistant(this)			
		});
	},
	
	showTTYDialog: function() {
		this.dialogBox = this.controller.showDialog({
			template: 'poundTTY/poundTTY-scene',
			assistant: new PoundTTYAssistant(this),			
		});
	},
	
	showPREVDialog: function() {
		this.dialogBox = this.controller.showDialog({
			template: 'template/phone-prev-dialog',
			assistant: new PrevAssistant(this),			
		});
	},
	
	
	
	// verifies MSL; continues to verifyMSLDone to show scene or error 
	handleMSL: function(msl) {
		this.continuePendingOperation = true;
		this.showMSLVerifyPending();
		TelephonyCommands.verifyMsl(msl,this.verifyMSLDone.bind(this));
	},
	
	// closes programming dialog box
	closeDialogBox: function(){
		
		if (this.mmiDialogBox) {
			this.mmiDialogBox.handleClose();
			this.mmiDialogBox = undefined;
		}
		
		if (this.dialPendingDialog) {
			this.dialPendingDialog.handleClose();
			this.dialPendingDialog = undefined;
		}
		
    },
	
	toggleStickyDialpad: function() {
		var state = !(this.appAssistant.stickyDialpad);
		this.appAssistant.setStickyDialpad(state);
	}
		    
});

var AkeyAssistant = Class.create({
	
	initialize: function(sceneAssistant) {
		this.sceneAssistant = sceneAssistant;
		this.controller = this.sceneAssistant.controller;
		
	},
	
	setup: function(parent){
		this.parent = parent;
		this.textAttributes = {
			enterSubmits: true,			
			multiline: false,       
			modifierState: Mojo.Widget.numLock,
			focusMode: Mojo.Widget.focusSelectMode,
			maxLength: 40,
			modelProperty: "value"			
		};
		
		this.akeyModel = {
			'value':''
		},
		this.mslModel = {
			'value':''
		},
		this.controller.setupWidget('akey', this.textAttributes, this.akeyModel);
		this.controller.setupWidget('msl', this.textAttributes, this.mslModel);	
		
		Mojo.Event.listen(this.controller.get('saveButton'),'mojo-tap', this.handleSave.bindAsEventListener(this));
		Mojo.Event.listen(this.controller.get('closeButton'),'mojo-tap', this.handleClose.bindAsEventListener(this));
	},
		
	handleSave: function() {
		
		var akey = this.controller.get('akey').mojo.getValue();
		var msl = this.controller.get('msl').mojo.getValue();
		if(!akey || !msl) {
			this.controller.get('message').innerHTML = "One of the value is missing";
			return;
		}			
		this.controller.get('message').innerHTML = '';
		this.controller.get('saveButton').disabled = true;
        this.controller.get('closeButton').disabled = true;
		TelephonyCommands.enterProgramMode(msl, this.doProgramming.bind(this));		
	},
	
	doProgramming: function (success, message) {
		if (success) {
			TelephonyCommands.setAkey(this.controller.get('akey').mojo.getValue(), 
			this.handleProgrammingSaved.bind(this));			 
		} else {
			this.controller.get('message').innerHTML = message;
            this.controller.get('saveButton').disabled = false;
            this.controller.get('closeButton').disabled = false;
		}
	},
	
	// updates status message; exits program mode
	handleProgrammingSaved: function(success, status) {
		QDLogger.log("AKEY ...", status);
		if (!success) {
			this.controller.get('message').innerHTML = status;
		} else {
			this.controller.get('message').innerHTML = Messages.akeySuccess;
		}
		
		this.exitProgramMode();	
	},
	
	// exits program mode, optionally closing dialog
	exitProgramMode: function() {		
		TelephonyCommands.exitProgramMode(null);
		this.controller.get('saveButton').disabled = false;
        this.controller.get('closeButton').disabled = false;			
	},
	
	handleClose: function() {
		this.parent.mojo.close();
	},
	
});

var OmadmAssistant = Class.create({
	
	initialize: function(sceneAssistant) {
		this.sceneAssistant = sceneAssistant;
		this.controller = this.sceneAssistant.controller;
	},
	
	updateUrl: function(payload) {
		if (payload && payload.URL) {
			this.urlModel.value = payload.URL
			this.controller.modelChanged(this.urlModel);
		} else {
			QDLogger.error("OmadmAssistant: URL payload invalid");	
		}
	},
	
	setup: function(parent){
		this.parent = parent;
		this.textAttributesMsl = {
			enterSubmits: true,			
			multiline: false,       
			focusMode: Mojo.Widget.focusSelectMode,
			modelProperty: "value",
			modifierState: Mojo.Widget.numLock			
		};
		
		this.textAttributesUrl = {
			enterSubmits: true,			
			multiline: false,       
			focusMode: Mojo.Widget.focusSelectMode,
			modelProperty: "value",
		};
		
		this.mslModel = {
			'value':''
		};
		
		this.urlModel = {
			'value':''
		}
		
		TelephonyCommands.getOmadmUrl(this.updateUrl.bind(this));
		
		this.controller.setupWidget('url', this.textAttributesUrl, this.urlModel);
		this.controller.setupWidget('msl', this.textAttributesMsl, this.mslModel);	
		
		Mojo.Event.listen(this.controller.get('saveButton'),'mojo-tap', this.handleSave.bindAsEventListener(this));
		Mojo.Event.listen(this.controller.get('defaultsButton'),'mojo-tap', this.handleSave.bindAsEventListener(this, true /* restore defaults */));
		Mojo.Event.listen(this.controller.get('closeButton'),'mojo-tap', this.handleClose.bindAsEventListener(this));
	},
		
	handleSave: function(event, restoreDefaults) {
		var url = ''
		
		// an empty URL returns to the default provisioning URL
		if (!restoreDefaults) {
			var url = this.controller.get('url').mojo.getValue();
		}
		
		var msl = this.controller.get('msl').mojo.getValue();
		if(!msl) {
			this.controller.get('message').innerHTML = "Please enter the MSL";
			return;
		}			
		this.controller.get('message').innerHTML = '';
		this.controller.get('saveButton').disabled = true;
        this.controller.get('closeButton').disabled = true;
		TelephonyCommands.enterProgramMode(msl, this.doProgramming.bind(this, msl, url));		
	},
	
	doProgramming: function (msl, url, success, message) {
		if (success) {
			TelephonyCommands.setOmadmUrl(msl, url, this.handleProgrammingSaved.bind(this));			 
		} else {
			this.controller.get('message').innerHTML = message;
            this.controller.get('saveButton').disabled = false;
            this.controller.get('closeButton').disabled = false;
		}
	},
	
	// updates status message; exits program mode
	handleProgrammingSaved: function(success, status) {
		QDLogger.log("Saving ...", status);
		if (!success) {
			this.controller.get('message').innerHTML = status;
		} else {
			this.controller.get('message').innerHTML = Messages.omadmSuccess;
		}
		
		this.exitProgramMode();	
		TelephonyCommands.getOmadmUrl(this.updateUrl.bind(this));
	},
	
	// exits program mode, optionally closing dialog
	exitProgramMode: function() {		
		TelephonyCommands.exitProgramMode(null);
		this.controller.get('saveButton').disabled = false;
        this.controller.get('closeButton').disabled = false;			
	},
	
	handleClose: function() {
		this.parent.mojo.close();
	},
	
});

var PrevAssistant = Class.create({
	
	initialize: function(sceneAssistant) {
		this.sceneAssistant = sceneAssistant;
		this.controller = this.sceneAssistant.controller;
		
	},
	
	setup: function(parent){
		this.textAttributes = {
			enterSubmits: true,			
			multiline: false,       
			modifierState: Mojo.Widget.numLock,
			focusMode: Mojo.Widget.focusSelectMode,
			maxLength: 40,
			modelProperty: "value"					
		};
		
		this.prevModel = {
			'value':''
		},
		this.mslModel = {
			'value':''
		},
		this.controller.setupWidget('prev', this.textAttributes, this.prevModel);
		this.controller.setupWidget('msl', this.textAttributes, this.mslModel);		
		
		this.parent = parent;
		Mojo.Event.listen(this.controller.get('saveButton'),'mojo-tap', this.handleSave.bindAsEventListener(this));
		Mojo.Event.listen(this.controller.get('closeButton'),'mojo-tap', this.handleClose.bindAsEventListener(this));
	},
		
	handleSave: function() {
		
		if(!this.controller.get('prev').mojo.getValue() || !this.controller.get('msl').mojo.getValue())
			return;
		this.controller.get('message').innerHTML = '';
		this.controller.get('saveButton').disabled = true;
        this.controller.get('closeButton').disabled = true;
		TelephonyCommands.enterProgramMode(this.controller.get('msl').mojo.getValue(), this.doProgramming.bind(this));
		
	},
	
	doProgramming: function (success, message) {
		if (success) {
			TelephonyCommands.setPrev(this.controller.get('prev').mojo.getValue(), 
			this.handleProgrammingSaved.bind(this));			 
		} else {
			this.controller.get('message').innerHTML = message;
            this.controller.get('saveButton').disabled = false;
            this.controller.get('closeButton').disabled = false;
		}
	},
	
	// updates status message; exits program mode
	handleProgrammingSaved: function(success, status) {
		if (!success) {			
			this.controller.get('message').innerHTML = status;
		} else {
			this.controller.get('message').innerHTML = Messages.prevSuccess;
		}
		
		this.exitProgramMode();
	},
	
	// exits program mode, optionally closing dialog
	exitProgramMode: function() {		
		TelephonyCommands.exitProgramMode(null);
		this.controller.get('saveButton').disabled = false;
        this.controller.get('closeButton').disabled = false;			
		if (this.sceneAssistant.appAssistant.rebootOnRadioSettingsChanged) {
			this.promptToReboot();
		}
	},
	
	handleClose: function() {
		this.parent.mojo.close();
	},
	
	promptToReboot: function() {
		this.controller.showAlertDialog({
			onChoose: function(value){
				TelephonyCommands.rebootPhone();				
			},
			message: "Phone must now reboot.",
			choices: [{
				label: 'Reboot',
				value: false,
				type: 'dismiss'
			}]
		});
	}
});

DialpadAssistant.kInternationalDialingValidNumber = /\+?\d{7,11}/;

