/* Copyright (c) 2009 Swizec Teller (swizec AT swizec DOT com || http://www.swizec.com)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * See http://swizec.com/code/styledButton/
 */

$.fn.styledButton = function ( params )
{
	$(this).each( function ()
	{
		var tempParams = $.extend( {}, params );
		var button = new styledButton( $(this), tempParams );
	} );
}

function styledButton( element, params )
{
	this.element = element;
	this.oldFirefox = ( $.browser.mozilla && parseFloat( $.browser.version ) < 1.9 );
	this.safari3 = ( $.browser.safari && parseFloat( $.browser.version ) < 526 ) ? true : false;
	this.inlineBlock = ( this.oldFirefox ) ? '-moz-inline-block' : 'inline-block';
	this.inParams = params;
	this.params = this.setupDefaultParams( params );
	this.info = this.init();

	this.bordersAndBackground();
	this.setupRole();
}

styledButton.prototype.setupDefaultParams = function ( params )
{
	if ( typeof( params ) == "undefined" )
	{
		params = {};
	}
	if ( typeof( params.orientation ) == "undefined" )
	{
		params.orientation = 'alone';
	}
	if ( typeof( params.action ) == "undefined" )
	{
		params.action = function () {};
		params.onclick = function () {};
	}else
	{
		params.onclick = params.action;
	}
	if ( typeof( params.cssClass ) == "undefined" )
	{
		params.cssClass = "button";
	}
	if ( typeof( params.role ) == "undefined" )
	{
		params.role = 'button';
	}
	if ( typeof( params.defaultValue ) == "undefined" )
	{
		params.defaultValue = '';
	}
	if ( params.role == "checkbox" )
	{
		if ( typeof( params.checkboxValue ) != "object" )
		{
			if ( params.defaultValue != '' )
			{
				var tmp = params.defaultValue;
			}else
			{
				var tmp = 'on';
			}
			params.checkboxValue = {};
			params.checkboxValue.on = tmp;
			params.checkboxValue.off = 'off';
		}
		if ( typeof( params.checked ) == "undefined" )
		{
			params.defaultValue = params.checkboxValue.off;
			params.checked = false;
		}else
		{
			params.checked = true;
			params.defaultValue = params.checkboxValue.on;
		}
		params.toggle = true;
		params.action = {};
		params.action.on = function ( calledOn ) { $(calledOn).styledButtonSetValue( params.checkboxValue.on ) };
		params.action.off = function ( calledOn ) { $(calledOn).styledButtonSetValue( params.checkboxValue.off ) };
	}
	if ( params.toggle )
	{
		if ( typeof( params.action ) != "object" )
		{
			var tmp = params.action;
			params.action = {};
			params.action.on = tmp;
			params.action.off = tmp;
		}


		params.onclick = {};
		params.onclick.on = function ( event ) {
						$(this).styledButtonActivate( event );
						params.action.on( $(this) )
					};
		params.onclick.off = function ( event ) {
						$(this).styledButtonDeactivate( event );
						params.action.off( $(this) )
					};
	}
	if ( typeof( params.dropdown ) == "undefined" )
	{
		params.hasDropdown = false;
		params.dropdown = {};
	}else
	{
		params.hasDropdown = true;
		if ( typeof( params.dropdown ) != 'object' )
		{
			params.dropdown = {};
		}
		if ( typeof( params.dropdown.element ) == "undefined" )
		{
			params.dropdown.element = 'ul';
		}
		if ( typeof( params.action ) != "object" )
		{
			var tmp = params.action;
			params.action = {};
			params.action.on = tmp;
			params.action.off = tmp;
		}

		params.toggle = true;
		params.onclick = {};
		params.onclick.on = function ( event ) {
						$(this).styledButtonActivate();
						$(this).styledButtonDropDownActivate();
					};
		params.onclick.off = function ( event ) {
						$(this).styledButtonDeactivate();
						$(this).styledButtonDropDownDeactivate();
					};
	}
	if ( typeof( params.display ) == "undefined" )
	{
		params.display = this.inlineBlock;
	}
	if ( typeof( params.border ) == "undefined" )
	{
		params.border = 1;
	}

	return params;
}

styledButton.prototype.init = function ( )
{
	var element = this.element;
	var params = this.params;

	if ( !$(this).is( '.'+params.cssClass ) )
	{
		element.addClass( params.cssClass );
	}
	element.addClass( "parent" );
	element.val( params.defaultValue );

	// this is here because otherwise sizes get calculated wrongly
	if ( params.hasDropdown )
	{
		this.hideDropdown();
	}

	var oldContent = element.html();
	var width = element.outerWidth();
	var height = element.outerHeight();
	var padding = {
			top: (element.outerHeight()-element.height())/2,
			left: (element.outerWidth()-element.width())/2
		}
	var innerLeft = 0;

	if ( this.safari3 )
	{
		innerLeft = -4;
	}else if ( $.browser.safari && params.hasDropdown )
	{
		if ( params.hasDropdown )
		{
			width += padding.left;
		}
	}

	if ( $.browser.msie )
	{
		if ( params.orientation == 'right' || params.orientation == 'center' )
		{
			innerLeft = -1;
		}
		if ( params.hasDropdown )
		{
			height -= 1;
		}
	}

	element.wrapInner( $('<span></span>').css({
							'padding' : padding.top+'px 0px '+padding.top+'px '+padding.left+'px',
							'margin' : 0,
							'z-index' : 1,
							'position' : 'absolute',
							'left' : innerLeft+'px',
							'display' : this.inlineBlock,
							'-moz-user-select' : 'none'
						})
		 			);

	var widthDelta = 0;
	if ( this.oldFirefox && params.orientation == 'right' )
	{
		widthDelta = 4;
	}

	element.css( {
		'cursor' : 'pointer',
		'padding-right': 0,
		'margin-left' : '-1px',
		'display' : params.display,
		'width' : width-padding.left+1+widthDelta
	} )
	.hover( function () {
			if ( !$(this).hasClass( 'hover' ) )
			{
				$(this).addClass( 'hover' );
				$(this).contents().styledButtonHover();
			}
		},
		function () {
			$(this).removeClass( 'hover' );
			$(this).removeClass( 'down' );
			$(this).contents().styledButtonUnhover();
		})
	.mousedown( function () {
			if ( !$(this).hasClass( 'down' ) )
			{
				$(this).addClass( 'down' );
				$(this).contents().styledButtonMouseDown();
			}
		})
	.mouseup( function () {
			$(this).removeClass( 'down' );
			$(this).contents().styledButtonMouseUp();
		});

	if ( this.oldFirefox && params.display != 'block' )
	{
		element.css({
			'float' : 'left',
			'clear' : ( params.clear ) ? params.orientation : 'none',
			'margin-top' : ( params.clear ) ? '1em' : 0
		});
	}

	if ( !params.toggle )
	{
		element.click( params.onclick );
	}else
	{
		if ( params.checked )
		{
			element.toggle( params.onclick.off, params.onclick.on );
		}else
		{
			element.toggle( params.onclick.on, params.onclick.off );
		}
	}

	var info = { 'oldContent' : oldContent, 'width' : width, 'height' : height, 'padding' : padding, 'border' : params.border };

	return info;
}

styledButton.prototype.bordersAndBackground = function ()
{
	var element = this.element;
	var params = this.params;
	var info = this.info;

	info.sizeDelta = 0;
	if ( $.browser.msie )
	{
		info.sizeDelta = info.border*2;
	}

	if ( params.orientation == 'left' )
	{
		this.background( {
				'width' : (info.width-info.border),
				'height' : info.height,
				'border' : info.border,
				'sizeDelta' : info.sizeDelta
			});
		this.bordersLeft( info );
	}else if ( params.orientation == 'center' )
	{
		this.background( {
				'width' : (info.width-info.border*2),
				'height' : info.height,
				'marginLeft' : info.border,
				'border' : info.border,
				'sizeDelta' : info.sizeDelta
			});
		this.bordersCenter( info );
	}else if ( params.orientation == 'right' )
	{
		this.background( {
				'width' : (info.width-info.border),
				'height' : info.height,
				'marginLeft' : info.border,
				'border' : info.border,
				'sizeDelta' : info.sizeDelta
			});
		this.bordersRight( info );
	}else if ( params.orientation == 'alone' )
	{
		this.background( info );
		this.bordersAlone( info );
	}
}

styledButton.prototype.background = function ( info )
{
	var element = this.element;
	var marginLeft = ( typeof( info.marginLeft ) != "undefined" ) ? info.marginLeft : 0;

	element.append( $('<span></span>').css({
							'width' : info.width,
							'height' : info.height,
							'z-index' : 0,
							'position' : 'absolute',
							'display' : this.inlineBlock,
							'margin-left' : marginLeft,
							'padding' : 0
						})
						.attr( 'class', 'background main' )
					);
	element.append( $('<span></span>').css({
							'width' : info.width,
							'height' : Math.floor( 4*info.height/10 )-info.sizeDelta,
							'font-size' : Math.floor( 4*info.height/10 )-info.sizeDelta,
							'z-index' : 0,
							'position' : 'absolute',
							'top' : 0,
							'display' : this.inlineBlock,
							'margin-left' : marginLeft
						})
						.attr( 'class', 'background top' )
					);
	element.append( $('<span></span>').css({
							'width' : info.width,
							'height' : Math.floor( 5*info.height/10 )-info.sizeDelta,
							'font-size' : Math.floor( 5*info.height/10 )-info.sizeDelta,
							'z-index' : 0,
							'position' : 'absolute',
							'bottom' : 0,
							'margin-top' : Math.floor( 5*info.height/10 )-info.sizeDelta,
							'margin-left' : marginLeft,
							'display' : this.inlineBlock
						})
						.attr( 'class', 'background bottom' )
					);
}

styledButton.prototype.bordersAlone = function ( info )
{
	var element = this.element;

	element.wrapInner( $('<span></span>').css({
							'width' : info.width,
							'height' : info.height+info.sizeDelta,
							'margin' : (-info.border)+'px 0 0 0',
							'display' : this.inlineBlock,
							'position' : 'absolute',
							'background' : 0,
							'border-left' : '0px',
							'border-right' : '0px'
						})
						.attr( 'class', 'border top' )
					);
	element.wrapInner( $('<span></span>').css({
							'width' : info.width+info.sizeDelta,
							'height' : info.height,
							'margin' : (-info.padding.top+1)+'px 0px 0px '+(-info.padding.left)+'px',
							'display' : this.inlineBlock,
							'border-top' : '0px',
							'border-bottom' : '0px'
						})
						.attr( 'class', 'border side' )
					);
}

styledButton.prototype.bordersLeft = function ( info )
{
	var element = this.element;

	element.wrapInner( $('<span></span>').css({
							'width' : info.width,
							'height' : info.height+info.sizeDelta,
							'margin' : (-info.border)+'px 0 0 0',
							'display' : this.inlineBlock,
							'position' : 'absolute',
							'background' : 0,
							'border-left' : '0px',
							'border-right' : '0px'
						})
						.attr( 'class', 'border top' )
					);
	element.wrapInner( $('<span></span>').css({
							'width' : info.width-info.border+info.sizeDelta,
							'height' : info.height,
							'margin' : (-info.padding.top+info.border)+'px 0px 0px '+(-info.padding.left)+'px',
							'display' : this.inlineBlock,
							'border-top' : '0px',
							'border-bottom' : '0px'
						})
						.attr( 'class', 'border side left' )
					);
}

styledButton.prototype.bordersCenter = function ( info )
{
	var element = this.element;

	element.wrapInner( $('<span></span>').css({
							'width' : info.width,
							'height' : info.height+info.sizeDelta,
							'margin' : (-info.border)+'px 0 0 '+(-info.border)+'px',
							'display' : this.inlineBlock,
							'position' : 'absolute',
							'background' : 0,
							'border-left' : '0px',
							'border-right' : '0px'
						})
						.attr( 'class', 'border top' )
					);
	element.wrapInner( $('<span></span>').css({
							'width' : info.width-info.border*2+info.sizeDelta,
							'height' : info.height,
							'margin' : (-info.padding.top+info.border)+'px 0px 0px '+(-info.padding.left+info.border)+'px',
							'display' : this.inlineBlock,
							'border-top' : '0px',
							'border-bottom' : '0px'
						})
						.attr( 'class', 'border side center' )
					);
}

styledButton.prototype.bordersRight = function ( info )
{
	var element = this.element;

	element.wrapInner( $('<span></span>').css({
							'width' : info.width,
							'height' : info.height+info.sizeDelta,
							'margin' : (-info.border)+'px 0 0 '+(-info.border)+'px',
							'display' : this.inlineBlock,
							'position' : 'absolute',
							'background' : 0,
							'border-left' : '0px',
							'border-right' : '0px'
						})
						.attr( 'class', 'border top' )
					);
	element.wrapInner( $('<span></span>').css({
							'width' : info.width-info.border+info.sizeDelta,
							'height' : info.height,
							'margin' : (-info.padding.top+info.border)+'px 0px 0px '+(-info.padding.left+info.border)+'px',
							'display' : this.inlineBlock,
							'border-top' : '0px',
							'border-bottom' : '0px'
						})
						.attr( 'class', 'border side right' )
					);
}

styledButton.prototype.hideDropdown = function ()
{
	var element = this.element;

	while ( !element.is( this.params.dropdown.element ) && element.contents().size() > 0 )
	{
		element = element.contents();
	}
	if ( element.is( this.params.dropdown.element ) )
	{
		$(element).css( {'display' : 'none'} );
	}
}

styledButton.prototype.setupRole = function ()
{
	var element = this.element;
	var params = this.params;

	element.attr( "role", params.role);

	if ( params.role != "button" )
	{
		element.append( '<input type="hidden" value="'+params.defaultValue+'" name="'+params.name+'"/>' );
	}

	if ( params.hasDropdown )
	{
		this.setupDropDown();
	}
	if ( params.role == "select" )
	{
		this.setupRoleSelect();
	}
	if ( params.role == "checkbox" && params.checked )
	{
		element.styledButtonActivate();
	}
}

styledButton.prototype.setupDropDown = function ()
{
	var element = this.element;
	var params = this.params;
	var info = this.info;

	while ( !element.is( params.dropdown.element ) && element.contents().size() > 0 )
	{
		element = element.contents();
	}

	var marginDelta = -1;
	if ( this.safari3 )
	{
		marginDelta = 3;
	}

	var topDelta = 0;
	var widthDelta = -4;
	if ( $.browser.msie )
	{
		topDelta = info.padding.top*3+params.border;
		widthDelta = 1;
	}

	if ( element.is( params.dropdown.element ) )
	{
		$(element).addClass( "dropdown" )
			.css( {
				'display' : 'none',
				'position' : 'absolute',
				'left' : '0px',
				'margin' : (info.padding.top+topDelta)+'px 0px 0px '+marginDelta+'px',
				'width' : info.width+widthDelta,
				'padding-right' : 0,
				'z-index' : 3
			});
	}
}

styledButton.prototype.setupRoleSelect = function ()
{
	var element = this.element;
	var params = this.params;
	var info = this.info;

	while ( !element.is( params.dropdown.element ) && element.contents().size() > 0 )
	{
		element = element.contents();
	}

	if ( element.is( params.dropdown.element ) )
	{
		$(element).children().click( function () {
				var value = $(this).attr( "value" );
				if ( typeof( value ) != "string" )
				{
					value = $(this).html();
				}
				$(this).styledButtonSetValue( value );
			} );
	}
}

//
// behaviour functions
//

$.fn.styledButtonSetValue = function ( value )
{
	var element = $(this);

	while ( !element.is( ".parent" ) && element.parent().size() > 0 )
	{
		element = element.parent();
	}

	$(element).val( value );
	if ( !$.browser.msie )
	{
		$(element).change();
	}

	while ( !element.is( "input" ) && element.contents().size() > 0 )
	{
		element = element.contents();
	}

	$(element).val( value )
}

$.fn.styledButtonHover = function ()
{
	$(this).addClass( 'hover' );

	if ( $(this).children().size() > 0 )
	{
		$(this).children().styledButtonHover();
	}
}

$.fn.styledButtonUnhover = function ()
{
	$(this).removeClass( 'hover' );
	$(this).removeClass( 'down' );

	if ( $(this).contents().size() > 0 )
	{
		$(this).contents().styledButtonUnhover();
	}
}

$.fn.styledButtonMouseDown = function ()
{
	$(this).addClass( 'down' );

	if ( $(this).contents().size() > 0 )
	{
		$(this).contents().styledButtonMouseDown();
	}
}

$.fn.styledButtonMouseUp = function ()
{
	$(this).removeClass( 'down' );

	if ( $(this).contents().size() > 0 )
	{
		$(this).contents().styledButtonMouseUp();
	}
}

$.fn.styledButtonActivate = function ()
{
	$(this).addClass( 'active' );

	if ( $(this).contents().size() > 0 )
	{
		$(this).contents().styledButtonActivate();
	}
}

$.fn.styledButtonDeactivate = function ()
{
	$(this).removeClass( 'active' );

	if ( $(this).contents().size() > 0 )
	{
		$(this).contents().styledButtonDeactivate();
	}
}

$.fn.styledButtonDropDownActivate = function ()
{
	if ( !$(this).is( '.dropdown' ) )
	{
		$(this).children().styledButtonDropDownActivate();
	}else
	{
		if ( $.browser.msie )
		{
			$(this).css( "display", "block" );
		}else
		{
			$(this).slideDown( 60 );
		}
	}
}

$.fn.styledButtonDropDownDeactivate = function ()
{
	if ( !$(this).is( '.dropdown' ) )
	{
		$(this).contents().styledButtonDropDownDeactivate();
	}else
	{
		if ( $.browser.msie )
		{
			$(this).css( "display", "none" );
		}else
		{
			$(this).slideUp( 20 );
		}
	}
}
