// Invasion of the Body Switchers
// This copyright statement must remain in place for both personal and commercial use
// ***********************************************************************************
// Creative Commons License -- http://creativecommons.org/licenses/by-nc-nd/2.0/
// Original concept and article by Malarkey (Andy Clarke) -- http://www.stuffandnonsense.co.uk/
// DOM scripting by Brothercake (James Edwards) -- http://www.brothercake.com/
// Create element and attributes based on a method by beetle -- http://www.peterbailey.net/
//************************************************
//open initialisation function
function iotbs() { switcher = new switchManager();
//************************************************



/*****************************************************************************
 Define switching controls
*****************************************************************************/


//create a switcher form ('container-id', 'label')
var screenSwitcher = new bodySwitcher('text-switcher', 'Text Size:  ');

//add a new class option ('classname', 'label')
screenSwitcher.defineClass('default', 'Default Size');
screenSwitcher.defineClass('size10', 'Size 10px');
screenSwitcher.defineClass('size11', 'Size 11px');
screenSwitcher.defineClass('size12', 'Size 12px');
screenSwitcher.defineClass('size13', 'Size 13px');
screenSwitcher.defineClass('size14', 'Size 14px');
screenSwitcher.defineClass('size15', 'Size 15px');
screenSwitcher.defineClass('size16', 'Size 16px');
screenSwitcher.defineClass('size17', 'Size 17px');
screenSwitcher.defineClass('size18', 'Size 18px');
screenSwitcher.defineClass('size19', 'Size 19px');
screenSwitcher.defineClass('size20', 'Size 20px');
screenSwitcher.defineClass('size21', 'Size 21px');
screenSwitcher.defineClass('size22', 'Size 22px');
screenSwitcher.defineClass('size23', 'Size 23px');
screenSwitcher.defineClass('size24', 'Size 24px');
screenSwitcher.defineClass('size25', 'Size 25px');
screenSwitcher.defineClass('size26', 'Size 26px');
screenSwitcher.defineClass('size27', 'Size 27px');
screenSwitcher.defineClass('size28', 'Size 28px');


//create a switcher form ('container-id', 'label')
var screenSwitcher = new bodySwitcher('font-switcher', 'Font Style:  ');

//add a new class option ('classname', 'label')
screenSwitcher.defineClass('default', 'Normal Font');
screenSwitcher.defineClass('arial', 'Arial');
screenSwitcher.defineClass('bookantiqua', 'Book Antiqua');
screenSwitcher.defineClass('couriernew', 'Courier New');
screenSwitcher.defineClass('garamond', 'Garamond');
screenSwitcher.defineClass('georgia', 'Georgia');
screenSwitcher.defineClass('palatino', 'Palatino Linotype');
screenSwitcher.defineClass('times', 'Times');
screenSwitcher.defineClass('trebuchetms', 'Trebuchet MS');
screenSwitcher.defineClass('verdana', 'Verdana');

//create a switcher form ('container-id', 'label')
var screenSwitcher = new bodySwitcher('colour-switcher', 'Text Colour:  ');

//add a new class option ('classname', 'label')
screenSwitcher.defineClass('default', 'Default Colour');
screenSwitcher.defineClass('black', 'Black');
screenSwitcher.defineClass('dsblue', 'Dark Slate Blue');
screenSwitcher.defineClass('darkgreen', 'darkgreen');
screenSwitcher.defineClass('darkslategray', 'darkslategray');
screenSwitcher.defineClass('firebrick', 'Firebrick');
screenSwitcher.defineClass('khaki', 'Khaki');
screenSwitcher.defineClass('darkgoldenrod', 'darkgoldenrod');
screenSwitcher.defineClass('lavendar4', 'Lavendar Blush4');
screenSwitcher.defineClass('deepskyblue4', 'deepskyblue4');
screenSwitcher.defineClass('bisque4', 'bisque4');
screenSwitcher.defineClass('chartreuse4', 'chartreuse4');
screenSwitcher.defineClass('royalblue4', 'royalblue4');
screenSwitcher.defineClass('cornsilk4', 'cornsilk4');
screenSwitcher.defineClass('dodgerblue4', 'dodgerblue4');
screenSwitcher.defineClass('gold4', 'gold4');
screenSwitcher.defineClass('honeydew4', 'honeydew4');
screenSwitcher.defineClass('lightsteelblue4', 'lightsteelblue4');
screenSwitcher.defineClass('antiquewhite4', 'antiquewhite4');
screenSwitcher.defineClass('burlywood4', 'burlywood4');
screenSwitcher.defineClass('aquamarine4', 'aquamarine4');
screenSwitcher.defineClass('azure2', 'azure2');
screenSwitcher.defineClass('azure3', 'azure3');
screenSwitcher.defineClass('azure4', 'azure4');
screenSwitcher.defineClass('beige', 'beige');
screenSwitcher.defineClass('blue3', 'blue3');
screenSwitcher.defineClass('blue4', 'blue4');
screenSwitcher.defineClass('blueviolet', 'blueviolet');
screenSwitcher.defineClass('brown', 'brown');
screenSwitcher.defineClass('brown3', 'brown3');
screenSwitcher.defineClass('brown4', 'brown4');
screenSwitcher.defineClass('burlywood', 'burlywood');
screenSwitcher.defineClass('burlywood3', 'burlywood3');
screenSwitcher.defineClass('cadetblue', 'cadetblue');
screenSwitcher.defineClass('cadetblue3', 'cadetblue3');
screenSwitcher.defineClass('cadetblue4', 'cadetblue4');
screenSwitcher.defineClass('chartreuse3', 'chartreuse3');
screenSwitcher.defineClass('choc', 'choc');
screenSwitcher.defineClass('choc4', 'choc4');
screenSwitcher.defineClass('cornsilk2', 'cornsilk2');
screenSwitcher.defineClass('cornsilk3', 'cornsilk3');
screenSwitcher.defineClass('crimson', 'crimson');
screenSwitcher.defineClass('darkgoldenrod2', 'darkgoldenrod2');
screenSwitcher.defineClass('darkgoldenrod3', 'darkgoldenrod3');
screenSwitcher.defineClass('darkgoldenrod4', 'darkgoldenrod4');
screenSwitcher.defineClass('darkkhaki', 'darkkhaki');
screenSwitcher.defineClass('darkolivegreen', 'darkolivegreen');
screenSwitcher.defineClass('darkorange3', 'darkorange3');
screenSwitcher.defineClass('darkorange4', 'darkorange4');
screenSwitcher.defineClass('darkorchid4', 'darkorchid4');
screenSwitcher.defineClass('darkred', 'darkred');
screenSwitcher.defineClass('deepskyblue3', 'deepskyblue3');
screenSwitcher.defineClass('firebrick4', 'firebrick4');
screenSwitcher.defineClass('floralwhite', 'floralwhite');
screenSwitcher.defineClass('forestgreen', 'forestgreen');
screenSwitcher.defineClass('gainsboro', 'gainsboro');
screenSwitcher.defineClass('gold', 'gold');
screenSwitcher.defineClass('gold3', 'gold3');
screenSwitcher.defineClass('honeydew3', 'honeydew3');
screenSwitcher.defineClass('ivory2', 'ivory2');
screenSwitcher.defineClass('ivory3', 'ivory3');
screenSwitcher.defineClass('ivory4', 'ivory4');
screenSwitcher.defineClass('lemonchiffon2', 'lemonchiffon2');
screenSwitcher.defineClass('lemonchiffon3', 'lemonchiffon3');
screenSwitcher.defineClass('lemonchiffon4', 'lemonchiffon4');
screenSwitcher.defineClass('lightblue3', 'lightblue3');
screenSwitcher.defineClass('lightblue4', 'lightblue4');
screenSwitcher.defineClass('lightcyan3', 'lightcyan3');
screenSwitcher.defineClass('lightcyan4', 'lightcyan4');
screenSwitcher.defineClass('lightsteelblue3', 'lightsteelblue3');
screenSwitcher.defineClass('midnightblue', 'midnightblue');
screenSwitcher.defineClass('olivedrab', 'olivedrab');
screenSwitcher.defineClass('olivedrab3', 'olivedrab3');
screenSwitcher.defineClass('royalblue', 'royalblue');
screenSwitcher.defineClass('seashell4', 'seashell4');
screenSwitcher.defineClass('sgibrightgray', 'sgibrightgray');
screenSwitcher.defineClass('Meringue', 'Meringue');
screenSwitcher.defineClass('antiquewhite3', 'antiquewhite3');
screenSwitcher.defineClass('yellow3', 'yellow3');
screenSwitcher.defineClass('yellow4', 'yellow4');
screenSwitcher.defineClass('sgilightblue', 'sgilightblue');


/*****************************************************************************
*****************************************************************************/



//close initialisation function
};


//global preferences manager reference
var switcher;


//setup initialisation function
//.. gecko, safari, konqueror and generic
if(typeof window.addEventListener != 'undefined')
{
	window.addEventListener('load', iotbs, false);
}
//.. opera 7
else if(typeof document.addEventListener != 'undefined')
{
	document.addEventListener('load', iotbs, false);
}
//.. win/ie
else if(typeof window.attachEvent != 'undefined')
{
	window.attachEvent('onload', iotbs);
}


//preferences manager 
function switchManager()
{
	//string for storing the overall custom classname
	//I was originally storing it in the body class name directly
	//but 1.7+ mozilla builds were not honouring the trailing whitespace we need
	this.string  = '';
	
	//store reference to body element
	this.body = document.getElementsByTagName('body')[0];

	//store the initial classname
	this.initial = this.body.className;
	
	//if the default classname is empty, add "iotbs"
	//because we need there to be at least one classname already - 
	//the leading and trailing space in each custom classname is required, 
	//but you can't set the body classname as " something" (beginning with a leading space)
	//because that may not work in Opera 7
	if(this.initial == '')
	{
		this.initial = 'itobs';
	}
	
	//look for a stored cookie
	this.cookie = this.read();

	//if it exists
	if(this.cookie != null)
	{
		//store cookie value to string
		this.string = this.cookie;
		
		//set new body class name
		this.body.className = this.initial + this.string;
	}
	
	//*** dev
	//document.title = '<' + this.body.className.replace(/ /g,'+') + '>   [' + this.string.replace(/ /g,'+') + ']';
	
};

//set a cookie method
switchManager.prototype.set = function(days)
{
	//format expiry date
	this.date = new Date();
	this.date.setTime(this.date.getTime() + ( days *24*60*60*1000));
	
	//store the string, replacing spaces with '#' so that leading spaces are preserved
	this.info = this.string.replace(/ /g,'#');
	
	//if the value is empty, set its expiry in the past to delete the cookie
	if(this.info == '') { this.date.setTime(0); }
	
	//create the cookie
	document.cookie = 'bodySwitcher=' + this.info
		+ '; expires=' + this.date.toGMTString() 
		+ '; path=/';
		
};


//read a cookie method
switchManager.prototype.read = function()
{
	//set null reference so we always have something to return
	this.cookie = null;
	
	//if a cookie exists
	if(document.cookie)
	{
		//if it's our cookie
		if(document.cookie.indexOf('bodySwitcher')!=-1)
		{
			//extract and store relevant information (turning '#' back into spaces)
			this.cookie = document.cookie.split('bodySwitcher=');
			this.cookie = this.cookie[1].split(';');
			this.cookie = this.cookie[0].replace(/#/g,' ');
		}
	}
	
	return this.cookie;
};


//switcher form constructor
function bodySwitcher(divid, label)
{

	//create an associate array of classnames for this option
	//so we can later iterate through and remove them from the custom classname string
	this.classes = [];

	//start counting options, because we'll need the index of each option as it's created
	//so that an option can be selected by default if necessary
	this.options = 0;
	
	//outer form
	this.attrs = { 'action' : '' };
	this.form = this.createElement('form', this.attrs);
	document.getElementById(divid).appendChild(this.form);

	//fieldset inside form
	this.fieldset = this.createElement('fieldset');
	this.form.appendChild(this.fieldset);

	//label inside fieldset
	this.attrs = { 'for' : 'select-' + divid };
	this.label = this.createElement('label', this.attrs);
	this.fieldset.appendChild(this.label);

	//span inside label containing label text
	this.attrs = { 'text' : label };
	this.span = this.createElement('span', this.attrs);
	this.label.appendChild(this.span);

	//select inside label
	this.attrs = { 'id' : 'select-' + divid };
	this.select = this.createElement('select', this.attrs);
	this.label.appendChild(this.select);

	//create a global [within this scope] reference to 'this'
	var self = this;

	//bind onchange handler
	this.select.onchange = function()
	{

		//run through classnames array
		this.classLen = self.classes.length;
		for(var i=0; i < this.classLen; i++)
		{
			//remove this key (custom class name) from string
			switcher.string = switcher.string.replace(' ' + self.classes[i] + ' ','');
		}

		//get new value from option
		this.chosen = this.options[this.options.selectedIndex].value;

		//if it isn't default then add to string
		//we need both a leading and a trailing space to work with 
		//to avoid confusion with identical leading or trailing substrings in classnames,
		//such as "high" and "highcontrast" or "large-serif" and "small-serif"
		if(this.chosen != 'default')
		{
			switcher.string += ' ' + this.chosen + ' ';	
		}
		
		//set new body class name
		switcher.body.className = switcher.initial + switcher.string;

		//store changes to a cookie which expires a year from now
		switcher.set(365)
		
		//*** dev
		//document.title = '<' + switcher.body.className.replace(/ /g,'+') + '>   [' + switcher.string.replace(/ /g,'+') + ']';

	};

};

//add a new class option method
bodySwitcher.prototype.defineClass = function(key, val)
{
	//option inside select
	this.attrs = { 'value' : key, 'text' : val }; 
	this.option = this.createElement('option', this.attrs);
	this.select.appendChild(this.option);

	//check for cookie value 
	if(switcher.cookie != null)
	{
		//if value contains this key
		if(switcher.cookie.indexOf(' ' + key + ' ')!=-1)
		{
			//select this option
			this.select.selectedIndex = this.options;
		}
	}
	
	//store the classname 
	this.classes[this.options] = key;

	//increase option count
	this.options ++;

};

//create element and attributes method -- http://www.codingforums.com/showthread.php?s=&postid=151108
bodySwitcher.prototype.createElement = function(tag, attrs)
{
	//detect support for namespaced element creation, in case we're in the XML DOM
	this.ele = (typeof document.createElementNS != 'undefined') ? document.createElementNS('http://www.w3.org/1999/xhtml',tag) : document.createElement(tag);

	//run through attributes argument
	if(typeof attrs != 'undefined')
	{
		for(var i in attrs)
		{
			switch(i)
			{
				//create a text node
				case 'text' :
					this.ele.appendChild(document.createTextNode(attrs[i]));
					break;
				
				//create a class name
				case 'class' : 
					this.ele.className = attrs[i];
					break;
				
				//create a for attribute 
				case 'for' : 
					this.ele.setAttribute('htmlFor',attrs[i]);
					break;
				
				//create a generic attribute using IE-safe attribute creation
				default : 
					this.ele.setAttribute(i,'');
					this.ele[i] = attrs[i];
					break;
			}
		}
	}
	return this.ele;
};

