var appManager = (function() {
	function _createAppItem(app) {
		var div = document.createElement('div');
		div.className = 'app-item';
		div.id = 'app-' + app.uid;
		div.title = app.name;
		div.setAttribute('appid', app.id);
		div.setAttribute('draggable',   'true');
		
		var html = [];
		html.push('		<div>');
		html.push('			<div class="app-item-icon-box">');
		html.push('				<div class="div-table full-size"><div>');
		if (app.type == 1 || app.type == 3) {
			html.push('				<div class="web-clip">');
		} else {
			html.push('				<div class="align-center app-item-icon">');
		}
		
		var icon_url = app.icon_data_url && app.icon_data_url.indexOf("data:image") == 0 ? app.icon_data_url : app.icon_url;
		// Resource page have no priority to access favicon url
		// Data migrated from livemargins could be favicon url, so strip the prefix.
		icon_url = icon_url.replace(/moz-anno:favicon:/i, "");
		var iconClassName = "app-icon";
		if (icon_url && icon_url.indexOf("http") == 0) {
			iconClassName += " app-icon-todataurl";
		}
		html.push('					<img class="' + iconClassName + '" src="' + icon_url + '" />');
		
		html.push('					</div>');
		html.push('				</div>');
		html.push('			</div>');
		html.push('		</div>');
		html.push('		<div align="center">');
		html.push('			<div class="app-op-btn app-del-btn" _title="appcenter.remove"></div>');
		
		if (app.is_local != 1) {
			html.push('			<div class="app-op-btn app-comment-btn" _title="appcenter.viewdetail"></div>');
		}
		
		html.push('			</div>');
		html.push('		</div>');
		html.push('		<div class="app-name-box">');
		html.push('			<span class="text-ellipsis">' + xmlFilter(app.name) + '</span>');
		html.push('		</div>');
		
		div.innerHTML = html.join('');
		
		_addEventListener(div, app);
		return div;
	}
	
	function _addEventListener(aDiv, app) {
		$(aDiv).bind("dragstart", function(event) {
			_appManager.ondragstart(event, app.uid);
		});
		$(aDiv).bind("dragover",  function(event) {
			_appManager.ondragover(event, app.uid);
		});
		$(aDiv).bind("dragenter", function(event) {
			_appManager.ondragenter(event, app.uid);
		});
		$(aDiv).bind("dragleave", function(event) {
			_appManager.ondragleave(event, app.uid);	
		});
		$(aDiv).bind("dragend", function(event) {
			_appManager.ondragend(event, app.uid);	
		});
		$(aDiv).bind("drop", function(event) {
			_appManager.ondrop(event, app.uid);	
		});
		$(".app-item-icon-box", aDiv).click(function(event) {
			_appManager.openApp(app.uid);
		});
		$(".app-item-icon-box", aDiv).mousedown(function(event) {
			$(aDiv).addClass("app-item-active");
		});
		$(".app-item-icon-box", aDiv).mouseup(function(event) {
			$(aDiv).removeClass("app-item-active");
		});
		$(".app-item-icon-box", aDiv).mouseover(function(event) {
			$(aDiv).removeClass("app-item-active");
		});
		$(".app-del-btn", aDiv).click(function(event) {
			 _appManager.unbookmarkApp(app.uid);
		});
		$(".app-comment-btn", aDiv).click(function(event) {
			_appManager.commentApp(app.uid);
			 _$t.track(_$t.app.type, _$t.app.actions.COMMENT_APP, 0);	
		});
		$(".app-name-box", aDiv).click(function(event) {
			 _appManager.onStartChangeAppName($(".app-name-box > span", aDiv)[0], app.uid);
		});
		$("img.app-icon-todataurl", aDiv).bind("load", function(event) {
			_appManager.onAppIconLoaded(this, app.uid);
		});
	}
	
	function _initAppList() {
		// reset _startIdx
		_startIdx = 0;
		_$('apps-box').innerHTML = '';
		_autoFillWithApps();
		_checkIfEmpty();
	}
	
	function _checkIfEmpty() {
		// if (contentAPI.appCenterDAO.getBookmarkedAppCount() == 0) {
		// app-item div with hidden class is an app which has been removed.
		
		$("#local-apps-box").removeClass("search-empty");
		if ($("#apps-box div.app-item").length - $("#apps-box div.app-item[class*=hidden]").length == 0) {
			$("#local-apps-box").addClass("empty");
			if (!!_keyword) {
				$("#local-apps-box").addClass("search-empty");
			}
		} else {
			$("#local-apps-box").removeClass("empty");
		}
	}
	
	var _interval = null;
	var _size = 40;
	var _startIdx = 0;
	function _fillWithAppList() {
		var size = _size;
		// Fullfill all the realestate when apps is loaded.
		if (_startIdx == 0) {
			var height = $("#content-box").height();
			var width = $("#content-box").width();
			var initRows = Math.floor(height / 130) + (height % 130 > 0 ? 1 : 0);
			var initCols = Math.floor((width - 25)/ 110);
			size = initRows * initCols;
		}
		
		var apps = contentAPI.appCenterDAO.getBookmarkedApps(_startIdx, size);
		_startIdx += apps.length;
		apps.forEach(function(app) {
			if (!_$("app-" + app.uid)) {
				_$('apps-box').appendChild(_createAppItem(app));
			}
		});
		_checkIfEmpty();
		return apps.length;
	}
	
	function _autoFillWithApps() {
		function checkScrollbar() {
			// Only do checking when apps-box is shown
			if ($("#local-apps-box").css("display") == "none") {
				return;
			}
			
			// check if total equals current number.
			var total = contentAPI.appCenterDAO.getBookmarkedAppCount();
			var current = $("#apps-box > div.app-item").length;
			if (total == current) {
				return;
			}
			
			var box = _$("local-apps-box");
			// Show more history when scrollbar is not shown
			if (box.clientHeight == box.scrollHeight) {
				_fillWithAppList();
				return;
			}
			
			// Show more history when scrollbar is scrolled to bottom.
			// 130: height of an app item.
			if (box.clientHeight + box.scrollTop > box.scrollHeight - 10) {
				_fillWithAppList();
				return;
			}
		}
		checkScrollbar();
		_interval = window.setInterval(checkScrollbar, 500);
	}
	
	var _trackerTimeout = null;
	function _searchApp(keyword) {
		// stop scrollbar checking interval.
		window.clearInterval(_interval);
		
		_$('apps-box').innerHTML = '';
		
		contentAPI.appCenterDAO.query('SELECT * FROM apps WHERE bookmark  = 1 AND (name LIKE :keyword OR description LIKE :keyword)', {
			keyword: '%' + keyword + '%'	
		}).forEach(function(app) {
			_$('apps-box').appendChild(_createAppItem(app));
		});
		
		_checkIfEmpty();
		
		window.clearTimeout(_trackerTimeout);
		_trackerTimeout = window.setTimeout(function() {
			_$t.track(_$t.app.type, _$t.app.actions.SEARCH_APP, 0);
		}, 1000);
	}
		
	/***** functions to handle app related action triggered by other app center pages. ***/
	function onUnbookmarkApp(uid) {
		$("#app-" + uid).addClass("hidden");
		_checkIfEmpty();
	}
	
	function onHideUnbookmarkUndoMsg(uid) {
		var div = document.getElementById('app-' + uid);
		if (div) {
			$(div).remove();
		}
	}
	
	function onChangeAppName(uid) {
		// reload app name from database.
		var appName = contentAPI.appCenterDAO.getAppName(uid);
		var div = _$('app-' + uid);
		div.title = appName;
		
		var nameBox = $(div).find('div.app-name-box')[0];
		var originSpan = $(div).find('div.app-name-box > span')[0];
		
		var span = document.createElement('span');
		span.className = originSpan.className;
		span.textContent = appName;
		
		nameBox.innerHTML = '';
		nameBox.appendChild(span);
	}
	
	function onBookmarkApp(uid) {
		if (_$('app-' + uid)) {
			$('#app-' + uid).removeClass("hidden");
			_checkIfEmpty();
			return;
		}
		_$('apps-box').appendChild(_createAppItem(contentAPI.appCenterDAO.getAppByUID(uid)));
	}
	
	function onSetAppLocal(uid) {
		var appItem = _$('app-' + uid);
		if (!appItem) {
			return;
		}
		
		$(appItem).find('.app-comment-btn')[0].style.display = 'none';
	}
	
	function onSetAppUnlocal(uid) {
		var appItem = _$('app-' + uid);
		if (!appItem) {
			return;
		}
		
		$(appItem).find('.app-comment-btn')[0].style.display = '';
	}
	/***** end *****/
	
	function _moveAppElem(source, target, behindIt) {
		var sourceElem = _$('app-' + source);
		var targetElem = _$('app-' + target);
		
		if (!targetElem || !sourceElem) {
			return;
		}
		
		if (behindIt) {
			if (targetElem.nextSibling) {
				_$('apps-box').insertBefore(sourceElem, targetElem.nextSibling);
			} else {
				_$('apps-box').appendChild(sourceElem);
			}
		} else {
			_$('apps-box').insertBefore(sourceElem, targetElem);
		}
	}
	
	function reBookmarkApp(uid) {
		contentAPI.appCenter.bookmarkApp(uid, true);
		$("#app-" + uid).removeClass("hidden");
		contentAPI.appCenter.appPref.updatePref('bookmark', uid, _observer);
	}
	
	function unbookmarkApp(uid) {
		contentAPI.appCenter.bookmarkApp(uid, false);
		$("#app-" + uid).addClass = "hidden";
		contentAPI.appCenter.appPref.updatePref('unbookmark', uid, _observer);
	}
	
	function bookmarkApp(uid) {
		contentAPI.appCenter.bookmarkApp(uid, true);
		onBookmarkApp(uid);
		contentAPI.appCenter.appPref.updatePref('bookmark', uid, _observer);
	}
	
	function makeUnbokmarkUndoable(uid) {
		Widgets.UndoMaker.make(_("appcenter.info.undoremove"), function() {
			reBookmarkApp(this);
		}.bind(uid), function() {
			onHideUnbookmarkUndoMsg(this);
			contentAPI.appCenter.appPref.updatePref('hideunbookmarkundomsg', this, _observer);
		}.bind(uid));
		
		unbookmarkApp(uid);
	}
	
	function makeChangeNameUndoable(uid, newname) {
		var originName = contentAPI.appCenterDAO.getAppName(uid);
		Widgets.UndoMaker.make(_("appcenter.info.undorename"), function(name) {
			contentAPI.appCenterDAO.changeAppName(this, name.toString());
			onChangeAppName(this);
			contentAPI.appCenter.appPref.updatePref('changename', this, _observer);
		}.bind(uid, originName));
			
		contentAPI.appCenterDAO.changeAppName(uid, newname);
		// update title
		_$('app-' + uid).title = newname;
		contentAPI.appCenter.appPref.updatePref('changename', uid, _observer);
	}
	
	var _observer = {
		onChangeName: function(uid) {
			onChangeAppName(uid);
			_$t.track(_$t.app.type, _$t.app.actions.CHANGE_NAME, uid);
		}, 
		
		onUnbookmark: function(uid) {
			onUnbookmarkApp(uid);
		},
		
		onBookmark: function(uid) {
			onBookmarkApp(uid);
		},
		
		onHideUnbookmarkUndoMsg: function(uid) {
			onHideUnbookmarkUndoMsg(uid);
		},
		
		onSetLocal: function(uid) {
			onSetAppLocal(uid);
		},
		
		onSetUnLocal: function(uid) {
			onSetAppUnlocal(uid);
		},
		
		onMoveApp: function(args) {
			var uidPair = args.split('$$$$');
			if (uidPair.length != 3) {
				return;
			}
			_moveAppElem(uidPair[0], uidPair[1], uidPair[2] == 1 ? true : false);
		}
	};
	
	function _getOffset(node, topParent) {
	    if (node.parentNode == document.documentElement || node.parentNode == topParent) {
	        return {
				top: node.offsetTop,
				left: node.offsetLeft
			};
	    }
	    
	    var offsetPos = {
	        top: node.offsetTop,
	        left: node.offsetLeft
	    };
	
	    var parentOffset = _getOffset(node.parentNode, topParent);
	    offsetPos.top += parentOffset.top;
	    offsetPos.left += parentOffset.left;
	
	    return offsetPos;
	}
	
	var _dragPosDiv = null;
	function _showDragPos(node, behindIt) {
		if (null == _dragPosDiv) {
			_dragPosDiv = document.createElement('div');
			_dragPosDiv.className = "drag-pos-indicator";
			$('#local-apps-box')[0].appendChild(_dragPosDiv);
		}
		
		var pos = _getOffset(node, $('#local-apps-box')[0]);
		_dragPosDiv.style.display = 'block';
		_dragPosDiv.style.top = pos.top + node.offsetHeight + 'px';
		if (behindIt) {
			_dragPosDiv.style.left = pos.left + node.offsetWidth + _dragPosDiv.offsetWidth / 2 - 6 + 'px';
		} else {
			_dragPosDiv.style.left = pos.left - _dragPosDiv.offsetWidth / 2 - 10 + 'px';
		}
	}
	
	function _hideDragPos() {
		_dragPosDiv.style.display = 'none';
	}
	
	var _initialized = false;
	var _keyword = null;
	var _openingTimeout = null;
	
	var _appManager = {
		init: function() {
			if (_initialized) {
				return;
			}
			_initialized = true;
			appManager.initAppList();	
		},
		
		openApp: function(uid) {
			function _setOpenFlag() {
				window.clearTimeout(_openingTimeout);
				_openingTimeout = window.setTimeout(function() {
					window.clearTimeout(_openingTimeout);
					_openingTimeout = null;
				}, 500);
			}
			
			// Sometimes, if user double click on app icon to open an app.
			// The window frame of the app will be broken, which means windowTools acts abnormally.
			// So set an timeout to make sure that opening action could be triggered only once in 500ms.
			if (_openingTimeout) {
				_setOpenFlag();
				return;
			}
			
			_setOpenFlag();
			contentAPI.appCenter.openApp(uid);
		},
		
		bookmarkApp: function(uid) {
			bookmarkApp(uid);
		},
		
		unbookmarkApp: function(uid) {
			makeUnbokmarkUndoable(uid);
		},
		
		changeAppName: function(uid, newname) {
			if (!newname || '' == newname.trim()) {
				return;
			}
			
			makeChangeNameUndoable(uid, newname);
		},
		
		initAppList: function() {
			_initAppList();
		},
		
		searchApp: function(keyword) {
			_keyword = keyword;
			if (!keyword) {
				this.showAll();
				return;
			}
			
			contentAPI.setLocation(_$('web-apps-frame'), appManager.appcenterDomain + 'search/?q=' + encodeURIComponent(keyword));
		},
		
		addObserver: function() {
			contentAPI.appCenter.appPref.addObserver(_observer);
		},
		
		removeObserver: function() {
			contentAPI.appCenter.appPref.removeObserver(_observer);
		},
		
		commentApp: function(uid) {
			// Switch to install view and show app detail page.
			_$('web-apps-frame').src = this.appcenterDomain + 'detail/uid/' + uid + '/';
			switchView('tab-install');
//			new Widgets.IFramePromptDialog({
//				location: this.appcenterDomain + 'comment/' + uid + '/'
//			});
		},
		
		showAll: function() {
			_keyword = null;
			contentAPI.setLocation(_$('web-apps-frame'), appManager.appcenterDomain);
			_$('search_input_install').value = '';
		},
		
		resizeAppBox: function(event) {
			// body's heigth - header's height - box's border
			var height = document.body.clientHeight - document.body.querySelectorAll('#layout > div')[0].clientHeight - 2;
			_$('local-apps-box').style.height = height + 'px';
		},
		
		get appcenterDomain() {
			return contentAPI.getPref('appcenter');
		},
		
		ondragstart: function(event, uid) {
			event.dataTransfer.setData('text/app-uid', uid);
			event.dataTransfer.effectAllowed = 'move';
			event.dataTransfer.dropEffect = 'move';
		},
		
		ondragover: function(event, uid) {
			if (event.dataTransfer.getData('text/app-uid')) {
				event.preventDefault();
			}
			
			var elem = _$('app-' + uid);
			var behindIt = event.clientX > _getOffset(elem).left + elem.offsetWidth / 2;
			_showDragPos(_$('app-' + uid), behindIt);
		},
		
		ondragenter: function(event, uid) {
			if (event.dataTransfer.getData('text/app-uid')) {
				event.preventDefault();
			}
		},
		
		ondragleave: function(event, uid) {
			_hideDragPos();
		},
		
		ondragend: function(event, uid) {
			_hideDragPos();
		},
		
		ondrop: function(event, uid) {
			function _getAppPos(uid) {
				return contentAPI.appCenterDAO.getAppPositionByUId(uid);
			}
			
			event.preventDefault();
			
			var elem = _$('app-' + uid);
			var behindIt = event.clientX > _getOffset(elem).left + elem.offsetWidth / 2;
			
			var source = event.dataTransfer.getData('text/app-uid');
			if (source && source != uid) {
				var origPos = _getAppPos(source);
				var targetPos = _getAppPos(uid);
				
				if (origPos == targetPos) {
					return;
				} else if (behindIt) {
					contentAPI.appCenterDAO.moveAppByUID(source, targetPos);
				} else {
					contentAPI.appCenterDAO.moveAppByUID(source, targetPos - 1);
				}
				
				contentAPI.appCenter.appPref.updatePref('moveapp', source + '$$$$' + uid + '$$$$' + (behindIt ? 1 : 0), _observer);
				_moveAppElem(source, uid, behindIt);
			}
			
			_hideDragPos();
			
			_$t.track(_$t.app.type, _$t.app.actions.DRAG_APP, 0);
		},
		
		onStartChangeAppName: function(node, uid) {
			Widgets.AppNameModifier.start(node, {
				onStart: function() {
					// If do not set draggable with false
					// Name input element can not be focused by clicking.
					_$('app-' + uid).draggable = false;
				}, 
				
				onComplete: function(value) {
					if (node.textContent != value) {
						appManager.changeAppName(uid, value);
					}
					_$('app-' + uid).draggable = true;
				}
			});
		},
		
		onAppIconLoaded: function(img, uid) {
			contentAPI.appCenterDAO.updateIconDataUrl(uid, contentAPI.getImageDataURL(img));
		}
	};
	
	return _appManager;
})();

registerInitListener(function(event) {
	appManager.addObserver();
	_$('search_input_install').value = '';
	// resize app box.
	appManager.resizeAppBox(event);
});

window.addEventListener('resize', appManager.resizeAppBox, false);

window.addEventListener('unload', function() {
	appManager.removeObserver();
}, false);