function Application() {
	this.navigation = layer.get('navigation');
	this.browser = layer.get('browser');
	this.content = layer.get('content');
	this.resizegrip = layer.get('resizegrip');
	this.initialized = false;
}

Application.prototype.initialize = function() {
	this.browserwidth = 200;

	this.min_browser_width = 170;
	this.min_content_width = 50;

	var bw = browser.getcookie('application_browserwidth');
	if (bw) {
		var max_bw = browser.clientWidth() - this.min_content_width;
		if ( (bw>=this.min_browser_width) && (bw<=max_bw) ) this.browserwidth = bw;
	}

	this.resizer = new Resizer(this);
	this.resizer.register('resizegrip',this.resize_start,this.resize_move,this.resize_done);

	this.rpc = new RPCClient('rpc.php','application.rpc',1);
	this.rpc.caching = true;
	this.rpc.set_callback('chmreader.fetch_index_by_keyword','application.set_index_terms');
	this.rpc.set_callback('chmreader.fetch_index_by_parent','application.index_set_items');
	this.rpc.set_callback('chmreader.fetch_toc','application.contents_set_items');
	this.rpc.set_callback('chmreader.fetch_search_by_keyword','application.search_set_items');
	this.rpc.set_callback('chmreader.fetch_toc_hierarchy_by_url','application.contents_set_selected');
	this.rpc.set_callback('chmreader.fetch_toc_hierarchy_by_id','application.contents_set_selected');

	this.tabset = new TabSet('browsertabs','application.tabset');
	this.tabset.add('Contents',this.page_changed,'browser_contents');
	this.tabset.add('Index',this.page_changed,'browser_index');
	this.tabset.add('Search',this.page_changed,'browser_search');
	this.tabset.select(0);
	
	this.resize();
	
	// create the contents treeview
	this.contents_treeview = new TreeView('browser_contents_list','application.contents_treeview','./');
	this.contents_treeview.onfetchitems = this.contents_fetch_items;
	this.contents_treeview.callback = this.launch_entry;
	// populate the contents treeview since it's the first thing we'll see
	this.contents_fetch_items(0);

	this.index_treeview = new TreeView('browser_index_list','application.index_treeview','./');
	this.index_treeview.onfetchitems = this.index_fetch_items;
	this.index_treeview.callback = this.launch_entry;
	
	var index_term = layer.get('browser_index_term');
	index_term.onsuggest = this.index_term_suggest;
	index_term.ondownarrow = this.index_term_downarrow;
	index_term.onkeyup = this.index_term_keyup;
	
	this.last_index_keyword = '';
	this.index_term_launch = false;

	this.inputfield = new InputField('application.inputfield');
	this.inputfield.register_field(index_term);
	
	this.search_treeview = new TreeView('browser_search_list','application.search_treeview','./');
	//this.search_treeview.onfetchitems = this.search_fetch_items;
	this.search_treeview.callback = this.launch_entry;

	var search_term = layer.get('browser_search_term');
	search_term.onkeyup = this.search_term_keyup;

	this.urlidcache = new Array();
	
	this.initialize_toolbar();

	this.initialized = true;
	this.first_contents_poll = true;

	if (window.opendocumentparents && (window.opendocumentparents.length>0) ) {
		this.contents_open_recursive = window.opendocumentid;
		this.contents_open_parents = window.opendocumentparents;
		this.contents_open_lastparent = 0;
	}
	
}

Application.prototype.initialize_toolbar = function() {
	var tb = layer.get('navigation');
	if (!tb) return;
	for (var i=0; i<tb.childNodes.length; i++) {
		var item = tb.childNodes[i];
		if (item.className=='navbutton') {
			item.onmouseover = this.toolbar_over;
			item.onmouseout = this.toolbar_out;
			item.onmousedown = this.toolbar_down;
			item.onmouseup = this.toolbar_up;
		}
	}
}
Application.prototype.toolbar_over = function() {
	this.className = 'navbutton navbutton_over';
	this.isover = true;
}
Application.prototype.toolbar_out = function()  {
	this.className = 'navbutton';
	this.isover = false;
}
Application.prototype.toolbar_down = function()  {
	this.className = 'navbutton navbutton_down';
}
Application.prototype.toolbar_up = function()  {
	if (this.isover) {
		this.className = 'navbutton navbutton_over';
	} else {
		this.className = 'navbutton';
	}
}


Application.prototype.reload = function() {
	
	this.contents_treeview.clear();
	this.index_treeview.clear();
	this.search_treeview.clear();	

	var search_term = layer.get('browser_search_term');
	search_term.value = '';
	var index_term = layer.get('browser_index_term');
	index_term.value = '';
	
	this.first_contents_poll = true;
	this.contents_fetch_items(0);
}

Application.prototype.resize = function() {
	this.content.style.width = '1px';
	
	var height = browser.clientHeight();
	var width = browser.clientWidth();
	
	var browserpos = layer.position(this.browser);
	contentheight = (height - browserpos.y - 2);
	
	this.browser.style.width = this.browserwidth+'px';
	this.browser.style.height = contentheight+'px';
	
	this.resizegrip.style.height = contentheight + 'px';
	
	var contentpos = layer.position(this.content);

	this.content.style.width = (width - contentpos.x)+'px';
	this.content.style.height = contentheight+'px';	
	
	var browsertabs = layer.get('browsertabs');
	this.tabsize = layer.size(browsertabs);
	this.tabpageheight = (contentheight - this.tabsize.y - 10);
		
	var pages = [ 'browser_contents', 'browser_index', 'browser_search' ];
	for (var i in pages) {
		var page = layer.get(pages[i]);
		if (!page) continue;
			
		page.style.height = this.tabpageheight + 'px';
		
	}
	
	this.resize_active_page();
	
}

Application.prototype.resize_active_page = function() {
	if (!this.tabpageheight) return;
	
	switch(this.tabset.selectedIndex) {
		case 0:
			var pane = layer.get('browser_contents_list');
			if (!pane) return;

			pane.style.height = this.tabpageheight + 'px';
			
			var panepos = layer.position(pane);
			pane.style.width = ( this.browserwidth - (panepos.x * 2) - 2 ) + 'px';
			
			if (this.contents_treeview && this.contents_treeview.selectednode) {
				this.contents_treeview.scroll_to_node(this.contents_treeview.selectednode);
			}
			
			break;
		case 1:
			var pane = layer.get('browser_index_list');
			if (!pane) return;
			
			var searchform = layer.get('browser_index_form');
			var searchsize = layer.size(searchform);
			
			pane.style.height = (this.tabpageheight - searchsize.y) + 'px';

			var panepos = layer.position(pane);
			var contentwidth = ( this.browserwidth - (panepos.x * 2) - 2 );
			pane.style.width = contentwidth + 'px';
			
			el = layer.get('browser_index_term');
			el.style.width = (contentwidth - 2) + 'px';
			el.focus();
			
			break;
		case 2:
			var pane = layer.get('browser_search_list');
			if (!pane) return;
			
			var searchform = layer.get('browser_search_form');
			var searchsize = layer.size(searchform);

			pane.style.height = (this.tabpageheight - searchsize.y) + 'px';

			var panepos = layer.position(pane);
			var contentwidth = ( this.browserwidth - (panepos.x * 2) - 2 );
			pane.style.width = contentwidth + 'px';
			
			el = layer.get('browser_search_term');
			el.style.width = (contentwidth - 2) + 'px';
			el.focus();
			
			break;
	}

}

Application.prototype.contents_fetch_items = function(parentid) {
	application.loading(true);
	application.rpc.execute('chmreader.fetch_toc',window.chmsource,parentid);
}


Application.prototype.search_term_keyup = function(e) {
	e = browser.get_event(e);
	if (e.keyCode==13) {
		application.notice('search',false);
		var field = layer.get('browser_search_term');
		if (!field || !field.value) return;
		var keyword = field.value.trim();
		if (keyword.length>=3) {
			application.search_execute(keyword);
		} else {
			alert('Your search term must be at least 3 characters in length.');
		}
	}
}

/*
Application.prototype.search_fetch_items = function(parentid) {
	application.loading(true);
	application.rpc.execute('chmreader.fetch_search_by_parent',window.chmsource,parentid);
}
*/

Application.prototype.search_execute = function(keyword) {
	application.loading(true);
	application.rpc.execute('chmreader.fetch_search_by_keyword',window.chmsource,keyword);
}


Application.prototype.index_term_suggest = function(field) {
	if (!field.ifo) return;
	
	var fieldvalue = field.value.toLowerCase();
	
	if ( (application.last_index_keyword.length>0) && (fieldvalue.length>=application.last_index_keyword.length) && (fieldvalue.substring(0,application.last_index_keyword.length)==application.last_index_keyword) ) {
		// we're simply refining the current list; no need to re-fetch
		for (var i=application.index_treeview.container.childNodes.length-1; i>=0; i--) {
			var node = application.index_treeview.container.childNodes[i];
			if (!node || !node.caption || !node.caption.innerHTML) continue;
			
			var captioncheck = node.caption.innerHTML.substring(0,fieldvalue.length);
			if (captioncheck.toLowerCase()!=fieldvalue) {
				application.index_treeview.hide_node(i);
			} else {
				application.index_treeview.show_node(i);
			}
		}
		
		if (application.index_term_launch) this.launch_index_term();
		return;
	}
	
	if (fieldvalue.length<3) return;
	
	application.notice('index',false);
	
	application.loading(true);
	application.rpc.execute('chmreader.fetch_index_by_keyword',window.chmsource,fieldvalue);
}

Application.prototype.launch_index_term = function() {
	var node = application.index_treeview.get_first_node();
	if (node && node.caption) node.caption.onclick();
	application.index_term_launch = false;
}

Application.prototype.index_term_downarrow = function() {
}

Application.prototype.index_term_keyup = function(e) {
	e = browser.get_event(e);
	if (e.keyCode==13) {
		var field = layer.get('browser_index_term');
		if (!field || !field.value) return;
		var keyword = field.value.trim();
		if (keyword.length>=3) {
			application.index_term_launch = true;
			application.index_term_suggest(field);
		}
	}
}

Application.prototype.index_fetch_items = function(parentid) {
	application.loading(true);
	application.rpc.execute('chmreader.fetch_index_by_parent',window.chmsource,parentid);
}

Application.prototype.set_index_terms = function(keyword,terms) {
	application.index_treeview.clear();

	application.last_index_keyword = keyword;

	if (!terms || !terms.length) {
		application.notice('index',true,'No matches found.');
		application.loading(false);
		return;
	}
	application.index_treeview.set_items(0,terms);
	
	application.loading(false);

	if (application.index_term_launch) this.launch_index_term();
}


Application.prototype.page_changed = function(tabset,tabindex) {
	application.resize_active_page();
}

Application.prototype.launch_entry = function(url) {
	application.content.src = window.chmsourcedir+url;
}

Application.prototype.resize_start = function(element) {
	var splitter = document.createElement('div');
	splitter.className = 'resize_splitter';

	var grippos = layer.position(element);
	var gripsize = layer.size(element);
	
	splitter.style.top = grippos.y + 'px';
	splitter.style.height = gripsize.y + 'px';
	
	splitter.style.left = grippos.x+'px';
	splitter.orig_left = grippos.x;

	browser.disable_page(true,false,'w-resize');

	document.body.insertBefore(splitter,document.body.childNodes[0]);

	window.resizer.splitter = splitter;
}

Application.prototype.resize_move = function(element,dX,dY) {
	if (!window.resizer || !window.resizer.splitter) return;
	var new_pos = window.resizer.splitter.orig_left + dX;
	
	var min_position = application.min_browser_width + 2;
	var max_position = browser.clientWidth() - application.min_content_width;
	
	if (new_pos<min_position) new_pos = min_position;
	if (new_pos>max_position) new_pos = max_position;
	window.resizer.splitter.style.left = new_pos+'px';
}

Application.prototype.resize_done = function(element) {
	var current_pos = parseInt(window.resizer.splitter.style.left) - parseInt(window.resizer.splitter.orig_left);
	
	document.body.removeChild(window.resizer.splitter);
	window.resizer.splitter = null;
	
	browser.disable_page(false);

	application.browserwidth = parseInt(application.browserwidth) + parseInt(current_pos);
	browser.clearcookie('application_browserwidth');
	browser.setcookie('application_browserwidth',application.browserwidth);

	application.resize();
}

Application.prototype.position_notice_div = function(elementid,width,height,visible,voffset) {
	var el = layer.get(elementid);
	if (!el) return false;

	if (!voffset) voffset = 0;
		
	var browserpos = layer.position(this.browser);
	el.style.left = (browserpos.x + Math.floor( (this.browserwidth - width) / 2)) + 'px';
	el.style.top = (browserpos.y + this.tabpageheight - height + voffset) + 'px';
	el.style.width = width + 'px';
	el.style.height = height + 'px';
	el.style.display = visible ? 'block' : 'none';
	
	return el;
}

Application.prototype.loading = function(isloading) {
	var loadingwidth = 100;
	var loadingheight = 16;
	
	this.position_notice_div('loading',loadingwidth,loadingheight,isloading,0);
}

Application.prototype.notice = function(page,isvisible,caption) {
	var noticewidth = 150;
	var noticeheight = 16;
	
	var voffset = -Math.floor(this.tabpageheight / 2);
	var el = this.position_notice_div(page+'_notice',noticewidth,noticeheight,isvisible,voffset);
	
	if (isvisible && el) el.innerHTML = caption;
}

Application.prototype.contents_set_items = function(parentid,values) {
	this.contents_treeview.set_items(parentid,values);
	this.loading(false);
	
	if (this.first_contents_poll && !window.opendocumentid) {
		this.first_contents_poll = false;
		var node = this.contents_treeview.get_first_node();
		if (node && node.caption) node.caption.onclick();	
	}
	
	// if the user requested a document in the URL, open that document in the tree
	if (this.contents_open_recursive && (this.contents_open_lastparent==parentid) ) {
		// iterate through all of the document parent IDs until we reach the
		// document itself
		if (this.contents_open_parents.length) {
			var nextparentid = this.contents_open_parents[this.contents_open_parents.length-1];
			this.contents_open_parents.length--;

			var node = this.contents_treeview.get_node_by_id(nextparentid);			
			if (node && node.stateimage) {
				this.contents_open_lastparent = nextparentid;
				node.stateimage.onclick();
			}
			return;
		} else {
			// we've reached the document itself; select its node
			this.first_contents_poll = false;
			
			var node = this.contents_treeview.get_node_by_id(this.contents_open_recursive);
			// launch without callback because the document was already preloaded in
			// the iframe
			if (node) {
				if (this.first_contents_poll) this.first_contents_poll = false;
				this.contents_treeview.launch_without_callback(node);
				this.contents_treeview.scroll_to_node(node);
			}
			return;
		}
	}	
}

Application.prototype.index_set_items = function(parentid,values) {
	if (values && values.length) {
		application.index_treeview.set_items(parentid,values);
	}
	application.loading(false);
}

Application.prototype.search_set_items = function(parentid,values) {
	application.search_treeview.clear();
	if (values && values.length) {
		application.search_treeview.set_items(parentid,values);
	} else {
		application.notice('search',true,'No matches found.');
	}
	application.loading(false);
}

Application.prototype.get_topic_url = function() {
	var url = window.location + '';
	url = url.replace(/\?.*$/,'');
	url = url.replace(/index\.php$/,'');
	if ( url.substr(url.length-1,1)!='/' ) url += '/';
	
	var directlink = url + 'chm/' + window.chmsource + '/';
	var contenturl = this.content.src;
	contenturl = contenturl.substring(directlink.length,contenturl.length);
	
	
	if (window.mod_rewrite) {
		url += 'manuals/' + window.chmsource + '/' + contenturl;
	} else {
		url += 'index.php?manual=' + window.chmsource + '&document=' + contenturl;
	}
	return url;
}

Application.prototype.add_bookmark = function() {
	var url = this.get_topic_url();
	var frametitle = "";
	try {
		frametitle = frames['content'].document.title;
	} catch(e) {
		frametitle = url.replace(/.*\//,'').replace(/\.html?$/,'');
	}
	var title = window.appname+' - '+window.openmanualtitle+' - '+frametitle;
	if (window.sidebar) {
		window.sidebar.addPanel(title,url,"");
	} else if (window.external) {
		window.external.AddFavorite(url,title);
	} else {
		alert('Sorry, your browser does not support the automatic addition of favorites/bookmarks.');
	}
}

Application.prototype.show_credits = function() {
	application.content.src = 'credits.php?manual=' + window.chmsource;
}

Application.prototype.show_helpreader_help = function() {
	application.content.src = 'help.php';
}

Application.prototype.new_window = function() {
	var randname = 'chmwin'+Math.round(Math.random()*1000000);
	window.open(this.get_topic_url(),randname);
}

Application.prototype.content_changed = function(content_url,content_title,tocid) {
	
	var newwinbutton = layer.get('newwinbutton');
	newwinbutton.href = this.get_topic_url();
	
	if (!tocid) return;
	if (this.contents_treeview.selectednode) {
		if (this.contents_treeview.selectednode.tree_id==tocid) {
			return;
		}
	}
	var node = this.contents_treeview.get_node_by_id(tocid);
	if (node) {
		this.contents_treeview.open_to_node(node);
	} else {
		this.rpc.execute('chmreader.fetch_toc_hierarchy_by_id',window.chmsource,tocid);
	}
}

Application.prototype.contents_set_selected = function(tocid,parents,url) {
	// open a the contents treeview to a node (recursively if necessary)
	while (parents.length>0) {
		var parentid = parents[parents.length-1];
		parents.length--;
		
		// first, try opening all nodes that we've already populated; no RPC is
		// necessary here
		var node = this.contents_treeview.get_node_by_id(parentid);
		if (node && node.tree_populated) {
			this.contents_treeview.set_collapsed(node,false);
			continue;
		}
		
		// when we hit a node that's not yet populated, then fallback to RPC
		this.contents_open_recursive = tocid;
		this.contents_open_parents = parents;
		this.contents_open_lastparent = parentid;
		
		this.contents_fetch_items(parentid);
		return;
	}
	
	var node = this.contents_treeview.get_node_by_id(tocid);
	if (!node) return;
	
	this.contents_treeview.launch_without_callback(node);
	this.contents_treeview.scroll_to_node(node);
}
