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

Photos.Scene.Home = Class.create(Photos.Scene.Scroll, Photos.Common.Opacity, {
	setup: function($super) {
		this.spinnerModel = {spinning: false};
		this.onlineModel = {items: []};
		this.thumbLoader = new Photos.Common.RowRequester(
						this.controller.window);

		Photos.Service.getState(
			this.handleServiceState.bind(this), this.controller);

		this.onlineList = this.controller.get('online_list');
		this.offlineList = this.controller.get('offline_list');
		this.photoRollButton = this.controller.get('photoroll');

		$super(this.offlineList, {
			itemTemplate:
				this.templatePrefix + 'home/offline-entry',
			filterFunction: this.getOfflineAlbums.bind(this),
			onItemRendered: this.offlineAlbumRendered.bind(this),
			initialAverageRowHeight: 84
		}, 80);
		this.controller.setupWidget('scan-spinner', {
			spinnerSize: 'large'
		}, this.spinnerModel);
		this.controller.setupWidget('online_list', {
			itemTemplate: this.templatePrefix + 'home/online-group',
			onItemRendered: this.accountRendered.bind(this)
		}, this.onlineModel);

		this.autoListen(this.photoRollButton,
			Mojo.Event.tap, this.photoRollTapped.bind(this));
		this.autoListen(this.onlineList, Mojo.Event.listTap,
			this.onlineTapped.bind(this));
	},

	accountRendered: function(widget, model, node) {
		function gotFriendsRecentPhotos(results) {
			if (!results || !results.photos) {
				Mojo.Log.error("Failed to get friends recent photos.");
				return;
			}
			var limit = Math.min(results.photos.length, 3);
			var element = node.down(".friends .thumb-container")
			element.update(Mojo.View.render({
				template: this.templatePrefix +
							"home/thumbcontainer",
				object: {
					row: 3,
					imagesTotal: limit,
					thumbsTotal: limit 
				}
			}));

			var holderNode = element.down(".image-holder");
			for (var i = 0; i < limit; ++i) {
				var imgNode = this.controller.document.createElement('img');
				imgNode.src = results.photos[i].icon;
				holderNode.appendChild(imgNode);
			}
		}

		this.controller.serviceRequest(
			'palm://com.palm.photo.facebook', {
				method: "getNewContactPhotos",
				onSuccess: gotFriendsRecentPhotos.bind(this),
				parameters: {accountTag: model.accountTag}
		});
	},

	offlineAlbumRendered: function(widget, model, node) {
		this.rowRequester.load(
			model.rowCount,
			this.requestAlbumImages.bind(
				this, model.albumID, node, model.rowCount));
	},

	onlineTapped: function(event) {
		var target = event.originalEvent.target.up(".palm-row");
		if (!target) {
			Mojo.Log.error("No target in online tap.");
			return;
		}

		if (target.hasClassName("self")) {
			this.pushWithTemplate(null, 'thumbs', {
				model: new Photos.Model.FacebookThumbs(
					event.item.albumID,
					event.item.albumName)
			});
		} else if (target.hasClassName("albums")) {
			this.pushWithTemplate(null, 'albums', {
				model: new Photos.Model.FacebookAlbums(
					event.item.accountID,
					event.item.contactID,
					event.item.accountName)
			});
		} else if (target.hasClassName("friends")) {
			this.pushWithTemplate(null, 'friends', {
				model: new Photos.Model.FacebookFriends(
					event.item.accountID,
					event.item.accountName)
			});
		} else {
			Mojo.Log.error("Couldn't find online list tap!");
		}
	},

	handleSelection: function(event) {
		this.pushWithTemplate(event, 'thumbs', {
			model: new Photos.Model.LocalThumbs(
				event.item.albumID, event.item.albumName)
		});
	},

	photoRollTapped: function(event) {
		if (!this.photoRollDetails) {
			Mojo.Log.error("We haven't found the photo " +
				"roll details yet to tap on.");
			return;
		}

		this.pushWithTemplate(event, 'thumbs', {
			model: new Photos.Model.LocalThumbs(
				this.photoRollDetails.albumID,
				this.photoRollDetails.albumName)
		});
	},

	aboutToActivate: function(callback) {
		this.resume();
		// we do some manual stuff because of the fake index.
		callback();
 
 		// reset items, we may have added an account between scene
		// changes. best we can do until subscribe.
 		this.onlineModel.items = [];
		this.controller.modelChanged(this.onlineModel);

		function gotAccountList(response) {
			
			if (!response || !response.accounts) {
				Mojo.Log.error("No photo accounts returned.");
				return;
			}

			function gotUserDetails(aid, response) {
				if (!response || !response.details) {
					Mojo.Log.error("Couldn't get user details from account list." + aid);
					return;
				}

				this.onlineModel.items.push({
					accountName: response.details.name,
					accountID: aid,
					contactID: response.details.cid,
					accountTag: aid
				});

				this.controller.modelChanged(this.onlineModel);
			}

			for (var a = 0; a < response.accounts.length; a++) {
				var account = response.accounts[a];
				this.controller.serviceRequest(
					'palm://com.palm.photo.facebook', {
					method: "getLoggedinUserDetails",
					onSuccess: gotUserDetails.bind(
						this, account.accountTag),
					parameters: {
						accountTag: account.accountTag
					}
				});
			}
		}
	},

	requestAlbumImages: function(albumID, node, row, complete, subscribe) {
		if (!node.parentNode) {
			//Mojo.Log.info("Removed node before row use!", row);
			complete();
			return;
		} else if (node.down(".thumb-container").firstChild) {
			//Mojo.Log.info("Node already has content.", row);
			complete();
			return;
		}
		Photos.Service.listImages(
			0, 3, null, albumID, !!subscribe,
			this.handleImageResults.bind(
				this,
				node.down(".thumb-container"), row, complete),
			this.controller);
	},

	getOfflineAlbums: function(filter, widget, offset, limit) {
		if (filter != this.lastFilter) {
			this.rowRequester.dropRequests();
			this.lastFilter = filter;
		}

		if (filter) {
			this.onlineList.hide();
			this.photoRollButton.hide();
		} else {
			this.onlineList.show();
			this.photoRollButton.show();
		}

		var self = this;
		function translate(response) {
			if (!response || !response.returnValue) {
				return;
			}

			self.subscribedAlbums = true;
			for (var i = 0, len = response.albums.length;
								i < len; i++) {
				var album = response.albums[i];
				switch (album.albumPath) {
				case "/media/internal/screencaptures":
					album.albumName = $L("Screen captures");
					break;
				case "/media/internal/Messaging":
					album.albumName = $L("Messaging");
					break;
				case "/media/internal/wallpapers":
					album.albumName = $L("Wallpapers");
					break;
				case "/media/internal/downloads":
					album.albumName = $L("Downloads");
					break;
				}
 				album.rowCount = offset + i;
			}

			var total = parseInt(response.albumsTotal, 10);
			self.pause();
			self.offlineList.mojo.setCount(total);
			self.offlineList.mojo.noticeUpdatedItems(
						offset, response.albums);
			self.offlineList.mojo.setLength(total);
			self.resume();
			self.ready();
		}

		Photos.Service.listAlbums(
			offset, limit, filter, translate, this.controller);
	},

	extractfsParams: ":63:63:4",
	handleImageResults: function(element, row, complete, response) {
		if (!response.images) {
			complete();
			return;
		}

		element.update(Mojo.View.render({
			template: this.templatePrefix + "home/thumbcontainer",
			object: {
				row: row % 4,
				imagesTotal: response.imagesTotal,
				thumbsTotal: response.images.length
			}
		}));

		var holderNode = element.down(".image-holder");
		for (var i = 0; i < response.images.length; ++i) {
			var imgNode = this.controller.document.createElement(
									'img');
			var imgModel = response.images[
					response.images.length - (i + 1)];
			holderNode.appendChild(imgNode);
			this.thumbLoader.load(row, this.loadImage.bind(
				this,
				Photos.Common.extractfsPath +
					encodeURIComponent(
						imgModel.imagePictureUrl) +
					this.extractfsParams,
				imgModel.imagePath,
				element,
				holderNode,
				imgNode));
		}

		// normally indexer will remove the image album, but for the
		// case where we still want to show the photo roll when its
		// empty we should.
		if (!response.images.length) {
			element.hide();
		} else {
			element.show();
		}

		// completes the row requester for albums ipcs.
		complete();
	},

	loadImage: function(
		path, fullPath, rowNode, holderNode, imgNode, complete) {
		if (!rowNode.parentNode) {
			// node removed between ipc request and image load.
			complete();
			return;
		}
		
		imgNode.onload = this.imageDone.bind(
			this, holderNode, imgNode, complete);
		imgNode.onerror = this.retryImageNoThumbnail.bind(
			this, holderNode, imgNode, fullPath, complete);
		imgNode.src = path;
	},

	imageDone: function($super, holderNode, imgNode, complete) {
		if (!holderNode.parentNode) {
			// node removed before image done, pretty easy to
			// trigger with multiple filesystem updates while
			// on another screen.
			$super(holderNode, imgNode, complete);
			return;
		}

		var thumbsSoFar = parseInt(
			holderNode.readAttribute('thumbsSoFar'), 10) + 1;
		var thumbsTotal = holderNode.getAttribute('thumbsTotal');
		holderNode.setAttribute('thumbsSoFar', thumbsSoFar);
		if (thumbsSoFar == thumbsTotal) {
			holderNode.parentNode.down(".count").style.visibility =
				thumbsTotal > 2 ? "visible" : "hidden";
			Mojo.Animation.animateStyle(
				holderNode.parentNode, 'opacity', 'bezier', {
					from: 0.0,
					to: 100.0,
					duration: 0.25,
					curve: 'over-easy',
					styleSetter: this.opacitySetter.bind(
						this, holderNode.parentNode)
				});
		}
		$super(holderNode, imgNode, complete);
	},

	scanState: function(show) {
		this.spinnerModel.spinning = show;
		this.controller.modelChanged(this.spinnerModel);
		this.controller.get('service-scan-div').style.display = 
						(show ? "block" : "none");
	},

	ejectState: function(show) {
		this.controller.get('service-eject-div').style.display = 
						(show ? "block" : "none");
	},

	gotPhotoRoll: function(response) {
		if (!response || !response.returnValue) {
			Mojo.Log.error("Failed to get photo roll.");
			delete this.photoRollDetails;
			return;
		}
		this.photoRollDetails = response.albums[0];
		this.subscribePhotoRoll();
	},

	subscribePhotoRoll: function() {
		if (!this.photoRollDetails) {
			Mojo.Log.error("No details to subscribe to photoroll!");
			return;
		}

		if (this.subscribedPhotoRoll) {
			Mojo.Log.info("Already subscribed to photoroll.");
			return;
		}

		if (this.state != "idle") {
			Mojo.Log.error("Invalid state to get images.");
			return;
		}

		function gotPhotoRollImages(response) {
			if (!response || !response.returnValue) {
				Mojo.Log.error("Failed to get images!");
				return;
			}

			this.subscribedPhotoRoll = true;
		}

		this.requestAlbumImages(
			this.photoRollDetails.albumID, this.photoRollButton,
			2, function(){}, true);
	},

	handleServiceState: function(response) {
		if (!response || !response.returnValue ||
				!response.state || !response.stateCode) {
			Mojo.Log.info("Error, unexpected state response!",
				Object.toJSON(response));
			response.state = "error";
			delete this.subscribedAlbums;
		}

		if (this.state == response.state) {
			Mojo.Log.info("Indexer state same as last.");
			return;
		}
		Mojo.Log.info("Indexer state change:", response.state,
						"(", response.stateCode, ")");

		this.state = response.state;

		switch (this.state) {
		case "init":
		case "scanning":
			this.ejectState(false);
			this.scanState(true);
			break;
		case "idle":
			this.ejectState(false);
			this.scanState(false);
			if (!this.photoRollDetails) {
				Photos.Service.detailPhotoRoll(
					this.gotPhotoRoll.bind(this),
					this.controller);
			} else {
				// state changed to idle, we already got the
				// details. just requery the albums.
				this.subscribePhotoRoll();
			}

			if (!this.subscribedAlbums) {
				this.mainListElement.mojo.setLengthAndInvalidate(1);
			}
			break;
		case "stopped":
			this.ejectState(true);
			this.scanState(false);
			break;
		default:
			this.ejectState(false);
			this.scanState(true);
			break;
		}

		if (this.state != "idle") {
			this.controller.stageController.popScenesTo('home');
		}
	}
});

