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

var SearchAssistant = Class.create(
{
	initialize : function(type, search) 
	{
		Mojo.Log.info("SearchAssistant.initialize");
		
		this._tag = '';
		this._query = '';
		this._category = undefined;
		this._sort = 'by_rating';
		this._installedApps = {};
		
		this['_'+type] = search;
			
		this.searchFieldModel = {
			'original': type == 'query' ? search : ''
		};
	},

	setup: function() 
	{
		Mojo.Log.info("SearchAssistant.setup");
		
		this._searchItemsCallback = this._searchItemsCallback.bind(this);
		this._gotoApp = this._gotoApp.bindAsEventListener(this);
		this._searchAppsKey = this._searchAppsKey.bindAsEventListener(this);
		this._searchApps = this._searchApps.bindAsEventListener(this);
		this._formatAppDivider = this._formatAppDivider.bind(this);

		// Set up the attributes & prepare this widget for lazy loading of data
		this._searchListAttr =
		{
			itemTemplate: 'search/search-appsummary', 
			dividerTemplate: 'search/search-appdivider',
			itemsCallback: this._searchItemsCallback.bind(this),
			formatters: {
				dummy: this._formatAppSummary.bind(this)
			},
			onItemRendered: this._renderedAppSummary.bind(this),
			dividerFunction: (this._sort == 'by_date' ? this._formatAppDivider : null),
			
			// These values have been set after a lot of experimentation 
			// with the list scrolling performance. Since list is loading
			// more items as user scrolls it is critical to get these numbers 
			// right. Don't change before carefully reevaluating scrolling perf.
			// also update this.listRerenderCount
			renderLimit: 40,
			lookahead: 50,
			scrollThreshold: 600 
		};
		
		this.listRerenderCount = 140; // 2*lookahead + renderLimit
		
		this.controller.setupWidget(
			'dv-fa-appslist', 
			this._searchListAttr,
			{}
		);
		this._appsListWidget = this.controller.get('dv-fa-appslist');
		
		// setup search field
		this.searchFieldModel.attributes = {
      		hintText: $L('Search...'),
			focus: false,
	  		enterSubmits: true,
			multiline: false,
			modelProperty: 'original',
			modifierState: Mojo.Widget.steModeSentenceCase,
			focusMode: Mojo.Widget.focusSelectMode,
			requiresEnterKey: true,
			changeOnKeyPress: true,
    	};
    	this.controller.setupWidget(
			'in-fa-search-text', 
			this.searchFieldModel.attributes, 
			this.searchFieldModel
		);
		this._appsSearch = 
		{
			widget: this.controller.get('in-fa-search-text'),
			results: this.controller.get('searchResults'),
			button: this.controller.get('searchResultsModified'),
			count: this.controller.get('tx-fa-totalCountofAppsList')
		};
		
		this._setSearchResultCount();
		
		// Set up a command menu
		this._sortItems =
		{
            items: [
				{
	                icon: "app-icon-filter-date",
	                command: 'by_date'
	            },
				{
	                icon: "app-icon-filter-alpha",
	                command: 'by_name'
	            },
				{
	                icon: "app-icon-filter-rating",
	                command: 'by_rating'
	            },
				{
	                icon: "app-icon-filter-price",
	                command: 'by_price'
	            },
			],
			toggleCmd: this._sort,
		};
        this._sortMenu = 
		{
			items: [
				{},
				this._sortItems,
				{}
			]
		};
		this.controller.setupWidget(Mojo.Menu.commandMenu, { menuClass: 'no-fade', }, this._sortMenu);

		// Menus
		Weave.Utilities.AppMenu.useDefault(this);
		
		this._spinner = new Spinner(this, 'spinner', true, 'large');
		
		// Set default sort ordering
		this._setSortOrder(this._sort);
		
		// get notified when installed applications change
		Catalog.AppDownloadMngr.attach(this);
	},

	cleanup: function() 
	{
		Catalog.AppDownloadMngr.detach(this);
	},

	activate: function() 
	{
		Mojo.Log.info("SearchAssistant.activate");
		
		this._appsListWidget.addEventListener(Mojo.Event.listTap, this._gotoApp);
		this._appsSearch.widget.addEventListener(Mojo.Event.propertyChange, this._searchAppsKey);
		this._appsSearch.button.addEventListener(Mojo.Event.tap, this._searchApps);
		// Refocus search field
		this._appsSearch.widget.mojo.focus();
	},

	deactivate: function() 
	{
		Mojo.Log.info("SearchAssistant.deactivate");
		
		this._appsListWidget.removeEventListener(Mojo.Event.listTap, this._gotoApp);
		this._appsSearch.widget.removeEventListener(Mojo.Event.propertyChange, this._searchAppsKey);
		this._appsSearch.button.removeEventListener(Mojo.Event.tap, this._searchApps);
	},
	
	handleCommand: function(event)
	{
		if (event.type == Mojo.Event.command)
		{
			switch (event.command)
			{
				case 'by_relevance':
				case 'by_date':
				case 'by_name':
				case 'by_rating':
				case 'by_price':
					this._setSortOrder(event.command);
					if (event.command == 'by_date')
					{
						this._searchListAttr.dividerFunction = this._formatAppDivider;
					}
					else
					{
						this._searchListAttr.dividerFunction = null;
						// We have to remove any pending dividers by hand
						this._removeOldDividers();
					}
					this._searchApps();
					break;
					
				default:
					break;
			}
		}
	},
	
	
	// observer method for notifications from AppDownloadMngr
	// called when apps installed on the system change 
	updateInstalledApps: function()
	{
		Mojo.Log.info("SearchAssistant.updateInstalledApps");
		if (this._appsListWidget && this._appsListWidget.mojo) 
		{
			var range = this._appsListWidget.mojo.getLoadedItemRange();
			this._appsListWidget.mojo.noticeUpdatedItems(range.offset, this._appsListWidget.mojo.getItems(range.offset, range.limit));	
		}
	},
	
	_getApplicationInstalledState: function(summary)
	{
		var app = Catalog.AppDownloadMngr.getInstalledApp(summary.publicApplicationId);
		if (app)
		{
			Mojo.Log.info("versions: installed %s download %s", app.installedVersion, summary.appVersion);
			if (Utilities.VersionCheck.compare(app.installedVersion, summary.appVersion) != -1)
			{
				return 'installed';
			}
			else
			{
				return 'update';
			}
		}
		return 'notinstalled';
	},
	
	_searchItemsCallback: function(widget, offset, count)
	{
		Mojo.Log.info('_searchItemsCallback');

		// do this only before we get the first batch of results back
		if (widget.mojo.getLength() === 0) {
			Mojo.Log.info("_searchItemsCallback _setSearchResultCount(undef) & start spinner");
			this._setSearchResultCount();
			this._spinner.start();
			this._setEnableOrderMenu(false);
		}

		var self = this;
		
		Mojo.Log.info("_searchItemsCallback requesting offset: %d count: %d", offset, count);
		Weave.Services.ApplicationServer.searchForApplications(this._query, this._category, offset, count, this._sortOrderServer, 
			Mojo.Locale.current, function(status, apps, total,country){
				
				Mojo.Log.info("CB offset %d, requestedCount %d, status %d, total %d", offset, count, status, total);
				
				// do this only when we get the first batch of results back
				if (widget.mojo.getLength() === 0) {	
					Mojo.Log.info("CB listLen is 0 stop the spinner");
					self._spinner.stop();
					self._setEnableOrderMenu(true);
					self._appsSearch.widget.mojo.focus();
				}
				
				if (status)
				{
					Mojo.Log.info("CB listLen before the update %d", widget.mojo.getLength());
					myProfile.activationCountry = country;
					Mojo.Log.info("Search-Assistant: Activation country %s", myProfile.activationCountry);
					var oldLen = widget.mojo.getLength();
					widget.mojo.noticeUpdatedItems(offset, apps);
					
					// set list len to total results
					if (oldLen === 0) {
						widget.mojo.setLength(total);
					}
					
					self._setSearchResultCount(total);
	
					Mojo.Log.info("CB listLen after update %d", widget.mojo.getLength());
					// No applictions found - display default message
					self.controller.get('dv-fa-appslist-message').style.display = (total == 0 ? 'block' : 'none');
					self._setSort(total > 0);
				}
				else
				{
					// Error
					Utilities.Errors.displayError(apps);
				}
		});
	},
	
	_setSearchResultCount: function(count)
	{
		if (count == undefined) 
		{
			this._appsSearch.results.style.display = 'none';
			this._appsSearch.button.style.display = 'block';
		}
		else 
		{
			this._appsSearch.count.innerText = count;
			this._appsSearch.results.style.display = 'block';
			this._appsSearch.button.style.display = 'none';
		}
	},
	
	_formatAppSummary: function(dummy, model)
	{	
		model.formattedPrice = (model.price === 'Free' || model.price == 0) ? $L("free") : Mojo.Format.formatCurrency(model.price, { fractionDigits: 2, countryCode: myProfile.activationCountry});
		model.formattedFree = ((model.price === 'Free' || model.price == 0) ? 'free' : '');
		model.formattedAverageRating = ('' + (Math.round(model.averageRating * 2) / 2)).replace(/\./, '');
		model.formattedUpdate = (this._getApplicationInstalledState(model) == 'update' ? 'has-update' : '');
		// HACK - author fixup
		model.author = (model.author ? model.author : '&nbsp;');
	},
	
	_formatAppDivider: function(model)
	{
		// We need dividers for date ordered apps.
		// NOTE: Find a faster way to do this!!
		var result = Mojo.Format.formatRelativeDate(Utilities.UTCDate.parse(model.lastModifiedTime), 'short');
		if ( result == $L('today') || result == $L('yesterday') ) {
			return result;
		}
		// everything else should default to the string "older" instead
		return $L('older');
	},
	
	_removeOldDividers: function()
	{
		var divs = this.controller.get('div-fa-search').querySelectorAll('table.palm-list-section-label');
		var len = divs.length;
		for (var i = 0; i < len; i++)
		{
			divs[i].parentNode.removeChild(divs[i]);
		}
	},
	
	_renderedAppSummary: function(widget, model, node)
	{
		new LazyLoadImage(model.appIcon, node.querySelector('.loadingicon'));
	},
	
	_setEnableOrderMenu: function(enable)
	{
		var items = this._sortMenu.items[1].items;
		if (items) 
		{
			for (var i = 0; i < items.length; i++) 
			{
				items[i].disabled = !enable;
			}
			this.controller.modelChanged(this._sortMenu);
		}
	},
	
	_gotoApp: function(event)
	{
		this.controller.stageController.pushScene("details", event.item.id, event.item.publicApplicationId);
	},
	
	_searchApps: function()
	{
		this._appsListWidget.mojo.setLength(0);
		this.controller.getSceneScroller().mojo.revealTop(0);
		//this._appsListWidget.mojo.revealItem(0, true);
		
		// We fire the search by hand, rather than invalidating the list, to avoid the list putting
		// visual junk on the screen while it's updating.
		this._searchItemsCallback(this._appsListWidget, 0, this.listRerenderCount);
	},
	
	_searchAppsKey: function(event)
	{
		//Mojo.Log.info("_searchAppsKey", event.value, event.originalEvent.type, event.originalEvent.keyCode);
		this._query = event.value;
		if (event.originalEvent.type == 'keyup' && event.originalEvent.keyCode == Mojo.Char.enter) 
		{
			this._searchApps();
		}
		else if (this._query == '')
		{
			this._setSearchResultCount(this._appsListWidget.mojo.getLength());
		}
		else
		{
			this._setSearchResultCount();
		}
	},
	
	_orderMappings: 
	{
		'by_date' :	'DATE_DESC', // Newest first
		'by_name' : 'NAME_ASC', // A-Z first
		'by_rating' : 'RATING_DESC', // Best first
		'by_price' : 'PRICE_ASC', // Cheapest first
		'DATE_ASC' : 'DATE_DESC',
		'NAME_ASC' : 'NAME_DESC',
		'RATING_ASC' : 'RATING_DESC',
		'PRICE_ASC' : 'PRICE_DESC',
		'DATE_DESC' : 'DATE_ASC',
		'NAME_DESC' : 'NAME_ASC',
		'RATING_DESC' : 'RATING_ASC',
		'PRICE_DESC' : 'PRICE_ASC',
		'default' : 'DEFAULT'
	},
	
	_setSortOrder: function(order)
	{
		if (this._sortOrder == order) 
		{
			this._sortOrderServer = this._orderMappings[this._sortOrderServer];
		}
		else 
		{
			this._sortOrderServer = this._orderMappings[order];
			this._sortOrder = order;
		}
	},
	
	_setSort: function(enable)
	{
		this._sortMenu.items[1] = enable ? this._sortItems : {};
		this.controller.modelChanged(this._sortMenu);
	}
});


