Class.subclass( Page, "Page.Base", {	
	
	graph_colors: ["0,0,255", "138,43,226", "0,128,0", "255,20,147", "0,191,255", "210,105,30", "100,149,237", "220,20,60", "0,139,139", "128,128,128"],
	
	requireLogin: function(args) {
		// user must be logged into to continue
		var self = this;
		
		if (!app.user) {
			// require login
			app.navAfterLogin = this.ID;
			if (args && num_keys(args)) app.navAfterLogin += compose_query_string(args);
			
			this.div.hide();
			
			var session_id = app.getPref('session_id') || '';
			if (session_id) {
				Debug.trace("User has cookie, recovering session: " + session_id);
				
				app.api.post( 'user/resume_session', {
					session_id: session_id
				}, 
				function(resp) {
					if (resp.user) {
						Debug.trace("User Session Resume: " + resp.username + ": " + resp.session_id);
						app.hideProgress();
						app.doUserLogin( resp );
						Nav.refresh();
					}
					else {
						Debug.trace("User cookie is invalid, redirecting to login page");
						// Nav.go('Login');
						self.setPref('session_id', '');
						self.requireLogin(args);
					}
				} );
			}
			else if (app.config.external_users) {
				Debug.trace("User is not logged in, querying external user API");
				app.doExternalLogin();
			}
			else {
				Debug.trace("User is not logged in, redirecting to login page (will return to " + this.ID + ")");
				setTimeout( function() { Nav.go('Login'); }, 1 );
			}
			return false;
		}
		return true;
	},
	
	isAdmin: function() {
		// return true if user is logged in and admin, false otherwise
		// Note: This is used for UI decoration ONLY -- all privileges are checked on the server
		return( app.user && app.user.privileges && app.user.privileges.admin );
	},
	
	getNiceJob: function(id) {
		if (!id) return '(None)';
		if (typeof(id) == 'object') id = id.id;
		return '<div style="white-space:nowrap;"><i class="fa fa-pie-chart">&nbsp;</i>' + id + '</div>';
	},
	
	getNiceEvent: function(title, width) {
		if (!width) width = 500;
		if (!title) return '(None)';
		var icon_class = 'fa fa-clock-o';
		if (typeof(title) == 'object') {
			if (title.chain || title.chain_error) icon_class = 'fa fa-link';
			title = title.title;
		}
		return '<div class="ellip" style="max-width:'+width+'px;"><i class="' + icon_class + '">&nbsp;</i>' + title + '</div>';
	},
	
	getNiceCategory: function(cat, width) {
		if (!width) width = 500;
		if (!cat) return '(None)';
		var title = cat.title;
		if (!cat.enabled) title += ' (Disabled)';
		return '<div class="ellip" style="max-width:'+width+'px;"><i class="fa fa-folder-open-o">&nbsp;</i>' + title + '</div>';
	},
	
	getNiceGroup: function(group, target, width) {
		if (!width) width = 500;
		if (!group && !target) return '(None)';
		if (group) {
			var title = group.title;
			if (group.multiplex) title += '&nbsp;(<i class="fa fa-bolt" title="Multiplexed"></i>)';
			return '<div class="ellip" style="max-width:'+width+'px;"><i class="mdi mdi-server-network">&nbsp;</i>' + title + '</div>';
		}
		else {
			return '<div class="ellip" style="max-width:'+width+'px;" title="'+target+'"><i class="mdi mdi-desktop-tower mdi-lg">&nbsp;</i>' + target.replace(/\.[\w\-]+\.\w+$/, '') + '</div>';
		}
	},
	
	getNicePlugin: function(plugin, width) {
		if (!width) width = 500;
		if (!plugin) return '(None)';
		var title = plugin.title;
		if (!plugin.enabled) title += ' (Disabled)';
		return '<div class="ellip" style="max-width:'+width+'px;"><i class="fa fa-plug">&nbsp;</i>' + title + '</div>';
	},
	
	getNiceAPIKey: function(item, link, width) {
		if (!item) return 'n/a';
		if (!width) width = 500;
		var key = item.api_key || item.key;
		var title = item.api_title || item.title;
		
		var html = '<div class="ellip" style="max-width:'+width+'px;">';
		if (link && key) html += '<a href="#Admin?sub=edit_api_key&id='+item.id+'">';
		
		html += '<i class="mdi mdi-key-variant">&nbsp;</i>' + title;
		
		if (link && key) html += '</a>';
		html += '</div>';
		
		return html;
	},
	
	getNiceUsername: function(user, link, width) {
		if (!user) return 'n/a';
		if ((typeof(user) == 'object') && (user.key || user.api_title)) {
			return this.getNiceAPIKey(user, link, width);
		}
		if (!width) width = 500;
		var username = user.username ? user.username : user;
		if (!username || (typeof(username) != 'string')) return 'n/a';
		
		var html = '<div class="ellip" style="max-width:'+width+'px;">';
		if (link) html += '<a href="#Admin?sub=edit_user&username='+username+'">';
		
		html += '<i class="fa fa-user">&nbsp;&nbsp;</i>' + username;
		
		if (link) html += '</a>';
		html += '</div>';
		
		return html;
	},
	
	setGroupVisible: function(group, visible) {
		// set web groups of form fields visible or invisible, 
		// according to master checkbox for each section
		var selector = 'tr.' + group + 'group';
		if (visible) {
			if ($(selector).hasClass('collapse')) {
				$(selector).hide().removeClass('collapse');
			}
			$(selector).show(250);
		}
		else $(selector).hide(250);
		
		return this; // for chaining
	},
	
	checkUserExists: function(pre) {
		// check if user exists, update UI checkbox
		// called after field changes
		var username = trim($('#fe_'+pre+'_username').val().toLowerCase());
		var $elem = $('#d_'+pre+'_valid');
		
		if (username.match(/^[\w\-\.]+$/)) {
			// check with server
			// $elem.css('color','#444').html('<span class="fa fa-spinner fa-spin fa-lg">&nbsp;</span>');
			app.api.get('app/check_user_exists', { username: username }, function(resp) {
				if (resp.user_exists) {
					// username taken
					$elem.css('color','red').html('<span class="fa fa-exclamation-triangle fa-lg">&nbsp;</span>Username Taken');
				}
				else {
					// username is valid and available!
					$elem.css('color','green').html('<span class="fa fa-check-circle fa-lg">&nbsp;</span>Available');
				}
			} );
		}
		else if (username.length) {
			// bad username
			$elem.css('color','red').html('<span class="fa fa-exclamation-triangle fa-lg">&nbsp;</span>Bad Username');
		}
		else {
			// empty
			$elem.html('');
		}
	},
	
	check_add_remove_me: function($elem) {
		// check if user's e-mail is contained in text field or not
		var value = $elem.val().toLowerCase();
		var email = app.user.email.toLowerCase();
		var regexp = new RegExp( "\\b" + escape_regexp(email) + "\\b" );
		return !!value.match(regexp);
	},
	
	update_add_remove_me: function($elems) {
		// update add/remove me text based on if user's e-mail is contained in text field
		var self = this;
				
		$elems.each( function() {
			var $elem = $(this);
			var $span = $elem.next();
						
			if (self.check_add_remove_me($elem)) $span.html( '&raquo; Remove me' );
			else $span.html( '&laquo; Add me' );
		} );
	},
	
	add_remove_me: function($elem) {
		// toggle user's e-mail in/out of text field
		var value = trim( $elem.val().replace(/\,\s*\,/g, ',').replace(/^\s*\,\s*/, '').replace(/\s*\,\s*$/, '') );
		
		if (this.check_add_remove_me($elem)) {
			// remove e-mail
			var email = app.user.email.toLowerCase();
			var regexp = new RegExp( "\\b" + escape_regexp(email) + "\\b", "i" );
			value = value.replace( regexp, '' ).replace(/\,\s*\,/g, ',').replace(/^\s*\,\s*/, '').replace(/\s*\,\s*$/, '');
			$elem.val( trim(value) );
		}
		else {
			// add email
			if (value) value += ', ';
			$elem.val( value + app.user.email );
		}
		
		this.update_add_remove_me($elem);
	},
	
	get_custom_combo_unit_box: function(id, value, items, class_name) {
		// get HTML for custom combo text/menu, where menu defines units of measurement
		// items should be array for use in render_menu_options(), with an increasing numerical value
		if (!class_name) class_name = 'std_combo_unit_table';
		var units = 0;
		var value = parseInt( value || 0 );
		
		for (var idx = items.length - 1; idx >= 0; idx--) {
			var max = items[idx][0];
			if ((value >= max) && (value % max == 0)) {
				units = max;
				value = Math.floor( value / units );
				idx = -1;
			}
		}
		if (!units) {
			// no exact match, so default to first unit in list
			units = items[0][0];
			value = Math.floor( value / units );
		}
		
		return (
			'<table cellspacing="0" cellpadding="0" class="'+class_name+'"><tr>' + 
				'<td style="padding:0"><input type="text" id="'+id+'" style="width:30px;" value="'+value+'"/></td>' + 
				'<td style="padding:0"><select id="'+id+'_units">' + render_menu_options(items, units) + '</select></td>' + 
			'</tr></table>' 
		);
	},
	
	get_relative_time_combo_box: function(id, value, class_name, inc_seconds) {
		// get HTML for combo textfield/menu for a relative time based input
		// provides Minutes, Hours and Days units
		var unit_items = [[60,'Minutes'], [3600,'Hours'], [86400,'Days']];
		if (inc_seconds) unit_items.unshift( [1,'Seconds'] );
		
		return this.get_custom_combo_unit_box( id, value, unit_items, class_name );
	},
	
	get_relative_size_combo_box: function(id, value, class_name) {
		// get HTML for combo textfield/menu for a relative size based input
		// provides MB, GB and TB units
		var TB = 1024 * 1024 * 1024 * 1024;
		var GB = 1024 * 1024 * 1024;
		var MB = 1024 * 1024;
		var KB = 1024;
		
		return this.get_custom_combo_unit_box( id, value, [[KB, 'KB'], [MB,'MB'], [GB,'GB'], [TB,'TB']], class_name );
	},
	
	expand_fieldset: function($span) {
		// expand neighboring fieldset, and hide click control
		var $div = $span.parent();
		var $fieldset = $div.next();
		$fieldset.show( 350 );
		$div.hide( 350 );
	},
	
	collapse_fieldset: function($legend) {
		// collapse fieldset, and show click control again
		var $fieldset = $legend.parent();
		var $div = $fieldset.prev();
		$fieldset.hide( 350 );
		$div.show( 350 );
	},
	
	choose_date_time: function(args) {
		// show dialog for selecting a date/time
		// args: {
		//		when: default date/time (epoch or Date object, defaults to now)
		//		timezone: custom timezone (defaults to app.tz)
		//		title: dialog title
		//		description: optional description
		//		button: optional button label ("Select")
		//		callback: fired when complete, passed new date/time
		// }
		var self = this;
		var html = '';
		
		if (!args.when) args.when = time_now();
		if (!args.timezone) args.timezone = app.tz;
		if (!args.title) args.title = "Select Date/Time";
		if (!args.button) args.button = "Select";
		
		if (args.description) {
			html += '<div style="font-size:12px; color:#777; margin-bottom:20px;">' + args.description + '</div>';
		}
		
		// var dargs = get_date_args( args.when );
		var margs = moment.tz(args.when * 1000, args.timezone);
		
		html += '<center><table><tr>';
		
		// years
		var year_items = [];
		for (var idx = margs.year() - 10; idx <= margs.year() + 10; idx++) { 
			year_items.push(idx); 
		}
		html += '<td align="left"><fieldset class="dt_fs"><legend>Year</legend>';
		html += '<select id="fe_dt_year">' + render_menu_options(year_items, margs.year()) + '</select>';
		html += '</fieldset></td>';
		
		// months
		html += '<td align="left"><fieldset class="dt_fs" style="margin-left:5px;"><legend>Month</legend>';
		html += '<select id="fe_dt_month">' + render_menu_options(_months, margs.month() + 1) + '</select>';
		html += '</fieldset></td>';
		
		// days
		html += '<td align="left"><fieldset class="dt_fs" style="margin-left:5px;"><legend>Day</legend>';
		html += '<select id="fe_dt_day">' + render_menu_options(_days, margs.date()) + '</select>';
		html += '</fieldset></td>';
		
		// hours
		var hour_items = _hour_names.map( function(value, idx) {
			return [idx, value.toUpperCase().replace(/^(\d+)(\w+)$/, '$1 $2')];
		} );
		html += '<td align="left"><fieldset class="dt_fs" style="margin-left:5px;"><legend>Hour</legend>';
		html += '<select id="fe_dt_hour">' + render_menu_options(hour_items, margs.hour()) + '</select>';
		html += '</fieldset></td>';
		
		// minutes
		var min_items = [];
		for (var idx = 0; idx < 60; idx++) { 
			min_items.push([ idx, (idx < 10) ? ('0'+idx) : (''+idx) ]); 
		}
		html += '<td align="left"><fieldset class="dt_fs" style="margin-left:5px;"><legend>Minute</legend>';
		html += '<select id="fe_dt_minute">' + render_menu_options(min_items, margs.minute()) + '</select>';
		html += '</fieldset></td>';
		
		html += '</tr>';
		html += '<tr><td align="left" colspan="5">';
			html += '<div class="caption">Timezone: ' + args.timezone + '</div>';
		html += '</td></tr>';
		html += '</table></center>';
		
		app.confirm( '<i class="fa fa-calendar">&nbsp;</i>' + args.title, html, args.button, function(result) {
			app.clearError();
			
			if (result) {
				Dialog.hide();
				
				margs.year( parseInt( $('#fe_dt_year').val() ) );
				margs.month( parseInt( $('#fe_dt_month').val() ) - 1 );
				margs.date( parseInt( $('#fe_dt_day').val() ) );
				margs.hour( parseInt( $('#fe_dt_hour').val() ) );
				margs.minute( parseInt( $('#fe_dt_minute').val() ) );
				margs.second( 0 );
				
				args.callback( margs.unix() );
			}
		} ); // app.confirm
	},
	
	render_target_menu_options: function(value) {
		// render menu items for server group (target)
		// including optgroups for both server group and individual servers
		var html = '';
		
		var server_groups = app.server_groups.sort( function(a, b) {
			// return (b.title < a.title) ? 1 : -1;
			return a.title.toLowerCase().localeCompare( b.title.toLowerCase() );
		} )
		.filter( function(group) {
			if (!app.user.privileges.grp_limit) return true; // user is not limited by groups
			return app.hasPrivilege( 'grp_' + group.id );
		});
		
		html += '<optgroup label="Groups:">' + render_menu_options(server_groups, value, false) + '</optgroup>';
		
		if (find_object(server_groups, { id: value })) value = '';
		
		// trim hostname suffixes
		var hostnames = hash_keys_to_array(app.servers).sort();
		if (value && !app.servers[value]) hostnames.push( value );
		
		// filter hostnames by server group privilege
		if (app.user.privileges.grp_limit) {
			hostnames = hostnames.filter(function(hostname) {
				var groups = server_groups.filter( function(group) {
					return hostname.match( group.regexp );
				} );
				
				// we just need one group to match, then the user has permission to target the server
				for (var idx = 0, len = groups.length; idx < len; idx++) {
					priv_id = 'grp_' + groups[idx].id;
					result = app.hasPrivilege(priv_id);
					if (result) return true;
				}
				return false;
			});
		} // grp_limit
		
		var short_hostnames = [];
		for (var idx = 0, len = hostnames.length; idx < len; idx++) {
			short_hostnames.push([ hostnames[idx], hostnames[idx].replace(/\.[\w\-]+\.\w+$/, '') ]);
		}
		
		html += '<optgroup label="Servers:">' + render_menu_options(short_hostnames, value, false) + '</optgroup>';
		return html;
	}
	
} );
