var roomify = {
	// Pass in just one param, a js obj with jquery selectors for room dropdown, adults, children, infants,
	// and a success and error function, not all are required, like so:
	// roomify( {
	//	rooms: '#showRoom select.Room',
	//	adults: '#showRoom :input.Adults',
	//	children: '#showRoom :input.Children',
	//	success: function () {
	//	},
	//	error: function () {
	//	}
	// } );
	//
	// Also works if you just pass them in the old way, like:
	// roomify( 'select.Room',':input.Adults', ':input.Children', ':input.Infants', function () { }, function () { } } );
	// but only there for backward compatibility

	roomTypes: { 
		S10: { name: 'Single', a: 1, i: 1 }, 
		A20: { name: 'Double', a: 2, i: 1 },
		B20: { name: 'Twin', a: 2, i: 1 },
		M11: { name: 'Twin', a: 1, c: 1, i: 1 },
		D22: { name: 'Family', a: 2, c: 2, i: 1 },
		D13: { name: 'Family', a: 1, c: 3, i: 1 },
		C12: { name: 'Triple', a: 1, c: 2, i: 1 },
		C21: { name: 'Triple', a: 2, c: 1, i: 1 },
		C30: { name: 'Triple', a: 3, i: 1 }
	},
	roomTypePresets: {
		theatre: 	{	
						S10: { name: 'Single', a: 1, i: 1 }, 
						A20: { name: 'Double', a: 2, i: 1 },
						B20: { name: 'Twin', a: 2, i: 1 },
						M11: { name: 'Twin', a: 1, c: 1, i: 1 },
						D22: { name: 'Family', a: 2, c: 2, i: 1 },
						D13: { name: 'Family', a: 1, c: 3, i: 1 },
						C12: { name: 'Triple', a: 1, c: 2, i: 1 },
						C21: { name: 'Triple', a: 2, c: 1, i: 1 },
						C30: { name: 'Triple', a: 3, i: 1 } 
		},
		theme:		{	
						L10: { bed: 1, name: 'Single', a: 1, i: 1 },
						M11: { bed: 2, name: 'Twin', a: 1, c: 1, i: 1 },
						M20: { bed: 2, name: 'Twin', a: 2, i: 1 },
						L20: { bed: 2, name: 'Double', a: 2, i: 1 },
						L12: { bed: 3, name: 'Triple', a: 1, c: 2, i: 1 },
						L21: { bed: 3, name: 'Triple', a: 2, c: 1, i: 1 },
						L30: { bed: 3, name: 'Triple', a: 3, i: 1 },
						L13: { bed: 4, name: 'Family', a: 1, c: 3, i: 1 },
						L22: { bed: 4, name: 'Family', a: 2, c: 2, i: 1 },
						L31: { bed: 4, name: 'Family', a: 3, c: 1, i: 1 },
						L40: { bed: 4, name: 'Family', a: 4, i: 1 },
						L32: { bed: 5, name: 'Family', a: 3, c: 2, i: 1 },
						L23: { bed: 5, name: 'Family', a: 2, c: 3, i: 1 },
						L14: { bed: 5, name: 'Family', a: 1, c: 4, i: 1 },
						L33: { bed: 6, name: 'Family', a: 3, c: 3, i: 1 },
						L24: { bed: 6, name: 'Family', a: 2, c: 4, i: 1 },
						L15: { bed: 6, name: 'Family', a: 1, c: 5, i: 1 } 
		},
		pas: {
						L10: { bed: 1, name: 'Single', a: 1,       i: 1 },
						M11: { bed: 2, name: 'Twin',   a: 1, c: 1, i: 1 },
						L12: { bed: 3, name: 'Triple', a: 1, c: 2, i: 1 },
						L13: { bed: 4, name: 'Family', a: 1, c: 3, i: 1 },
						L14: { bed: 5, name: 'Family', a: 1, c: 4, i: 1 },
						L15: { bed: 6, name: 'Family', a: 1, c: 5, i: 1 },

						M20: { bed: 2, name: 'Twin',   a: 2,       i: 1 },
						L20: { bed: 2, name: 'Double', a: 2,       i: 1 },
						L21: { bed: 3, name: 'Triple', a: 2, c: 1, i: 1 },
						L22: { bed: 4, name: 'Family', a: 2, c: 2, i: 1 },
						L23: { bed: 5, name: 'Family', a: 2, c: 3, i: 1 },
						L24: { bed: 6, name: 'Family', a: 2, c: 4, i: 1 },

						L30: { bed: 3, name: 'Triple', a: 3,       i: 1 },
						L31: { bed: 4, name: 'Family', a: 3, c: 1, i: 1 },
						L32: { bed: 5, name: 'Family', a: 3, c: 2, i: 1 },
						//L33: { bed: 6, name: 'Family', a: 3, c: 3, i: 1 },

						L40: { bed: 4, name: 'Family', a: 4,       i: 1 }
			},
		selfCathering: {		
						L10: { bed: 1, 	name: 'Single', a: 1,       i: 1 },
						M11: { bed: 2, 	name: 'Twin',   a: 1, c: 1, i: 1 },
						L12: { bed: 3, 	name: 'Triple', a: 1, c: 2, i: 1 },
						L13: { bed: 4, 	name: 'Family', a: 1, c: 3, i: 1 },
						L14: { bed: 5, 	name: 'Family', a: 1, c: 4, i: 1 },
						L15: { bed: 6, 	name: 'Family', a: 1, c: 5, i: 1 },
						
						M20: { bed: 2, 	name: 'Twin',   a: 2,       i: 1 },
						L20: { bed: 2, 	name: 'Double', a: 2,       i: 1 },
						L21: { bed: 3, 	name: 'Triple', a: 2, c: 1, i: 1 },
						L22: { bed: 4, 	name: 'Family', a: 2, c: 2, i: 1 },
						L23: { bed: 5, 	name: 'Family', a: 2, c: 3, i: 1 },
						L24: { bed: 6, 	name: 'Family', a: 2, c: 4, i: 1 },
						
						L30: { bed: 3, 	name: 'Triple', a: 3,       i: 1 },
						L31: { bed: 4, 	name: 'Family', a: 3, c: 1, i: 1 },
						L32: { bed: 5, 	name: 'Family', a: 3, c: 2, i: 1 },
						L33: { bed: 6, 	name: 'Family', a: 3, c: 3, i: 1 },
						
						L40: { bed: 4, 	name: 'Family', a: 4, c: 0, i: 1 },
						L41: { bed: 5, 	name: 'Family', a: 4, c: 1, i: 1 },
						L42: { bed: 6, 	name: 'Family', a: 4, c: 2, i: 1 },
						
						L50: { bed: 5, 	name: 'Family', a: 5, c: 0, i: 1 },
						L51: { bed: 6, 	name: 'Family', a: 5, c: 1, i: 1 },
						
						L60: { bed: 6, 	name: 'Family', a: 6, c: 0, i: 1 }
				}
	},
	max: {},
	init: function ( param, a, c, i, success, error ) {
		if (	a ) { // old way
			this.dropdowns = $(param);
			this.a = $(a); // a for adults, jquery selector with number of adults
			this.c = $(c); // c for children, jquery selector with number of children
			this.i = $(i); // i for infants, jquery selector with number of infants
			this.success = success; // success is a function
			this.error = error; // function
		}
		else {	// new way, pass in just one param of { lang: lang } etc
			// var okParams = [ 'dropdown', 'adults', 'children', 'infants', 'success', 'error', 'lang' ];
			// for (	var i = 0; i < okParams.length; i ++ ) {
			// 	this[ okParams[i] ] = param[ okParams[i] ]; // this.foo === this['foo']
			// }
			this.dropdowns = param.dropdowns || param.rooms || ':input.Room';
			this.a = param.a || param.adults || ':input[name=Adults]';
			this.c = param.c || param.children || ':input[name=Children]';
			this.i = param.i || param.infants || ':input[name=Infants]';
			if (	param.roomTypes ) {
				this.roomTypes = param.roomTypes;
			}
			if (	param.success ) {
				this.success = param.success;
			}
			if (	param.error ) {
				this.error = param.error;
			}
			if (	param.debug ) {
				this.debug = param.debug;
			}
			this.max = { a: 3, c: 3, i: 1 }; // 'temporary' hard coding, can calculate this from this.roomTypes
		}
		var self = this;
		$(this.a).change( function () {
			self.calculate();
		} );
		$(this.c).change( function () {
			self.calculate();
		} );
		$(this.i).change( function () {
			self.calculate();
		} );
		$(this.dropdowns).change( function () {
			self.calculate();
		} ).parents('form').submit( function () {
			return self.calculate();
		} );
		self.calculate(); // and recalculate now
	},
	kill: function() { // We want to change the rooms setup, need to kill roomify
		$(this.a).unbind( 'change' ) ;
		$(this.c).unbind( 'change' ) ;
		$(this.i).unbind( 'change' ) ;
		$(this.dropdowns).unbind( 'change' ) ;
	},
	myInt: function ( n ) {
		var n = parseInt( n );
		return isNaN( n ) ? 0 : n;
	},
	beds: function ( id ) { // take an id, return an object of bed info
		var b = { a: 0, c: 0, i: 0 }; // b for beds, a for adults, c for children, i for infants
		if (	id ) {
			var r = this.roomTypes[id];
			b.a = this.myInt( r.a );
			b.c = this.myInt( r.c );
			b.i = this.myInt( r.i );
		}
		b.total = b.a + b.c;
		return b;
	},
	debug: function ( ) {
		// do nothing by default
	},
	getError: function ( ) {
		var err = '';
		var needed = { a: 0, c: 0, i: 0 }; // start with no adults, no children, no infants
		var self = this; // need to refer to 'this' within an each(), where 'this' will be out of scope
		$(this.a).each( function () {
			needed.a += self.myInt( $(this).val( ));
		});
		$(this.c).each( function () {
			needed.c += self.myInt( $(this).val( ));
		});
		$(this.i).each( function () {
			needed.i += self.myInt( $(this).val( ));
		});
		// this.debug( 'getError; Needed ' + needed.a + ' adult and ' + needed.c + ' child beds and ' + needed.i + ' cots... ' + err );
		var need = { a: needed.a, c: needed.c, i: needed.i };
		$(this.dropdowns).each( function ( i ) {
			$(this).addClass('roomify rooms');
			var beds = self.build( this, need );
			need.a -= beds.a;
			need.c -= beds.c;
			need.i -= beds.i;
		} );
		if (	needed.a > 0 ) {
			if (	need.a > 0 ) {
				err += 'Still need ' + need.a + ' adult bed(s).\n';
			}
			if (	need.a < 0 ) {
				err += 'Got too many ' + need.a + ' adult bed(s).\n';
			}
			if (	need.c > 0 ) {
				err += 'Still need ' + need.c + ' child bed(s).\n';
			}
			if (	need.c < 0 ) {
				err += 'Booked too many ' + need.c + ' child bed(s).\n';
			}
			if (	need.i > 0 ) { // max of one infant per room
				err += 'Still need ' + need.i + ' cot(s).\n';
			}
			return err;
		}
	},
	handleError: function ( e ) {
		if (	e && this.error ) {
			this.error( e ); // Pass error string back to error function, that can decide what to do with it
			$(this.dropdowns).parents('form').removeClass('ok');
			return false;
		}
		else {	if (	this.success ) {
				this.success();
			}
			$(this.dropdowns).parents('form').addClass('ok');
			return true;
		}
	},
	calculate: function ( ) { // a public method...
		return this.handleError( this.getError( ));
	},
	desc: function ( id ) { // get room description
		var r;
		if (	r = this.roomTypes[id] ) {
			var d = '' + r.name + ' (';
			if (	r.a ) {
				d += r.a + ' adult' + ( r.a == 1 ? '' : 's' );
			}
			if (	r.a && r.c ) {
				d += ' and ';
			}
			if (	r.c ) {
				d += r.c + ' child' + ( r.c == 1 ? '' : 'ren' );
			}
			d += ')';
			return d;
		}
	},
	build: function ( d, need ) { // rebuilds one dropdown, d for dropdown
		this.debug( 'build()' );
		var o = $(d).val( ); // original option
		d.options.length = 0; // truncate dropdown
		d.options[d.length] = new Option( 'Select a room', '' );
		// d.options[d.length] = new Option( 'original value was ' + o, '' );
		var freeRooms = 0; // There must be a one liner to count these...
		$(this.dropdowns).each( function () {
			if (	! $(this).val( )) {
				freeRooms ++;
			}
		} );
		myMin = { a: need.a, c: need.c };
		if (	! o ) {
			for (	var i = freeRooms - 1; i > 0; i -- ) {
				myMin.c -= this.max.c;
				myMin.a -= this.max.a;
			}
		}
		for (	var id in this.roomTypes ) {
			var beds = this.beds( id );
			if (	beds.a > need.a || beds.c > need.c ) {
				this.debug( id + ' is too big' );
			}
			else if ( ! o && ( beds.c < myMin.c || beds.a < myMin.a )) {
				this.debug( id + ' is too small' );
			}
			else if ( ! o && beds.a == need.a && beds.c < need.c ) {
				this.debug( id + ' ok for adults but kids left over!' );
			}
			else {	d.options[d.options.length] = new Option( this.desc( id ), id, id == o );
				// d.options[d.options.length] = new Option( this.desc( id ) + ' (debug, ' + id + ' == ' + o + '?)', id, id == o ); // ie doesn't seem to like this
			}
		}
		if (	o ) { // Reselect the original option if we can
			for (	var i = 0; i < d.length; i ++ ) {
				if (	d.options[i].value == o ) {
					d.selectedIndex = i;
				}
			}
		}
		$(d).attr( 'disabled', d.options.length <= 1 ); // disable the whole dropdown if no options
		if (	d.options.length == 2 ) { // including the 'Select a room', there is only one option, choose it
			d.selectedIndex = 1;
		}
		return this.beds( $(d).val( ));
	}
}; // Essential to have this last semicolon or 'low' embedded form compression fails!
