
// =================================================================================================
// constructor - this should NOT be called directly; instead use
// 		this static factory method, i.e., Scheduler.attach (id, program)
// =================================================================================================

function Scheduler (id, program) {

	// reference to this instance for any closures in this function
	var self = this;

	///////////////////////////////////////
	// vars
	///////////////////////////////////////

	this.defaultDescText = "Hover your mouse over an activity to view a description.<br>Click an activity to select it for this block.";

	this.selections = {}; /* user selections are saved here; this is 2 dimentional arrays.  1st: camper, 2nd: activity id */
	this.id = id;
	this.data = null;
	this.cells = null;
	this.backend = 'scheduler.php';
	this.program = program;
	this.container = document.getElementById(id);
	this.children = [];

	this.weeks = { 
	  /*1: 'Week 1 (June 22 - June 26)',
	  2: 'Week 2 (June 29 - July 3)',
	  3: 'Week 3 (July 6 - July 10)',
	  4: 'Week 4 (July 13 - July 17)',
	  5: 'Week 5 (July 20 - July 24)',
	  6: 'Week 6 (July 27 - July 31)',
	  7: 'Week 7 (August 3 - August 7)',
	  8: 'Week 8 (August 10 - August 14)',*/
	  9: 'Week 9 (August 16 - August 20)',
	};

	this.grades = { 1 : '1st', 2 : '2nd', 3 : '3rd', 4 : '4th', 5 : '5th' };

	this.days = [1,2,3,4,5];

	///////////////////////////////////////
	// exit if not valid container or instance not defined
	///////////////////////////////////////
	if (Scheduler.instances[id] !== undefined) {
		return;
	}

	if (!this.container) {
		Scheduler.error("Invalid container id in constructor");
	}
	///////////////////////////////////////
  // fill in grades dropdowns on account panel
	///////////////////////////////////////
  $('#skd_account select,#skd_account_edit select').each (function () {
  	var el = this;
		this.options.length = 0;
		this.options[0] = new Option('', '');
		for (var grade in self.grades) {
			el.options[el.options.length] = new Option(self.grades[grade], grade);
		}
  });

	///////////////////////////////////////
	// define click actions
	///////////////////////////////////////

	////////////////
  // update account
	////////////////
  $('#skd_account_edit_update').click(function() {
    self.EditAccountSubmit();
  });

	// action to go back to scheduler
  $('#skd_account_edit_back').click(function() {
    self.togglePanel('skd_app');
  });

	////////////////
  // create account
	////////////////

  // action if user wants to create account
  $('#skd_account_create').click(function() {
    self.CreateAccountSubmit();
  });

	// action to go back to loader screen
  $('#skd_account_back').click(function() {
    self.togglePanel('skd_loader');
  });

	////////////////
  // loader
	////////////////

	// create accunt
	$('#skd_loader_createaccount').click(function () {
		self.CreateAccount();
	});

	// login
	$('#skd_loader_login').click(function () {
	  self.togglePanel('skd_login');
	});

  $('#skd_login_run').click(function() {
    self.Login();
  });

  $('#skd_login_back').click(function() {
    self.togglePanel('skd_loader');
  });

  // intro
	$('#skd_intro_ok').click(function() {
		self.BeginSchedule();
	});

  // scheduler
	$('#skd_popup_close').click(function() {
		self.closePopup();
	});

	// scheduler toolbar
	$('#skd_toolbar_week').change	(function() { self.onWeekChange(); });
	$('#skd_toolbar_child').change(function() { self.onChildChange(); });

	$('#skd_toolbar_editchildren').click(function () {
	  self.EditAccount();
	});

	$('#skd_toolbar_logout').click(function() {
		self.talk({
		  'action' : 'logout'
		}, function (success, data) {
		  window.location = 'http://www.acteeva.com/customizer-registered/';
		});
	});

	///////////////////////////////////////
	// show loader screen
	///////////////////////////////////////
	this.togglePanel('skd_loader');

	///////////////////////////////////////
	// load schedule data
	///////////////////////////////////////
	this.talk({
		'action' : 'query_session'
	}, function (success, data) {
	  if (!success) {
			var msg = data != null ? data.error : "There was a problem with your submission. Try again later.";
			alert(msg);
			return;
		}

		// store schedule data
		self.data = data;

		// check if user is logged in; returns error if user is not
		self.talk({
		  'action' : 'query_account'
		}, function (success, data) {
		  // if user not logged in show login options
		  if (!success) {
				$('#skd_loader_pleasewait').hide();
				$('#skd_loader_finished').show();
				return;
			}
			// otherwise set returned data and begin scheduling
			self.SetAccountData(data);
			self.BeginSchedule();
		});
	});
}

// =================================================================================================
// edit account/submit
// =================================================================================================

Scheduler.prototype.EditAccount = function () {
  var data = {
    'name' : this.account.name,
    'email' : this.account.email,
    'children' : this.children
  };

  this.SetFormData('skd_account_edit', data);
  this.togglePanel('skd_account_edit');
}

Scheduler.prototype.EditAccountSubmit = function () {
	var data = this.GetFormData('skd_account_edit');
	
	if (data.name == '' || data.email == '') {
	  alert("You are missing some information.");
	  return;
	}

	var count = 0;
	for (var i in data.children) {
	  var child = data.children[i];
	  if (child.name == '') {
	    continue;
	  }
	  count++;

	  if (child.grade == '') {
			alert("Please specify a grade for " + child.name);
			return;
	  }
	}

	if (count == 0) {
	  alert("You did not entered any information for your children.");
	  return;
	}
	
	//alert($.toJSON(data));	

	// submit json to server
	$('#skd_account_edit_update').attr('disabled', 'true');
	var self = this;
	this.talk({
		'action' : 'update_account',
		'data' : $.toJSON(data)
	}, function (success, data) {
		$('#skd_account_edit_update').removeAttr('disabled');

		if (!success) {
			var msg = data != null ? data.error : "There was a problem with your submission. Try again later.";
			alert(msg);
		} else {
			$("#skd_account :input").clearForm();

			self.SetAccountData(data);
			self.BeginSchedule();
		}
	});
}

// =================================================================================================
// create account/submit
// =================================================================================================

Scheduler.prototype.CreateAccount = function () {
	var self = this;
  this.togglePanel('skd_account');
}

Scheduler.prototype.CreateAccountSubmit = function () {
	var data = this.GetFormData('skd_account');
	//alert($.toJSON(data));

	if (data.name == '' || data.email == '' || data.pwd1 == '') {
	  alert("You are missing some information.");
	  return;
	}

	if (data.pwd1 != data.pwd2) {
	  alert("Passwords do not match.");
	  return;
	}
	data.password = data.pwd1;
	delete data.pwd1;
	delete data.pwd2;

	var count = 0;
	for (var i in data.children) {
	  var child = data.children[i];
	  if (child.name == '') {
	    continue;
	  }
	  count++;

	  if (child.grade == '') {
			alert("Please specify a grade for " + child.name);
			return;
	  }
	}

	if (count == 0) {
	  alert("You have not entered any information for your children.");
	  return;
	}

	// submit json to server
	$('#skd_account_create').attr('disabled', 'true');
	var self = this;
	this.talk({
		'action' : 'create_account',
		'data' : $.toJSON(data)
	}, function (success, data) {
		$('#skd_account_create').removeAttr('disabled');

		if (!success) {
			var msg = data != null ? data.error : "There was a problem with your submission. Try again later.";
			alert(msg);
		} else {
			$("#skd_account :input").clearForm();
			self.SetAccountData(data);
			self.togglePanel('skd_intro');
		}
	});
}

// =================================================================================================
// set account data
// =================================================================================================
Scheduler.prototype.SetAccountData = function (data) {
	this.account = data.account;
	this.children = data.children;
	this.selections = data.selections;
}

// =================================================================================================
// log in
// =================================================================================================

Scheduler.prototype.Login = function () {

	var data = this.GetFormData('skd_login');
	if (data.username == '' || data.password == '') {
		alert("Enter in a username/password to log in");
		return;
	}

	// disable submit button
	$('#skd_account_create').attr('disabled', 'true');

	// submit json to server
	var self = this;
	this.talk({
		'action' : 'login_user',
		'data' : $.toJSON(data)
	}, function (success, data) {
		$('#skd_account_create').removeAttr('disabled');

		if (!success) {
			var msg = data != null ? data.error : "There was a problem with your submission. Try again later.";
			alert(msg);
		} else {
			$("#skd_login :input").clearForm();

			self.SetAccountData(data);
			self.BeginSchedule();
		}
	});

}

// =================================================================================================
// account related - called when user has logged in
// =================================================================================================

Scheduler.prototype.BeginSchedule = function () {

	var self = this;

	///////////////////////////////////////
	// initialize schedule related actions here
	///////////////////////////////////////

	// fill in schedule week dropdown
	var cboWeeks = $('#skd_toolbar_week');
	cboWeeks.html('');
	for (var weekId in this.weeks) {
		var option = $(document.createElement('option'));
		option.val(weekId);
		option.html(this.weeks[weekId]);
		cboWeeks.append(option);
	}

	///////////////////////////////////////
	// fill in children combo box
	///////////////////////////////////////
	var cboChildren = $('#skd_toolbar_child');
	cboChildren.html('');
	for (var i in self.children) {
	  if (self.children[i].name == '') {
	    continue;
	  }

		var option = $(document.createElement('option'));
		option.val(self.children[i].id);
		option.html(self.children[i].name);
		cboChildren.append(option);
	}

	///////////////////////////////////////
	// populate table
	///////////////////////////////////////
	this.populateTable();

	///////////////////////////////////////
	// begin app
	///////////////////////////////////////
	this.togglePanel('skd_app');
};

// =================================================================================================
// activity popup
// =================================================================================================

Scheduler.prototype.togglePopup = function (cellId) {
	// vars
	var content = $('#skd_popup_content');

	var cell = $('#skd_cell_' + cellId);

	// if popup is currently open, ignore click
	if ($('#skd_popup').css('display') != 'none') {
		return;
	}

	// add popup dialog to grid
	$(this.id).append($('#skd_popup_content'));

	// clear any previous content
	content.html('');

	// add default description
	$('#skd_popup_desc')
		.addClass('defaultDesc')
		.html(this.defaultDescText);

	// if user is clicking on a cell that is active, then 
	// interpret this to mean user wants to close dialog
	if (cell.hasClass('active')) {
		this.closePopup();
		return;
	}

	// remove all active cells & make this cell active
	$('#' + this.id + " td").removeClass('active');
	cell.addClass('active');

	// add removal link if this cell has a selection already
	var cellData = this.cells[cellId];
	var camper = $('#skd_toolbar_child').val();
	var selection = new SchedulerSelection(this, camper, cellData.weekId, cellData.dayId, cellData.blockId);
	if (selection.exists()) {
		var html = "<p class='remove'>" +
			"<a onClick=\"Scheduler.activityClick('" + this.id + "', " + cellId + ", '');return false\" href=''>" +
			"Remove Activity</a></p>";
		content.append(html);
	}

	// create list of activities to choose from
	var self = this;
	var ul = $(document.createElement("ul"));
	for (var activityId in this.cells[cellId].activities) {
		var li = document.createElement("li");
		var act = this.data.activities[activityId];

		// store data in jQuery object; we must do this and cannot use
		// local vars in callbacks (via closure) because we are in a loop
		$.data(li, 'description', act.description);
		$.data(li, 'activityId', activityId);

		$(li)
			.html(
				'<div class="' + act.program_area.replace(/ /, '') + '">' +
					act.program_area +
				'</div>' +
				'<div class="activity">' +
					act.name +
					(act.grade != '' ? ' <span class="grade">(Grades ' + act.grade + ')</span>' : '') +
				'</div>')
			.click(function () { Scheduler.activityClick(self.id, cellId, $.data(this, 'activityId')); })
			.hover(
				function() {
					$('#skd_popup_desc')
						.removeClass('defaultDesc')
						.html($.data(this, 'description'));
				},
				function () {
					$('#skd_popup_desc')
						.addClass('defaultDesc')
						.html(self.defaultDescText);
				});
		ul.append(li);
	}
	content.append(ul);

	// show popup & dropshadow
	$('#skd_popup')
		.show()
		.center()
		.removeShadow() // remove shadow because
		.dropShadow();
}
//////////////////////////////////////////////////////
// click activity
//////////////////////////////////////////////////////

Scheduler.prototype.clickActivity = function (cellId, activityId) {
	this.selectActivity(cellId, activityId);
	this.renderCell(cellId);
	this.closePopup();
}

//////////////////////////////////////////////////////
// close popup
//////////////////////////////////////////////////////

Scheduler.prototype.closePopup = function () {
	// remove all active cells
	$('#' + this.id + " td").removeClass('active');

	// hide and remove shadow
	$('#skd_popup')
		.removeShadow()
		.hide();
}

// =================================================================================================
// toolbar related
// =================================================================================================

Scheduler.prototype.onWeekChange = function() {
	this.populateTable();
}

Scheduler.prototype.onChildChange = function() {
	this.populateTable();
}

// =================================================================================================
// grid related
// =================================================================================================

//////////////////////////////////////////////////////
// populate table
//////////////////////////////////////////////////////

Scheduler.prototype.populateTable = function () {

	// prep dictionary lookup of cells; this gets populated later below
	// this lookup only applies to what is currently populated in table, so if user changes week/child
	// then this lookup gets refreshed
	this.cells = {};

	// empty table
	this.container.innerHTML = '';

	var data = this.data;

	var html = "<table>\n";

	// column groups
	var dowNames = new Array('Sun', 'Mon', 'Tue', 'Wed', 'Thr', 'Fri', 'Sat');
	html += "<colgroup class='leftcol'><colgroup span='" + this.days.length + "'>\n";

	// header section
	html += "<thead><tr><th>&nbsp;</th>\n";
	for (var i in this.days) {
		html += "<th>" + dowNames[this.days[i]] + "</th>\n";
	}
	html += "</tr></thead>\n";

	// get current week
	var weekId = $('#skd_toolbar_week').val();

	var cellId = 1;
	html += "<tbody>\n";

	// loop for each block row for this week
	for (var blockId in data.blocks) {
		html += "<tr>\n";

		// create first col of block: block name
		html +=
			"\t<th class='block'>" +
				"<p class='label'>" + data.blocks[blockId].name + "</p>" +
				"<p class='time'>" + data.blocks[blockId].begins + "</p>" +
			"</th>\n";

		// loop through days of week for this block row
		for (var i in this.days) {
			var dayId = this.days[i];
			var cell =
				typeof data.cells[weekId][blockId] != 'undefined' &&
				typeof data.cells[weekId][blockId][dayId] != 'undefined' ? data.cells[weekId][blockId][dayId] : '';

			if (cell != '') {
				// add helper function for this cell with choice count
				cell.id = cellId;
				cell.dayId = dayId;
				cell.weekId = weekId;
				cell.blockId = blockId;

				cell.choices = 0;
				for (var activityId in cell.activities) {
					cell.choices++;
				}

				// add cell to dictionary for easy access; this step MUST be done before
				// rendering cell
				this.cells[cellId] = cell;

				// add empty cell
				html += "<td id=\"skd_cell_" + cellId + "\">&nbsp;</td>";

				cellId++;
			} else {
				html += "<td class='disabled'>&nbsp;</td>";
			}
		}
		html += "</tr>\n";
	}
	html += "</tbody>\n";


	// end table
	html += "</table>\n\n";


	// place table in document
	this.container.innerHTML = html;

	// render cells
	this.renderCells(cellId);
}

//////////////////////////////////////////////////////
// cell click event
//////////////////////////////////////////////////////

Scheduler.prototype.clickCell = function (cellId) {
	var cell = this.cells[cellId];
	if (cell.choices > 0) {
		this.togglePopup(cellId);
		return;
	}	else if (cell.choices == 0) {
		return;
	}
}

//////////////////////////////////////////////////////
// select activity for cell ->
// remove activity by passing blank activity id
//////////////////////////////////////////////////////

Scheduler.prototype.selectActivity = function (cellId, activityId) {
	var cell = this.cells[cellId];

	// store selections in format: selections[user][week_block_day] = activityId
	var selector = new SchedulerSelection(this, $('#skd_toolbar_child').val(), cell.weekId, cell.dayId, cell.blockId);
	if (activityId == '') {
		selector.remove();
	} else {
		selector.set(activityId);
	}


	this.renderCell(cellId);
}

//////////////////////////////////////////////////////
// selection helper class
//////////////////////////////////////////////////////

SchedulerSelection = function (caller, camper, week, day, block) {
	if (caller == null || camper == null || week == null || day == null || block == null) {
		throw ("Bad data provided to SchedulerSelection. " +
			'CALLER: ' + caller + ' ' +
			'camper: ' + camper +  ' ' +
			'week: ' + week + ' ' +
			'day: ' + day + ' ' +
			'block: ' + block
		);
	}

	this.caller = caller;
	this.camper = camper;
	this.id = week + '_' + block + '_' + day;
}

SchedulerSelection.prototype.exists = function() {
	var sel = this.caller.selections;
	return typeof sel[this.camper] != 'undefined' && typeof sel[this.camper][this.id] != 'undefined' && sel[this.camper][this.id] != '';
}

SchedulerSelection.prototype.remove = function() {
	if (typeof this.caller.selections[this.camper] != 'undefined' && typeof this.caller.selections[this.camper][this.id] != 'undefined') {
		delete this.caller.selections[this.camper][this.id];
	}

	this.caller.talk({
		'action' : 'save_block',
		'data' : $.toJSON({ 'child_id': this.camper, 'id': this.id, 'activity_id': '' })
	}, function (success, data) {
		if (!success) {
			var msg = data != null ? data.error : "Failed to save this block.";
			alert(msg);
		}
	});

}

SchedulerSelection.prototype.set = function(activityId) {
	if (typeof this.caller.selections[this.camper] == 'undefined') {
		this.caller.selections[this.camper] = {};
	}
	this.caller.selections[this.camper][this.id] = activityId;

	// save change to server
	this.caller.talk({
		'action' : 'save_block',
		'data' : $.toJSON({ 'child_id': this.camper, 'id': this.id, 'activity_id': activityId })
	}, function (success, data) {
		if (!success) {
			var msg = data != null ? data.error : "Failed to save this block.";
			alert(msg);
		}
	});

}

SchedulerSelection.prototype.get = function() {
	if (this.exists()) {
		return this.caller.selections[this.camper][this.id];
	} else {
		return '';
	}

	// save change to server
}

//////////////////////////////////////////////////////
// draw cell
//////////////////////////////////////////////////////

Scheduler.prototype.renderCells = function () {
	for (var cellId in this.cells) {
		this.renderCell(cellId);
	}
}

Scheduler.prototype.renderCell = function (cellId) {
	if (!document.getElementById('skd_cell_' + cellId)) {
		Scheduler.error("Cannot render cell because it does not exist in DOM.");
		return;
	}
	// prep cell, user
	var cell = this.cells[cellId];
	var camper = $('#skd_toolbar_child').val();

	var selection = new SchedulerSelection(this, camper, cell.weekId, cell.dayId, cell.blockId).get();
	var content = "";
	var disabled = true;

	if (cell.choices == 1 && cell.required == '1') { // support for text display in disabled block
		for (var activityId in cell.activities) break; // get first member in activities object
		content = "<span>" + this.data.activities[activityId].name + "</span>";
	} else if (cell.choices > 0) {
		content = selection != '' ? this.actDisplayName(this.data.activities[selection]) : "<span>Click to Select</span>";
		disabled = false;
	}

	var self = this;

	if (disabled) {
		$('#skd_cell_' + cell.id)
			.removeClass()
			.addClass('disabled')
			.unbind('click')
			.html(content);
	} else {
		$('#skd_cell_' + cell.id)
			.removeClass()
				.addClass(cell.choices > 0 ? 'hover' : '')
				.addClass(cell.choices == 0 ? 'disabled' : '')
				.addClass(selection != '' ? 'required_selected' : (cell.required == 1 ? 'required_not_selected' : ''))
			.unbind('click')
			.click(function() { Scheduler.cellClick(self.id, cell.id); })
			.html(content)
			.css('opacity', 0.1)
			.fadeTo(350, 1);
	}
}

Scheduler.prototype.actDisplayName = function(act) {
	return act.name + (act.grade != '' ? ' <b>(Grades ' + act.grade + ')</b>' : '');
}

// =================================================================================================
// toggle panel
// =================================================================================================

// list of all panels we can toggle through
Scheduler.panels = ['skd_app', 'skd_loader', 'skd_account', 'skd_login', 'skd_intro', 'skd_account_edit'];

Scheduler.prototype.togglePanel = function (panelName) {
	for (var i = 0; i < Scheduler.panels.length; i++) {
	  var panel = Scheduler.panels[i];
	  if (panel == panelName) {
			$('#' + panel).show();
	  } else {
	    $('#' + panel).hide();
	  }
	}
}

Scheduler.prototype.SetFormData = function (id, data) {

	//alert($.toJSON(data));

	// place all form data into json tree
	var inputs = $("#" + id + " :input");
	for (var i = 0; i < inputs.length; i++) {
	  // ignore buttons
	  if ($(inputs[i]).attr('type') == 'button') {
	    continue;
	 	}

		var parts = inputs[i].name.split('.');
		var tmp = data;
		var oldTmp = null;
		for (var part in parts) {
			if (typeof tmp[parts[part]] == 'undefined') {
				tmp[parts[part]] = {};
			}
			oldTmp = tmp;
			tmp = tmp[parts[part]];
		}
		$(inputs[i]).val(typeof oldTmp[parts[part]] == 'object' ? '' : oldTmp[parts[part]] );
	}
}


Scheduler.prototype.GetFormData = function (id) {

	// place all form data into json tree
	var inputs = $("#" + id + " :input");
	var data = {};
	for (var i = 0; i < inputs.length; i++) {
	  // ignore buttons
	  if ($(inputs[i]).attr('type') == 'button') {
	    continue;
	 	}

		var parts = inputs[i].name.split('.');
		var tmp = data;
		var oldTmp = null;
		for (var part in parts) {

			if (typeof tmp[parts[part]] == 'undefined') {
				tmp[parts[part]] = {};
			}
			oldTmp = tmp;
			tmp = tmp[parts[part]];
		}
		oldTmp[parts[part]] = inputs[i].value;
	}
	return data;
}

// =================================================================================================
// server talk
// =================================================================================================

Scheduler.prototype.talk = function (params, funcCallback) {
	var action = params.action;
	var type = params.type;
	params.program = this.program;

	// Note: we aren't using $.getJSON method because
	// it does not have error callback if json parsing fails
  var req = {};
  req.type = "POST";
  req.url = "scheduler.php";
  req.processData = true;
  req.data = params;
  //req.dataType = "json";
  req.error = function (reqObj, textStatus, errorThrown) {
		Scheduler.error("SERVER REQUEST FAILED: " + reqObj.responseText);
		if (funcCallback != null) {
			funcCallback(false, null);
		}
	}

	var self = this;
  req.success = function (data, textStatus) {
  	try {
  		var parsed = $.evalJSON(data);
  	} catch (ex) {
  		Scheduler.error("FAILED TO PARSE JSON: " + data);
 			if (funcCallback != null) {
				funcCallback(false, null);
			}
  		return;
  	}

		if (parsed.error != '') {
			//Scheduler.error("SERVER RETURN WITH ERROR MESSAGE: " + parsed.error);
			if (funcCallback != null) {
				funcCallback(false, parsed);
			}
			return;
		}

		if (funcCallback != null) {
			funcCallback(true, parsed);
		}
	}
  $.ajax(req);
}

// =================================================================================================
// static callbacks
// =================================================================================================

//////////////////////////////////////////////////////////
// instances related
//////////////////////////////////////////////////////////

// all schedule instances are store in associative array here
Scheduler.instances = {};

// all new instances of scheduler should be attached through here
Scheduler.attach = function (id, program) {
	if (Scheduler.instances[id] !== undefined) {
		return;
	}
	Scheduler.instances[id] = new Scheduler(id, program);
}

//////////////////////////////////////////////////////////
// static callbacks
//////////////////////////////////////////////////////////

// when a user clicks on a cell we get call here; dispatch it to the scheduler instance
Scheduler.cellClick = function (skdId, cellId) {
	if (Scheduler.instances[skdId] === undefined) {
		return;
	}
	Scheduler.instances[skdId].clickCell(cellId);
}

// when a user clicks on a choice activity we get call here; dispatch it to the scheduler instance
Scheduler.activityClick = function (skdId, cellId, activityId) {
	if (Scheduler.instances[skdId] === undefined) {
		return;
	}
	Scheduler.instances[skdId].clickActivity(cellId, activityId);
}

//////////////////////////////////////////////////////////
// static functions for debugging
//////////////////////////////////////////////////////////

Scheduler.log = function (msg) {
	if (typeof console != 'undefined' && typeof console.log != 'undefined') {
		console.log(msg);
	}
}

Scheduler.error = function (msg) {
	if (typeof console != 'undefined' && typeof console.error != 'undefined') {
		console.error(msg);
	} else {
		throw (msg);
	}
}

// =================================================================================================
// jquery stuff
// =================================================================================================

jQuery.fn.clearForm = function() {
  return this.each(function() {
 var type = this.type, tag = this.tagName.toLowerCase();
 if (tag == 'form')
   return $(':input',this).clearForm();
 if (type == 'text' || type == 'password' || tag == 'textarea')
   this.value = '';
 else if (type == 'checkbox' || type == 'radio')
   this.checked = false;
 else if (tag == 'select')
   this.selectedIndex = -1;
  });
};


jQuery.fn.center = function(){
	this.css("position", "absolute");

  var top = ( $(window).height() - this.height() ) / 2 + $(window).scrollTop() + "px";
	var left = ( $(window).width() - this.width() ) / 2 + $(window).scrollLeft() + "px";
	//alert(top + ' ' + left);
	this.css("top", top);
  this.css("left", left);
  return this;
};


