goog.require('goog.structs.Trie');

function AppViewModel() {
	this.matchingDicts = ko.observableArray([]);
	this.currentLoading = ko.observable('...');
	this.term = ko.observable('');
}

function canonicalizePrefix(str) {
	return str.trim().toLowerCase().chars().filter(function(c) {
		return !c.match(/[ ,_.!~*\'()-]/);
	}).join('');
}

/**
 * Show and activate the progress widget.
 */
function setProgressState(running) {
	if (running) {
//		$("#progress").progress("option", "running", true);
//		$("#progress").show();
	} else {
//		$("#progress").progress("option", "running", false);
//		$("#progress").hide();
	}
}

/**
 * The in-memory trie is structured as follows: key: canonicalTerm value: k
 * 
 * k is used instead of ID because ID is just 'Article_' + k
 * 
 * canonicalTerm is lowercased and only accepts a-z + 0..9 TODO: unicode support
 */
function loadTrie(onSuccess, onError) {
	totalTerms = 0;
	var checkSuccess = function() {
		console.info(Object.size(tries) + ' out of ' + Object.size(dicts) + ' tries loaded');
		if (Object.size(tries) >= Object.size(dicts)) {
			console.info(Object.size(tries) + ' tries loaded ' + totalTerms + ' terms');
			// all dicts loaded
			onSuccess(totalTerms);
		}
	}
	
	for (var dictName in dicts) {
		if (!Object.has(tries, dictName)) {
			(function(dictName) {
				var trieUri = dictName + '/dict-trie.json';
				console.info('Loading ', trieUri, '...');
				
				$.ajax({
                    dataType: 'json',
                    url: trieUri,
                    success: function(data) {
                        totalTerms += Object.size(data);
                        console.info(trieUri + ' returned ' + Object.size(data) + ' terms');
                        tries[dictName] = new goog.structs.Trie(data);
                        console.info('Trie ' + dictName + ' built');
                        checkSuccess();
                    },
                    error: function(event, jqxhr, exception) {
                        console.error('Cannot load', trieUri, jqxhr, exception);
                        onError(trieUri);
                    }
                });
			})(dictName);
		}
	}
	
	checkSuccess();
}

// Initialize functions
$(function() {
//	// add eventListener for tizenhwkey
//	document.addEventListener('tizenhwkey', function(e) {
//		var activePage = $.mobile.activePage.attr('id');
//		
//		if (e.keyName == "back") {
//			if (activePage == 'aboutPage')
//				$.mobile.back();
//			else
//				tizen.application.getCurrentApplication().exit();
//		}
//		if (e.keyName == "menu")
//			if (activePage == 'mainPage')
//				// https://developer.tizen.org/forums/web-application-development/open-context-popup-hardware-menu-button-press
//				setTimeout(function() { $.mobile.activePage.find('.menuBtn').click() }, 0);
//	});
    console.debug('Applying Knockout bindings');
	appViewModel = new AppViewModel();
	ko.applyBindings(appViewModel);
	
	var searchSeq = 0;
	$('#searchFld').bindWithDelay('keyup', function(e) {
		searchSeq++;
		var mySearchSeq = searchSeq;
		var term = $('#searchFld').val();
		var canonicalTerm = canonicalizePrefix(term);
		if (canonicalTerm.length >= 1) {
			console.log("Searching! " + term + " / " + canonicalTerm);
			
			var foundTerms = 0;
			var matchingDictsCleared = false;
			for (var dictName in dicts) {
				var found = tries[dictName].getKeys(canonicalTerm).to(MAX_RESULTS_PER_DICT);
				foundTerms += found.length;
				if (!found.isEmpty()) {
					// sort first, because Trie doesn't guarantee that frog < frogman
					//found = found.sortBy();
					console.debug('Found ' + found.length + ' in ' + dictName + ': ' + found.join(', '));
					$('#emptyTerm').hide();
					$('#notFound').hide();
					
//					appViewModel.matchingArticles(found.map(function(e) { return {k: '...', def: '...'}; }));
					if (!matchingDictsCleared) {
						appViewModel.matchingDicts([]);
						matchingDictsCleared = true;
					}
					
					var matchingArticles = ko.observableArray([]);
					appViewModel.matchingDicts.push({name: dicts[dictName].name, articles: matchingArticles});
					// db.allDocs({keys: keys, include_docs: true}, function(err,
					// result) {
					// // result is total_rows, offset, rows, where:
					// // rows: array, each contains: doc, id, key, value
					// var articles = result.rows.map(function(r) { return r.doc;
					// });
					// console.debug('Articles:', articles.length, articles);
					// appViewModel.matchingArticles(articles);
					// });
					found.forEach(function(trieKey, idx) {
						var k = tries[dictName].get(trieKey);
						// I truly *wish* UTF-8 filenames would work: https://developer.tizen.org/forums/web-application-development/error-signature_invalid-after-updating-sdk-2.2.1#comment-8777
						//var basename = encodeURIComponent(k.trim().toLowerCase().substring(0, 3).replace(new RegExp('[ :/\\,-.!~*\'\"()]', 'g'), '_'));
						// must double the URI encoding because the filename itself is URI encoded,
						// then we must URI encode again in order to access as proper URI
						// JavaScript's encodeURIComponent is pretty stupid, the only 3 safe symbol chars are _.-
						// !    ~     *     '     (     )
						// %21  %7E   %2A   %27   %28   %29'
						var basename = encodeURIComponent(encodeURIComponent(k.trim().toLowerCase().substring(0, 3))
							.replace('~', '%21').replace('~', '%7E').replace('*', '%2A').replace('\'', '%27').replace('(', '%28').replace(')', '%29')
						);
						var articleUri = dictName + '/' + basename + '.json';
						(function(matchingArticles) {
                            console.debug('get article "' + articleUri + '" for "' + k + '"');
							$.ajax({
                                dataType: 'json',
                                url: articleUri,
                                success: function(data) {
                                    if (mySearchSeq == searchSeq) {
//                                        console.debug('got article', mySearchSeq, data);
                                        var article = data[k];
                                        article.k = k;
                                        //console.debug('Get article', id, result);
                //						appViewModel.matchingArticles()[idx] = article; // not working
                                        matchingArticles.push(article);
                                        matchingArticles.sort(function(left, right) {
                                            return left.k.toLowerCase().localeCompare(right.k.toLowerCase());
                                        });
                                    } else {
                                        console.debug('Ignoring stale mySearchSeq ' + mySearchSeq + ', latest searchSeq is ' + searchSeq);
                                    }
							     }
                            });
						})(matchingArticles);
					});
				}
			}

			if (foundTerms == 0) {
				console.debug('Not Found:', canonicalTerm);
				appViewModel.matchingDicts([]);
				appViewModel.term(term);
				$('#emptyTerm').hide();
				$('#notFound').show();
			}
		} else {
			$('#notFound').hide();
			$('#emptyTerm').show();
			console.debug('Empty term');
			appViewModel.matchingDicts([]);
		}
//		TODO: in App Framework: no method scrollview. $($.ui.activeDiv).scrollview('scrollTo', 0, 0);
	}, 250);
	
});

var init = function() {
	// TODO:: Do your initialization job
	console.log("pageinit(*) called");
	
};
$.ui.ready(init);

$(document).on('loadpanel', function(event) {
    console.debug('loadpanel:', event.target.id);
    switch (event.target.id) {
    case 'loadingPage': {
        loadAllSelectiveFunc = function() {
//            $("#loadingPage .progress").progress("option", "running", true);
//            $("#loadingPage .progress").show();
            appViewModel.currentLoading('Loading Trie');

            loadTrie(function(articleCount) {
                $.ui.loadContent('#mainPage', false, true);
                setTimeout(function() {
//                    $('#mainPage .notification').notification('text', 'Indexed ' + articleCount + ' headwords.');
//                    $('#mainPage .notification').notification('open');
                }, 400);
            }, function(trieUri) {
//                $('#loadingPage .notification').notification('text', 'Cannot load ' + trieUri);
//                $('#loadingPage .notification').notification('open');
            });
        }
        $('#loadingPage .loadAllSelective').click(loadAllSelectiveFunc);

        setTimeout(loadAllSelectiveFunc, 250); // give ample time, please!
        break;
    }
    case 'mainPage': {
        setTimeout(function() {
            setProgressState(true);
            loadTrie(function(articleCount) {
                setProgressState(false);
    //			$('#mainPage .notification').notification('text', 'Indexed ' + articleCount + ' headwords.');
    //			$('#mainPage .notification').notification('open');
            }, function(trieUri) {
                setProgressState(false);
//                $('#mainPage .notification').notification('text', 'Cannot load ' + trieUri);
//                $('#mainPage .notification').notification('open');
            });
        }, 250); // give ample time, please!
        break;
    }
    case 'aboutPage': {
        break;
    }
    }
});
