function UserProfile() { }
UserProfile.prototype = new EventDispatcher;

// Overriding the EventDispatcher property
UserProfile.prototype.events = {
	"load":new Array(),
	"save":new Array(),
	"delete":new Array()
};
// URL to get/set data
UserProfile.prototype.url = 'profile/';

// Create the fields for the actual profile
UserProfile.prototype.fields = {
	"id" : null,
	"username" : "",
	"alias" : "",
	"email" : "",
	"color" : ""
},

// Load a user from the primary key
UserProfile.prototype.load = function() {
	var req = request_manager.createAjaxRequest();
	req.get.id = this.fields.id;
	req.addEventListener('load', this.loadValues);
	req.open('GET', this.url);
	req.send();
}

/**
 * Assuming a response in the format of:
<?xml version="1.0"?>
<user>
	<id>23</id>
	<username>shawn</username>
	<alias>Shawn Lauriat</name>
	<email>shawn@frozen-o.com</email>
	<color>black</color>
</user> 
 */
UserProfile.prototype.loadValues = function(event) {
	// <user> node
	var user = event.request.responseXML.getElementsByTagName('user').item(0);
	// If no user node, stop right there
	if (!user) {
		return false;
	}
	for (var i in this.fields) {
		if (input = user.getElementsByTagname(i)) {
			this.fields[i] = input.item(0).firstChild.nodeValue;
		}
	}
	// Just need to send a quick loaded event
	var loaded_event = new CustomEvent();
	// Pass the UserProfile ID in the event
	loaded_event.userid = this.fields.id;
	this.dispatchEvent('load', loaded_event);
	return true;
}

// Save the current user
UserProfile.prototype.save = function() {
	var req = request_manager.createAjaxRequest();
	// Need to tell the server which user to save
	req.get.id = this.fields.id;
	for (var i in this.fields) {
		req.post[i] = this.fields[i];
	}
	// Assumes server-side code performs the action
	req.post.action = 'save';
	req.xhr.addEventListener('load', new Array(this, UserProfile.prototype.saved));
	req.open('POST', this.url);
	req.send();
}

// Dispatch the save event
UserProfile.prototype.saved = function(event) {
	// Just need to send a quick loaded event
	var saved_event = new CustomEvent();
	// Pass the UserProfile ID in the event
	saved_event.userid = this.fields.id;
	this.dispatchEvent('save', saved_event);
}

// Delete the current user. Note that we can't
// use this.delete because IE can't tell the
// difference between a JavaScript operator
// and an object method
UserProfile.prototype.eliminate = function() {
	var req = request_manager.createAjaxRequest();
	// Need to tell the server which user to delete
	req.get.id = this.fields.id;
	// Assumes server-side code performs the action
	req.post.action = 'delete';
	req.xhr.addEventListener('load', new Array(this, UserProfile.prototype.eliminated));
	req.open('POST', this.url);
	req.send();
}

// Dispatch the delete event
UserProfile.prototype.eliminated = function(event) {
	// Just need to send a quick loaded event
	var deleted_event = new CustomEvent();
	// Pass the UserProfile ID in the event
	deleted_event.userid = this.fields.id;
	this.dispatchEvent('delete', deleted_event);
}

function ProfileEvent() {
	this.id = null;
	this.username = null;
	this.alias = null;
	this.email = null;
	this.color = null;
}
ProfileEvent.prototype = new CustomEvent;

function ProfileView() { }
ProfileView.prototype = new EventDispatcher;
ProfileView.prototype.step = 0,
ProfileView.prototype.form = null;
ProfileView.prototype.label_template = null;
ProfileView.prototype.events = {
	"display":new Array(),	// New display
	"save":new Array(),		// Apply the edits
	"delete":new Array()		// Delete record
};
ProfileView.prototype.steps = new Array(
	{
		title : 'Account',
		fields : new Array(
			'username',
			'password',
			'password_confirm'
		)
		
	},
	{
		title : 'Profile',
		fields : new Array(
			'alias',
			'email',
			'color'
		)
	},
	{
		title : 'Confirm',
		fields : new Array(
			'username',
			'alias',
			'email',
			'color'
		)
	}
);
// In practice, it usually does not work out
// that you can use element IDs to match your
// variable names. This not only pairs elements
// with member variables, but also defines the
// validation regular expressions and holds
// the values until it all passes inspection.
ProfileView.prototype.profile = {
	id : {
		label : null,
		element : 'id',
		match : /^\d+$/,
		value : null
	},
	username : {
		label : 'Username',
		element : 'username',
		match : /^\w+$/,
		value : null
	},
	password : {
		label : 'Password',
		element : 'password',
		match : /^.+$/,
		value : null
	},
	password_confirm : {
		label : 'Confirm Password',
		element : 'password_confirm',
		match : /^.+$/,
		value : null
	},
	alias : {
		label : 'Alias',
		element : 'name',
		match : /^.+$/,
		value : null
	},
	email : {
		label : 'Email Address',
		element : 'email',
		match : /^[\w\-.]+@([\w\-]+\.)+[\w\-]{2,4}$/,
		value : null
	},
	color : {
		label : 'Favorite Color',
		element : 'color',
		match : /^(maroon)|(red)|(orange)|(yellow)|(olive)|(purple)|(fuchsia)|(white)|(lime)|(green)|(navy)|(blue)|(aqua)|(teal)|(black)|(silver)|(gray)$/,
		value : null
	}
};
// A simple object holding the values of the server object
ProfileView.prototype.profile_data = {
	id : null,
	username : null,
	name : null,
	email : null,
	color : null
};
ProfileView.prototype.syncFromUI = function() {
	var errors = false;
	for (var member in this.steps[this.step].fields) {
		var element = this.profile[this.steps[this.step].fields[member]] &&
			document.getElementById(this.profile[this.steps[this.step].fields[member]].element);
		if (!element) {
			continue;
		} else if (element.value == '') {
			// Quick notify of incorrect value
			var new_label = document.createTextNode('(Missing) ' + this.profile[this.steps[this.step].fields[member]].label + ':');
			element.parentNode.replaceChild(
				new_label,
				element.previousSibling
			);
			element.parentNode.style.fontWeight = 'bold';
			errors = true;
		} else if (!this.profile[this.steps[this.step].fields[member]].match.test(element.value)) {
			// Quick notify of incorrect value
			var new_label = document.createTextNode('(Incorrect) ' + this.profile[this.steps[this.step].fields[member]].label + ':');
			element.parentNode.replaceChild(
				new_label,
				element.previousSibling
			);
			element.parentNode.style.fontWeight = 'bold';
			errors = true;
		} else {
			// Assign the object's temporary member variable
			// the value from the form element
			this.profile_data[this.steps[this.step].fields[member]] = element.value;
			var new_label = document.createTextNode(this.profile[this.steps[this.step].fields[member]].label + ':');
			element.parentNode.replaceChild(
				new_label,
				element.previousSibling
			);
			element.parentNode.style.fontWeight = 'normal';
		}
	}
	if (errors) {
		if (!this.input_error) {
			this.input_error = messenger.displayError('Errors found');
		}
		return false;
	} else if (this.input_error) {
		messenger.removeError(this.input_error);
	}
	// If it made it this far, they all passed and
	// the new values get exist in their proper place
	// to get accessed by the rest of the application
	for (var member in this.steps[this.step].fields) {
		if (this.profile_data[this.steps[this.step].fields[member]]) {
			this.profile_data[this.steps[this.step].fields[member]] = this.profile[this.steps[this.step].fields[member]].value;
		}
	}
	return true;
}
ProfileView.prototype.syncToUI = function() {
	for (var member in this.profile) {
		var element = document.getElementById(this.profile[this.steps[this.step].fields[member]].element);
		if (!element) {
			continue;
		} else {
			// Simplified to show escaping output
			var escaped = this.profile[this.steps[this.step].fields[member]].value.replace(
								/[<>"&]/,
								function (s) {
									switch (s) {
										case '<':
											return '&lt;';
										case '>':
											return '&gt;';
										case '"':
											return '&quot;';
										case '&':
											return '&amp;';
									}
								}
							);
			element.value = escaped;
		}
	}
	this.dispatchEvent('display');
}
// Catch the form submission
ProfileView.prototype.submit = function(event) {
	if (profile.syncFromUI()) {
		this.nextStep();
	}

	// Return true regardess to keep the form
	// itself from submitting. This makes more
	// sense than it seems here. Returning
	// basically means "it ran"
	return true;
}
/**
 * Increment the counter or save
 */
ProfileView.prototype.nextStep = function() {
	if (this.step == this.steps.length) {
		var new_event = new ProfileEvent({
			id : profile.id,
			username : profile.username,
			name : profile.name,
			email : profile.email,
			color : profile.color
		});
		profile.dispatchEvent('complete', new_event);
	} else {
		// Switch tabs
		var tab_list = document.getElementById('registration_tabs');
		var tabs = tab_list.getElementsByTagName('li');
		tabs.item(this.step).className = 'completed';
		this.step++;
		tabs.item(this.step).className = 'selected';
		// Switch forms
		var labels = this.form.getElementsByTagName('label');
		var j = 0;
		for (var i in this.steps[this.step].fields) {
			var old_label = labels.item(j);
			if (this.steps[this.step].fields[i]) {
				var new_label = this.label_template.cloneNode(true);
				var new_label_text = document.createTextNode(this.profile[this.steps[this.step].fields[i]].label);
				var new_label_input = new_label.lastChild;
				new_label.insertBefore(new_label_text, new_label_input);
				new_label.setAttribute('for', this.profile[this.steps[this.step].fields[i]].element);
				new_label.setAttribute('tabindex', (j + 1));
				new_label.lastChild.setAttribute('id', this.profile[this.steps[this.step].fields[i]].element);
				new_label.lastChild.setAttribute('name', this.profile[this.steps[this.step].fields[i]].element);
				this.form.replaceChild(new_label, old_label);
				j++;
			} else {
				this.form.removeChild(old_label);
			}
		}
	}
}
/**
 * Add Event Listeners for various events this
 * particular view needs to know about.
 */
ProfileView.prototype.init = function() {
	// The form submission itself
	this.form = document.getElementById('registration');
	// In this case, if no profile form exists, the
	// script has no reason to attach itself to anything.
	if (!profile) {
		return false;
	}
	this.form.onsubmit = function() {
		ProfileView.prototype.submit.apply(profile, arguments);
		return false;
	};
	// Template element for dynamic form generation
	this.label_template = document.createElement('label');
	var input = document.createElement('input');
	input.setAttribute('type', 'text');
	this.label_template.appendChild(input);
}
var profile = new ProfileView();

function ProfileController() { }
ProfileController.prototype.model;
ProfileController.prototype.view;
/**
 * Called when the page first finishes loading
 * in order to make sure the objects and declarations
 * exist
 */
ProfileController.prototype.init = function() {
	// Instances to manage
	this.model = new UserProfile();
	this.view = profile;

	// Add the event listeners for the model
	this.model.addEventListener('load', controller.modelLoaded);
	this.model.addEventListener('save', controller.modelSaved);
	this.model.addEventListener('delete', controller.modelDeleted);

	// Add the event listeners for the view
	this.view.addEventListener('display', controller.viewDisplayed);
	this.view.addEventListener('save', controller.viewSaved);
	this.view.addEventListener('delete', controller.viewDeleted);
}
/**
 * Callback for this.model's load event
 */
ProfileController.prototype.modelLoaded = function(event) {
	this.view.profile.id = event.id;
	this.view.profile.username = event.username;
	this.view.profile.name = event.name;
	this.view.profile.email = event.email;
	this.view.syncToUI();
}
/**
 * Callback for this.model's save event
 */
ProfileController.prototype.modelSaved = function(event) {
	// let user know it worked.
	document.title = 'Profile - ' + event.name;
}
/**
 * Callback for this.model's delete event
 */
ProfileController.prototype.modelDeleted = function(event) {
	// let user know it worked.
	this.view.profile.id = '';
	this.view.profile.username = '';
	this.view.profile.name = '';
	this.view.profile.email = '';
	this.view.syncToUI();
	document.title = 'Profile';
}
/**
 * Callback for this.view's display event
 */
ProfileController.prototype.viewDisplayed = function(event) {
	document.title = 'Profile - ' + event.name;
}
/**
 * Callback for this.view's save event
 */
ProfileController.prototype.viewSaved = function(event) {
	// Brand new one or? Make a new Model
	if (this.model.id != event.id) {
		this.model = new UserProfile();
	}
	this.model.username = event.username;
	this.model.name = event.name;
	this.model.email = event.email;
	this.model.save();
}
/**
 * Callback for this.view's delete event
 */
ProfileController.prototype.viewDeleted = function(event) {
	// Only if still editing the same one
	if (this.model.id == event.id) {
		this.model.eleminate();
	}
}

var controller = new ProfileController();

/**
 * Since the form probably will not exist until after
 * this script runs, add event listeners when the
 * page has completely loaded.
 */
addElementListener(window, 'load', new Array(controller, ProfileController.prototype.init));
addElementListener(window, 'load', new Array(profile, ProfileView.prototype.init));
