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

*/
CaptureAssistant = Class.create({
	initialize : function(params) {
		llog("CaptureAssistant::initialize ", Object.toJSON(params));

		// Set-up some 'class' variables
		Object.extend(CaptureAssistant,	{
			FLASH_OFF:  0, 
			FLASH_AUTO: 1,
			FLASH_ON:   2
		});		
	
		this.photorollInfo = null;
		
		this._powerService = null;
		this._powerServiceEventRef = null;
		

		this._blurHandlerTimeout = null;
		this._focusHandlerTimeout = null;

		this._displayOn = true;
		
		this.launchParams = params || {};


		this.sublaunch = !!this.launchParams.sublaunch;
		if (!this.launchParams.mode){ 
			this.launchParams.mode = 'still';
		};

		if ( (!this.launchParams.filename) 
			|| (0 !== this.launchParams.filename.indexOf("/media/internal/"))
			|| (-1 !== this.launchParams.filename.indexOf("/../")) )
		{
			// No filename specified or filename is not in user accessible partition
			this.defaultFilename = null; 
		}
		else {
			this.defaultFilename = this.launchParams.filename;
		}			

		if (this.launchParams.mode === 'video'){
			// No auto for camcorder.
		}
		else {
			if (!!this.launchParams.autoCount) {
				this.auto = {
					count: this.launchParams.autoCount,
					delay: this.launchParams.autoDelay
				};
				
				this.autoSetup();
			}
		} 

		llog("CaptureAssistant::initialize launchParams: ", Object.toJSON(this.launchParams));

	},

	
	setup: function() { try {
		llog("CaptureAssistant::setup ", Object.toJSON(arguments));
		
		// CameraFactory creates instances of "Camera" objects.  The objects returned implement
		// the Camera interface, but are delegate that talk to a real implementation on the mediaserver
		//
		// Pass in a property bundle containing implementation specific params.  In this implemenation
		// only the luna-bus endpoint of the mediaserver needs to be provided.

		Media.MediaCapture.setup(this, AppProperties.VideoCapture.FACTORY_PARAMS);

		
		this.controller.enableFullScreenMode(true);


		this.controller.sceneElement.addClassName('preview-off');

		var appController = Mojo.Controller.getAppController();
		this.cameraControl = new CameraControl(appController, this);
		
		CameraPrefs.loadPrefs(function(success, prefs){
			this.cameraControl.setPrefs(prefs);
		}.bind(this));

		if (this.sublaunch){
			this._handleCaptureToggle(this.launchParams.mode, true/*isFromPrefs*/);
		}
		else {
			var mode = 'still';
			if (!!AppAssistant.restartParams){
				mode = AppAssistant.restartParams.captureMode;
				delete AppAssistant.restartParams;
			}

			// Always start in still capture mode.  
			this._handleCaptureToggle(mode);

			// Last capture mode is stored in prefs.  
			// The following line would restore the last capture mode from preferences. 
			// Some people might prefer to remember what the last capture mode was.  
			// Enough clues?!
			//this._handleCaptureToggle(this.cameraControl.prefs[CameraControl.PREFS.CAPTURE_MODE], true/*isFromPrefs*/);

		}
		this.cameraControl.setupCamera();

		this._onBlurHandler = this._onBlur.bind(this);
		this._onFocusHandler = this._onFocus.bind(this);
		
		Mojo.Event.listen(this.controller.window.document, Mojo.Event.deactivate, this._onBlurHandler, false);
		Mojo.Event.listen(this.controller.window.document, Mojo.Event.activate, this._onFocusHandler, false);
		
		this.controller.get('capture-button').observe(Mojo.Event.tap, function(){
			this.onCapture();
		}.bind(this));

		this.controller.get('flash-toggle').observe(Mojo.Event.tap, function(){
			this._handleFlashButton();
		}.bind(this));
		
		if (this.sublaunch){
			// Hide the toggle button, we only allow sublaunch to still capture.
			this.controller.get('capture-toggle').hide();
			this.controller.get('capture-thumbnail').hide();
			this.controller.get('capture-thumbnail-overlay').hide();
		}
		else {
			this.controller.get('capture-toggle').observe(Mojo.Event.tap, function(){
				this._handleCaptureToggle();
			}.bind(this));
		}
		
		
		
		this.onKeyPressHandler = this.onKeyPress.bindAsEventListener(this);
		Mojo.listen(this.controller.sceneElement, Mojo.Event.keydown, this.onKeyPressHandler);
		Mojo.listen(this.controller.sceneElement, Mojo.Event.keyup, this.onKeyPressHandler);
		
		if (CameraControl.__debug) {
			var elemC = this.controller.get('sagar_console');
			if (!!elemC) {
				elemC.style.display = '';
			}
		}
		
		if (!AppAssistant.photoRollPhotoLoader) {
			//loading photos scripts for fast photo roll launch
			var loader = new PhotosLoader("com.palm.app.photos", this.controller);
			function openedOkay(){
				AppAssistant.photoRollPhotoLoader = loader;
			}
			function failed(){
				Mojo.Log.error("Failed to open up loader...");
			}
			loader.open(openedOkay.bind(this), failed);
		}
		
		if (!AppAssistant.photoRollVideoLoader) {
			AppAssistant.photoRollVideoLoader = AppAssistant.libraries["metascene.videos"];

		}
		
		llog("CaptureAssistant::setup() finished");
	}catch(e){llog("setup threw: "+Object.toJSON(e));}},
	


	/**
	 * Set-up stuff that we don't want to do until we've brought up preview 
	 */
	deferredSetup: function(){
		llog ("Entering deferredSetup");

		if (!this.isFocused()){
			llog("Already carded when entering deferredSetup");
			return;
		}


		this.imageService		= new MediaDBImageService();
		this.appManagerService	= new AppManagerService();



		if (!this.sublaunch){
			// Only need to do these for full launch.			
			this.setupPhotoRoll();
			if ('disabled' !== this.cameraControl.prefs[CameraControl.PREFS.GEOTAG]) {
				
				if ('enabled' == this.cameraControl.prefs[CameraControl.PREFS.GEOMETER]){
					var gpsElem = this.controller.get('gps-meter');
					GeoControl._fixMonitorElem = gpsElem;
					if (!!GeoControl._fixMonitorElem) {
						gpsElem.style.display = "block";
					}
				}

				GeoControl.lbsCheckAndStart();
			}
			else {
				llog("Geotagging disabled in camera's prefs.");
			}
			
		}

		this.setupMSM();
		this.setupPowerService();
		this.startIdleCheck();
		this.cameraControl.setupPreviewWatch();

		var prefFlashState = +this.cameraControl.prefs[CameraControl.PREFS.FLASH];
		this.setFlashState(prefFlashState);

		try {
			var initialOrientation = PalmSystem.screenOrientation;
			this.orientationChanged(initialOrientation);
		}
		catch(e){} 


		if (this.sublaunch){
			if (this.autoActive()) {
				llog("We're in autoActive");
				
				var timeout = this.autoHandle();
				if (-1 !== timeout) {
					setTimeout(this.autoCapture, timeout);
				}
				
			}			
		}

		this.controller.sceneElement.removeClassName('preview-off');
		this.controller.get("camera-icon").style.display = "block";
		llog("Controls are up");
	},


	autoActive: function(){
		return (this.auto && (this.auto.count > 0) );
	},
	autoSetup: function(){
		if (this.auto.count > 9) { this.auto.count = 9; }
		if (this.auto.count < 0) { this.auto.count = 0; }
		if (this.auto.delay < 1000) { this.auto.delay = 1000; }
		if (this.auto.delay > 5000) { this.auto.delay = 5000; }
		
		this.auto.filenameTmplt = this.defaultFilename;
		this.auto.next = 0;
		this.auto.startTime = new Date().getTime();
		
		this.autoCapture = this.autoCapture.bind(this);

		return (!!this.auto.count);
	},
	

	autoHandle: function(){
		if (undefined !== this.auto.filenameTmplt){
			
			var fileSplitIdx = this.auto.filenameTmplt.lastIndexOf(".");
			var filePart1;
			var filePart2;
			
			if (-1 !== fileSplitIdx){
				filePart1 = this.auto.filenameTmplt.substring(0, fileSplitIdx);
				filePart2 = this.auto.filenameTmplt.substring(fileSplitIdx);
			}
			else {
				filePart1 = this.auto.filenameTmplt;
				filePart2 = ".jpg";
			}
			
			this.defaultFilename = filePart1
				+"_"
				+this.auto.next
				+filePart2;
		}
		
		
		var targetTimeout = -1;
		
		if (!this.isFocused()){
			llog("Can't do any more captures, lost focus");
		}
		else if ( (this.auto.next !== this.auto.count) && (this.auto.next < 10) ){
			targetTimeout = this.auto.startTime;
			targetTimeout += this.auto.delay*(1+this.auto.next);
			
			targetTimeout -= new Date().getTime();
			
			if (targetTimeout < 500){
				targetTimeout = 500;
			}

			llog("Recommending capture in "+targetTimeout+"mS, with filename: "+this.defaultFilename);			
		}
		else {
				llog("Not recommending any more captures");
		}
		
		++this.auto.next;
		
		
		return targetTimeout; 
	},
	
	autoCapture: function(){
		this.onCapture();
	},
	
	/**
	 * Called from the scene controller when the scene is torn down.
	 */
	cleanup: function(){
		llog("CaptureAssistant::cleanup");
		
		Mojo.Event.stopListening(this.controller.window.document, Mojo.Event.deactivate, this._onBlurHandler, false);
		Mojo.Event.stopListening(this.controller.window.document, Mojo.Event.activate, this._onFocusHandler, false);

		Mojo.stopListening(this.controller.sceneElement, Mojo.Event.keypress, this.onKeyPressHandler);
		
		this.stopIdleCheck();
		if (this._powerServiceEventRef) {
			this._powerServiceEventRef.cancel();
			delete this._powerServiceEventRef;
		}
		
		this.cameraControl.closeCamera();
	},
	
	handleCommand: function(event){
		llog ("CaptureAssistant::handleCommand");
		llog ("event.type: "+event.type);

		if (event.type == Mojo.Event.command)
		{
			llog("Mojo.Event type == command, command type == "+ event.command);
		}
		
	},
	
		
	onKeyPress: function(event) {
//		var evtStr = "onKeyPress: "+event.type;
//		if (Mojo.Event.keydown === event.type){
//			evtStr += " / "+event.originalEvent.keyCode;
//		} 
//		llog(evtStr);

		// Space bar also takes a picture.
		if (Mojo.Char.spaceBar == event.originalEvent.keyCode) {
			if (event.type === Mojo.Event.keydown) {
				if (!this.captureBurst) {
					this.captureBurst = true;
					this.onCapture(true /*keyboard*/);
				}
			}
			else {
				this.captureBurst = false;
			}
		}
		else if ( (Mojo.Char.p === event.originalEvent.keyCode) || (Mojo.Char.q === event.originalEvent.keyCode) ) {
			if (event.type === Mojo.Event.keydown){
				if (!this.cameraControl._haveFrobs()){
					this._handleCaptureToggle((Mojo.Char.q === event.originalEvent.keyCode)?"still":"video");
				}
			}
		}
	},
	
	onCapture: function(isHardkey){
		if (this.isVideoCapture){
			this.cameraControl.videoCapture(isHardkey/*haptic*/);
		}		
		else {
			this.cameraControl.stillCapture();
		}
	},
  
	
	/**
	 * Called by Mojo when the orientation of the device changes.
	 * 
	 * @param {String} orientation   The new orientation of the device.
	 */
	orientationChanged: function(orientation){
		llog ("Got orientation ", orientation);

		var lastOrientation = this.orientation;
		this.controller.sceneElement.removeClassName(lastOrientation);
		this.orientation = orientation;

		this.controller.sceneElement.addClassName(orientation);
		
		switch (orientation){
			case 'up':
				this.cameraControl.exifOrientation = Exif.Orientation.UP;
				break;
			case 'right':
				this.cameraControl.exifOrientation = Exif.Orientation.RIGHT;
				break;
			case 'down':
				this.cameraControl.exifOrientation = Exif.Orientation.DOWN;
				break;
			case 'left':
				if (this.isVideoCapture){
					// Once the user gets the device the right way round never show the "Turn your device round" message again.
					this.controller.get('rotate-container').setAttribute("style", "-webkit-transition-property: opacity, color; -webkit-transition-duration: 1s; opacity: 0; color: rgba(255, 255, 255, 0);");
					this.controller.get('rotate-message').setAttribute("style", "-webkit-transition-property: opacity, color; -webkit-transition-duration: 1s; opacity: 0; color: rgba(255, 255, 255, 0);");
				}


				this.cameraControl.exifOrientation = Exif.Orientation.LEFT;
				break;			
		}
		

		llog("Updated orientation: ", this.controller.sceneElement.className);
	},
	
	setupPhotoRoll: function(){
		if (this.photorollInfo){
			return;
		}
		
		llog("Checking/Setting up Photo Roll");

		// This will get still and video properties, once the video and still services 
		// return their counts of contents.
		this.photorollInfo = {};

		// Hide the photoroll icon until we get a photoroll response.		
		this._setIndexingStyle(true);

		var stateRequestH = this.imageService.getState(function(response){
			llog("getState says: "+Object.toJSON(response));
			if (response.state === "idle"){
				this.imageService.retrievePhotoRoll(this._returnedPhotoRollDetails.bind(this), this.controller);
				stateRequestH.cancel();
			}
		}.bind(this), this.controller);
			
	},

	/**
	 * Called when we are sublaunched to return control to calling app  
	 * 
	 * 
	 * @param {Boolean} success   Status of the capture. true if the capture was successful
	 * @param {String} filename   Returns the filename of the captured image, or null if capture failed.
	 */	
	captureComplete: function(success, filename){
		llog("CaptureAssistant::captureComplete()");
		if (this.sublaunch){
			var timeout = -1;
			if (this.autoActive()) {
				timeout = this.autoHandle();
			}

			if (-1 == timeout){
				this.controller.stageController.popScene({ returnValue: !!success, filename: filename });
			}
			else {
				setTimeout(this.autoCapture, timeout);
			}
		}
	},
	

	/**
	 * Called once the indexer has returned the ID of the photoroll album.
	 * 
	 * @param {Object} response  Data from the file indexer
	 * @private
	 */
	_returnedPhotoRollDetails: function(response){
		llog("Response received for detail proll: "+Object.toJSON(response));
		var proll = response.albums[0];

		llog("Photoroll album: "+Object.toJSON(proll));		

		var count = (+proll.albumCount);
		if (0 === count){
			llog("No images in photoroll album");
		}
		proll.albumCount = count;

		// stash the album info
		this._setupPhotorollAlbum(proll);

		// These are images in the album, go get a URL for an image.
		this._mediadbImageService = this.imageService.retrievePhotoRollImages(proll, this._returnedPhotoRollStillDetails.bind(this), this.controller);
		
		// Go see if there are videos too!
		this._mediadbVideoServiceH = this.imageService.retrieveVideoRollImages(this._returnedPhotoRollVideoDetails.bind(this), this.controller);

        this._observeThumbnailHitTarget();

	},
	
	/**
	 * Called once the indexer has returned the image list for the photoroll.  If 
	 * there are any images in the photoroll the image returned must be put in the 
	 * photoroll button in the UI
	 * 
	 * @param {Object} response  Data from the file indexer
	 * @private
	 */
	_returnedPhotoRollStillDetails: function(response){
		llog("_returnedPhotoRollStillDetails - response: ", Object.toJSON(response));
		if (0 === response.images.length) {
			// No images, put up a clear photo roll
			if (!this.isVideoCapture) {
				this.setPhotoRollImage("");

				// Hide the photoroll icon until we get a photoroll response with images.		
				this._setIndexingStyle(true);
			}
		}
		else {
			this.photorollInfo.still.album_last_image_thumb = response.images[0].imagePictureUrl;
			this.photorollInfo.still.album_last_image = response.images[0].imagePath;

			
			if (!this.isVideoCapture) {
				// Currently in still capture, so we want the updated still image to show.
				this.setPhotoRollImage(AppAssistant.EFS.exe
					+ this.photorollInfo.still.album_last_image_thumb
					+ AppAssistant.EFS.savedThumb);

				if (!this.isFocused()){
					// If we're carded and there was an update, then update the scrim shot 
					this.setScrimImage();
				}
			}
		}
			
		// Update our cached value for total images.
		this.photorollInfo.still.album_image_count = (+response.imagesTotal);
		
	},
	
	_returnedPhotoRollVideoDetails: function(response){
		llog("_returnedPhotoRollVideoDetails - response: ", Object.toJSON(response));
		if ( !response || !response.returnValue || (+response.videosTotal === 0) ) {
			this.photorollInfo.video = {
				album_video_count: 0
			};

			// No images, put up a clear photo roll
			if (this.isVideoCapture) {
				this.setPhotoRollImage("");

				// Hide the photoroll icon until we get a photoroll response with videos.		
				this._setIndexingStyle(true);
			}
		}
		else {
			this.photorollInfo.video = {};
			this.photorollInfo.video.album_video_count = +response.videosTotal;
			if (!!response.videosTotal){
				this.photorollInfo.video.details = response.videos[0];
			}

			
			if (this.isVideoCapture) {
				if (!response.videosTotal){
					this.setPhotoRollImage("");
				}
				else {
					var imgUrl = "";
					if (!!this.photorollInfo.video.details.videoPictureUrl) {
						imgUrl = AppAssistant.EFS.exe
							+ this.photorollInfo.video.details.videoPictureUrl
							+ AppAssistant.EFS.savedThumb;						
					}
					
					// Currently in still capture, so we want the updated still image to show.
					this.setPhotoRollImage(imgUrl);
	
					if (!this.isFocused()){
						// If we're carded and there was an update, then update the scrim shot 
						this.setScrimImage();
					}
				}
			}
		}
			
	},
	
	_observeThumbnailHitTarget: function() {
		if (undefined === this._thumbnailTapHandler) {
			this._thumbnailTapHandler = this._thumbnailTap.bind(this);
			this.controller.get('capture-thumbnail-overlay').observe(Mojo.Event.tap, this._thumbnailTapHandler);
		}
	},
	
	_thumbnailTap: function(event){
		llog("ThumbnailHitTarget tap event");
		if (this.photorollInfo) {
			if (this.isVideoCapture && this.photorollInfo.video && this.photorollInfo.video.album_video_count){
	    		this._handlePhotorollVideo();
			}
			else if (!this.isVideoCapture && this.photorollInfo.still && this.photorollInfo.still.album_image_count){
	    		this._handlePhotorollStill();
				
			}
		}
	},
	
	/** 
	 * Check to see if two paths point to the same file, by choping anything before DCIM.
	 * 
	 * This is to get around the issue that a src element on an img will prefix absolute path
	 * and protocol, while the indexer gives the path the extractfs.
	 * 
	 * @param {Object} pathA
	 * @param {Object} pathB
	 */
	_checkImageSamishness: function(pathA, pathB){
		var isSameImage = false;
		if (pathA && pathB){
			var idx = pathA.lastIndexOf('DCIM');
			var a;
			var b;
			if (-1 !== idx) {
				a = pathA.substr(idx);
			}
			idx = pathB.lastIndexOf('DCIM');
			if (-1 !== idx){
				b = pathB.substr(idx);
			}

			isSameImage = (a == b); 

		}

		return isSameImage;
		
	},
	
	/**
	 * Used to set an image into the photoroll button in the UI.  If the photoroll is not yet
	 * visible, this function will display it.
	 * 
	 * @param {URL} imageUrl
	 * @private
	 */
	setPhotoRollImage: function(imageUrl){
		llog("Setting photoroll to existing capture: ", imageUrl);

		var savedImgElem = this.controller.get('capture-thumbnail');
		var isSameImage = this._checkImageSamishness(imageUrl, savedImgElem.src);

		if ( (undefined === imageUrl) || (null === imageUrl) || ("" === imageUrl) ){
			this._setIndexingStyle(true);
		} 
		else if (isSameImage){
			// Image has not changed, don't load, but ensure it's displaying
			llog("No change to image: ", savedImgElem.src);
			this.setPhotorollUpdating(false);
		}
		else {
			if (!this.photoHasLoadedHandler){
				this.photoHasLoadedHandler = this.photoHasLoaded.bind(this);
			}

			savedImgElem.addEventListener('load', this.photoHasLoadedHandler, false);
			savedImgElem.addEventListener('abort', this.photoHasLoadedHandler, false);
			savedImgElem.addEventListener('error', this.photoHasLoadedHandler, false);
			savedImgElem.src = imageUrl;
		}

        this._observeThumbnailHitTarget();
		
	},
	
	/**
	 * Set the image that is displayed behind the scrim when the app is minimized.
	 * 
	 * This function will check the current mode (still/video capture) and set the  
	 * appropriate scrim.
	 */
	setScrimImage: function(){
		var imageUrl;

		// No URL specified, get one from the photoroll, based on the mode we are in.		
		if (this.isVideoCapture){
			if (!!this.photorollInfo && !!this.photorollInfo.video && this.photorollInfo.video.album_video_count && !!this.photorollInfo.video.details){
				imageUrl = AppAssistant.EFS.exe
					+ this.photorollInfo.video.details.videoPictureUrl
					+ AppAssistant.EFS.scrimVideo;
			}
		}
		else {
			if (!!this.photorollInfo && !!this.photorollInfo.still && this.photorollInfo.still.album_image_count  && !!this.photorollInfo.still.album_last_image){
				imageUrl = AppAssistant.EFS.exe 
					+ this.photorollInfo.still.album_last_image 
					+ AppAssistant.EFS.scrimImage;
			}
		}

		if (!!imageUrl) {
			var scrimShot = this.controller.get('scrim-shot');
		
			if (!this._showScrimShotAfterLoadHandler){
				this._showScrimShotAfterLoadHandler = this._showScrimShotAfterLoad.bind(this);
				this._showScrimShotLoadFailedHandler = this._showScrimShotLoadFailed.bind(this);
			}
			
			var isSameImage = this._checkImageSamishness(imageUrl, scrimShot.src);

			if (isSameImage) {
			    scrimShot.style.display = "";
				this.controller.window.setTimeout(function() {
				    scrimShot.style.opacity = "1.0";
				}, 500);
			} else {
				var freshScrimShot = this.controller.document.createElement('img');

				freshScrimShot.setAttribute('id', 'scrim-shot');
				freshScrimShot.setAttribute('style', scrimShot.getAttribute('style'));
				
				freshScrimShot.addEventListener('load', this._showScrimShotAfterLoadHandler, false);
				freshScrimShot.addEventListener('error', this._showScrimShotLoadFailedHandler, false);
				freshScrimShot.addEventListener('abort', this._showScrimShotLoadFailedHandler, false);
	
                freshScrimShot.src = imageUrl;
			}
		}
	},
	
	_showScrimShotAfterLoad: function(event){
		var freshScrimShot = event.target;
		freshScrimShot.removeEventListener('load', this._showScrimShotAfterLoadHandler, false)
		freshScrimShot.removeEventListener('error', this._showScrimShotLoadFailedHandler, false);
		freshScrimShot.removeEventListener('abort', this._showScrimShotLoadFailedHandler, false);

		var scrimShot = this.controller.get('scrim-shot');
		scrimShot.replace(freshScrimShot);

		this.controller.window.setTimeout(function() {
			if (!this.isFocused()) {
			    scrimShot.style.display = "";
				freshScrimShot.style.opacity = "1.0";
				freshScrimShot.style.zIndex = "101";
			}
		}.bind(this), 500);		

	},
	_showScrimShotLoadFailed: function(event){
		var freshScrimShot = event.target;

		freshScrimShot.removeEventListener('load', this._showScrimShotAfterLoadHandler, false)
		freshScrimShot.removeEventListener('error', this._showScrimShotLoadFailedHandler, false);
		freshScrimShot.removeEventListener('abort', this._showScrimShotLoadFailedHandler, false);
	},
  

	/**
	 * Called when there is a response from the mediadb service indicating the details of the photoroll.
	 * 
	 *  @private
	 */
	_setupPhotorollAlbum: function(image_album){
		this.photorollInfo.still = {
			album_id: image_album.albumID,
			album_name: $L("Photo roll")
		};
	},
	


	_storageProgress: function(resp){
		llog("In MSM progress callback ");
	
		if (!resp){
			return;
		}
	
		
		if (resp['mode-avail']){
			// Back from mass storage mode.
			this.cameraControl.onMsmStop();
		}
	},
	

	setupMSM: function(){
		llog("CaptureAssistant::setupMSM()");
		if (this.storageNotificationSession){
			llog("MSM is already setup");
			return;
		}
	
		this._storageProgressHandler = this._storageProgress.bind(this);
	
		this.storageNotificationSession = new Mojo.Service.Request(
			'palm://com.palm.bus/signal',
			{
				method: 'addmatch',
				parameters:
				{
					category: "/storaged"
				},
				onSuccess: this._storageProgressHandler
			}		
		);
	},
	
	
	_powerEvent: function(event){
		if ( (!event) || (!event.event) ){
			llog("Power event had no event");
			return;
		}
		
		var elemC = this.controller.get('sagar_console');
		
		llog("Power event: "+Object.toJSON(event));
		
		if ("displayOff" == event.event){
			if (this.sublaunch) {
				this.captureComplete(false, null);
			}
			else {
				this._displayOn = false;
				this.cameraControl.onDisplayOff();
			}
		}
		else if ("displayOn" == event.event){
			if(this.controller.stageController.activeScene().sceneName == "capture"){
				if (false === this._displayOn) {
					this._displayOn = true;
					this.cameraControl.onDisplayOn();
				}
			}
		}
	},
	
	setupPowerService: function(){
		llog("Setting up power service...");
	
		if (this._powerServiceEventRef){
			llog("Power service was already set-up");
			return;
		}
	
		this._powerEventHandler = this._powerEvent.bind(this);
		this._powerService = new PowerManagerService();		
		this._powerServiceEventRef = this._powerService.registerForEvents(this._powerEventHandler);
		
	},

	/**
	 * Disable screen off and start checking for capture activity
	 * 
	 * We disable the screen off for the first two minutes, so use is not
	 * bothered by the screen going dim after 30 seconds.  we need to check 
	 * periodically wether the user is still taking pictures.  If not, we will
	 * re-enable the screen dim.  
	 */
	startIdleCheck: function(){
		llog("Idle timer started");
		this._triggerIdleHandler = this._triggerIdle.bind(this);

		this._idleCheckTimer = setTimeout(this._triggerIdleHandler,  this.cameraControl.prefs[CameraControl.PREFS.IDLEMAX]);
		this._powerService.stopScreenDim();
	},
	/**
	 * Stop checking for capture activity and re-enable the screen dim.
	 * 
	 */
	stopIdleCheck: function(){
		llog("Idle timer stopped");
		if (this._powerService) {
			this._powerService.allowScreenDim();
		}

		if (this._idleCheckTimer){
			clearTimeout(this._idleCheckTimer);
			delete this._idleCheckTimer;
		}
	},
	/**
	 * Indicate that an event has occured and reset the screen-off check time.
	 */
	resetIdleCheck: function(){
		llog("Idle timer reset");
		if (this._idleCheckTimer){
			clearTimeout(this._idleCheckTimer);
			this._idleCheckTimer = setTimeout(this._triggerIdleHandler,  this.cameraControl.prefs[CameraControl.PREFS.IDLEMAX]);

		}
		else{
			this.startIdleCheck();
		}
	},
	/**
	 * If no captures occur in the prescribed time re-enable the screen dim.
	 * @private
	 */
	_triggerIdle: function(){
		llog("Idle timer triggered");
		if (this._idleCheckTimer) {
			delete this._idleCheckTimer;
		}

		this._powerService.allowScreenDim();
	},
			

	/**
	 * Click handler for flashmode button.
	 *  
	 * @param {Event} event  The click event
	 */
	_handleFlashButton: function(event){
		if ( (this.flashState < CaptureAssistant.FLASH_OFF) || (this.flashState >= CaptureAssistant.FLASH_ON) ){
			// Cycle order is off, auto, on.
			this.flashState = CaptureAssistant.FLASH_OFF;
		}
		else {
			++this.flashState;
		}

		var validatedFlash = false;
		if  ( (this.flashState == CaptureAssistant.FLASH_OFF)
			|| (this.flashState == CaptureAssistant.FLASH_AUTO)
			|| (this.flashState == CaptureAssistant.FLASH_ON) )
		{
			validatedFlash = true;
		}
		
		if (!validatedFlash){
			this.flashState = CaptureAssistant.FLASH_AUTO;
		}

		this.setFlashState(this.flashState);
	},
		
	setFlashState: function(state){

		if ( (state < CaptureAssistant.FLASH_OFF) || (state > CaptureAssistant.FLASH_ON) ) {
			llog("Requested flash state is out of range (", state, ")");
			return;
		}

		this.flashState = state;
		CameraPrefs.updatePref(this.cameraControl.prefs, CameraControl.PREFS.FLASH, state);

		
		if (this.flashState == CaptureAssistant.FLASH_OFF) {
			this.controller.get('flash-toggle').className = "flash-button flash-off";
		}
		else if (this.flashState == CaptureAssistant.FLASH_ON) {
			this.controller.get('flash-toggle').className = "flash-button flash-on";
		} 
		else if (this.flashState == CaptureAssistant.FLASH_AUTO) {
			this.controller.get('flash-toggle').className = "flash-button flash-auto";
		} 


		var camera = this.cameraControl.getCameraInstance();

		switch(this.flashState){
			case CaptureAssistant.FLASH_OFF:
				camera.flash = Camera.FLASH_OFF;
				break;
			case CaptureAssistant.FLASH_ON:
				camera.flash = Camera.FLASH_ON;
				break;
			case CaptureAssistant.FLASH_AUTO:
				camera.flash = Camera.FLASH_AUTO;
				break;
		} 

		llog("Set Flash Mode to ", camera.flash);
	},
	
	/**
	 * Handle the toggle event from the UI.
	 * 
	 * Takes an optional parameters, to allow the actual mode to be specified.
	 * 
	 * @param {String}   opt           'video'/true or 'still'/false
	 * @params {Boolean} fromPrefs     Prevent updating the preferences. 
	 */
	_handleCaptureToggle: function(opt, fromPrefs){
		var transition = null;
		try {
			transition = this.controller.prepareTransition(Mojo.Transition.crossFade, false);
		}
		catch(e){
			llog("Transition can't be used, there is still one running");
		}
		
		if (undefined !== opt) {
			if ('video' === opt) {
				this.isVideoCapture = true;
			}
			else {
				this.isVideoCapture = false;
			}
		}
		else {
			this.isVideoCapture = !this.isVideoCapture;
		}
		
		if (!fromPrefs) {
			var modeStr = this.isVideoCapture ? 'video' : 'still';
			CameraPrefs.updatePref(this.cameraControl.prefs, CameraControl.PREFS.CAPTURE_MODE, modeStr);
		}

		if (this.isVideoCapture) {
			this.controller.sceneElement.removeClassName('camera');
			this.controller.sceneElement.addClassName('camcorder');
			
		}
		else {
			this.controller.sceneElement.removeClassName('camcorder');
			this.controller.sceneElement.addClassName('camera');
		}

		if (transition) {
			// Transisiton will be null if last transition was still running when the user attempted
			// to toggle the mode again (NOV-92381).
			transition.run();
		}


		if (this.photorollInfo && this.photorollInfo.still && this.photorollInfo.video){
			// Takes a while for any valid photorollinfo to appear.  Skip this step
			// if the indexer hasn't returned any data yet.
			var imgUrl = "";
			
			if (this.isVideoCapture){
				if (!!this.photorollInfo.video.album_video_count && !!this.photorollInfo.video.details.videoPictureUrl) {
					imgUrl = AppAssistant.EFS.exe
						+ this.photorollInfo.video.details.videoPictureUrl
						+ AppAssistant.EFS.savedThumb;
				}
			}
			else {
				if (this.photorollInfo.still.album_image_count) {
					imgUrl = AppAssistant.EFS.exe 
						+ this.photorollInfo.still.album_last_image_thumb 
						+ AppAssistant.EFS.savedThumb;
				}
			}				
			
			llog("Toggling capture mode means updating photoroll image: ", imgUrl);
			this.setPhotoRollImage(imgUrl);
		}

	},

	/**
	 * Handler for click of photoroll button.
	 * 
	 * The photoroll scene will be pushed on.
	 */	
	_handlePhotorollStill: function(){
		this.appManagerService.launchPhotos(
			this.photorollInfo.still.album_id, 
			this.photorollInfo.still.album_name, 
			this.photorollInfo.still.album_image_count, 
			AppAssistant.photoRollPhotoLoader, 
			this.controller);
	},

	_handlePhotorollVideo: function(){
		this.appManagerService.launchVideos(
			this.photorollInfo.video.details.videoPath,
			this.photorollInfo.video.details.videoPictureUrl,
			this.photorollInfo.video.details.videoName,
			this.photorollInfo.video.album_video_count, 
			this.photorollInfo.video.details.videoDuration, 
			this.photorollInfo.video.details.videoSize,			
			AppAssistant.photoRollVideoLoader,
			this.controller);
		
	},

	/**
	 * Blur event handler.
	 * 
	 * called when the application is no longer focus.  Used to grab a screenshot of the preview
	 * and shutdown the video pipeline, plus release the video sink.
	 *  
	 * @param {Event}  event   The event that occured 
	 */
	_onBlur: function(event){
		llog("Got a blur event");

		if (this._blurHandlerTimeout){
			llog("Re-initializing the blurHandler timeout");
			clearTimeout(this._blurHandlerTimeout);
			delete this._blurHandlerTimeout;
		}
		
		if (this._focusHandlerTimeout){
			clearTimeout(this._focusHandlerTimeout);
			delete this._focusHandlerTimeout;
		}
			
		// Set a scrim right now, don't bother waiting for the timeout.
		this.controller.sceneElement.addClassName('preview-off');
		this.controller.sceneElement.style.background = "#404040";	
		this.setScrimImage();

		this._blurHandlerTimeout = setTimeout(function(){
			delete this._blurHandlerTimeout;

			try{
				if (!this.isFocused()){
					this.cameraControl.freezePreview();
	
					GeoControl.stopTracking();
				}
			}
			catch(e){
				llog("Exception thrown: "+Object.toJSON(e));
			}

		}.bind(this), 350);
		
	},

	/**
	 * Focus event handler.
	 * 
	 * Called when the application gets focus.   Used as trigger to resume preview
	 * and re-enable capture.
	 * 
	 * @param {Event} event   The event that occured
	 */	
	_onFocus: function(event){
		llog("Got a focus event");

		if (this._focusHandlerTimeout) {
			llog("Re-initializing the focusHandler timeout");
			clearTimeout(this._focusHandlerTimeout);
			delete this._focusHandlerTimeout;
		}

		if (this._blurHandlerTimeout){
			clearTimeout(this._blurHandlerTimeout);
			delete this._blurHandlerTimeout;
		}
		
		this.controller.sceneElement.style.background = "transparent";	

		this._focusHandlerTimeout = setTimeout(function(){
			delete this._focusHandlerTimeout;
			
			if (this.isFocused()) {
				this.cameraControl.resumePreview();
			}
		}.bind(this), 350);
	},
	
	activate: function(){
		llog("Scene deactivate called");
		this.cameraControl.resumePreview();
		

		try{
			this.controller.stageController.setWindowOrientation("up");
		}
		catch(e){
			llog("CaptureAssistant::activate, doing setWindowOrientation, caught ", Object.toJSON(e.message));
		}
		
		try{
			this.controller.window.PalmSystem.setWindowProperties({suppressBannerMessages:true});		
		}
		catch(e){
			llog("CaptureAssistant::activate, doing setWindowProperties, caught ", Object.toJSON(e.message));
		}
	},
	
	deactivate: function(){
		llog("Scene activate called");
		try{
			this.cameraControl.freezePreview();
			GeoControl.stopTracking();
			
		}
		catch(e){
			llog("Exception thrown: "+Object.toJSON(e));
		}

		try{
			this.controller.window.PalmSystem.setWindowProperties({suppressBannerMessages:false});		
		}
		catch(e){}
	},

	/**
	 *  Return the focus state of the scene.
	 *  
	 *  The state is stored on the stage controller, as the scene could well be popped
	 *  and reloaded due to a reset of the mediaserver, etc.  
	 *  
	 *  @returns {Boolean}   Focus state.
	 */
	isFocused: function(){
		return (this.controller.stageController.active && (this.controller.stageController.topScene().sceneName === 'capture'));
	},

	setPhotorollUpdating: function(busy){
		llog("setPhotorollUpdating: ", busy?"busy":"no busy");
		
		this._setIndexingStyle(busy);

		// Put a safeguard in.  If the photoroll doesn't update within 10 seconds, just remove the spinner anyway.		
		if (busy){
			if (this.prollUpdatingTimeout){
				// If there's a spinner active then reset the timer.
				this.controller.window.clearTimeout(this.prollUpdatingTimeout);
			}
			this.prollUpdatingTimeout = this.controller.window.setTimeout(function(){
				this.setPhotorollUpdating(false);
			}.bind(this), 10000);
		}
		else {
			if (this.prollUpdatingTimeout){
				this.controller.window.clearTimeout(this.prollUpdatingTimeout);
				delete this.prollUpdatingTimeout;	
			}
		} 
	},
	_setIndexingStyle: function(on){
		if (!!on) {
			this.controller.get("capture-controls").addClassName("indexing");

			this.controller.get("capture-thumbnail").setAttribute("style", "opacity: 0.0;");
			this.controller.get("capture-thumbnail-overlay").setAttribute("style", "opacity: 0.0;");
		}
		else{
			this.controller.get("capture-controls").removeClassName("indexing");

			this.controller.get("capture-thumbnail").setAttribute("style", "-webkit-transition-property: -webkit-transform, opacity; -webkit-transition-duration: 0.5s; opacity: 1.0;");
			this.controller.get("capture-thumbnail-overlay").setAttribute("style", "-webkit-transition-property: -webkit-transform, opacity; -webkit-transition-duration: 0.5s; opacity: 1.0;");
		}
	},

	photoHasLoaded: function(event){
		llog("Photo has (", event.type, "), remove spinner...");
		event.target.removeEventListener('load', this.photoHasLoadedHandler, false);
		event.target.removeEventListener('abort', this.photoHasLoadedHandler, false);
		event.target.removeEventListener('error', this.photoHasLoadedHandler, false);
		this.setPhotorollUpdating(false);		
	}
		  
});
