/*!
 * jGauge v0.3.0 Alpha 3
 * http://www.jgauge.com/
 * Date: 03 March 2011
 *
 * Copyright 2010-2011, Darian Cabot
 * Licensed under the MIT license
 * http://www.jgauge.com/#licence
 */


/*
 * CHANGE LOG: VERSION 0.3.0 ALPHA 3:
 * ====================================
 *
 *  - Added automatic 'SI/binary prefix' option for k, M, G, etc...
 *
 *  - Added SI/binary prefix support for gauge auto-ranging.
 *
 *  - Added auto-update off CSS from jGauge size settings.
 *
 *  - Added label and ticks.label color setting.
 *
 *  - Fixed findUpperLimit bug (not rounding value up).
 *
 *  - Fixed tick values and needle position when tick.start isn't 0 (zero).
 *
 *  - Fixed needle z-index issue.
 *
 *  - jGauge internals are more object oriented.
 *
 *  - All spelling for functions, vars, etc. changed to American-English from
 *    Australian-English. This is to follow the general code standards and
 *    avoid confusion.
 *
 * CHANGE LOG: VERSION 0.3.0 ALPHA 2:
 * ====================================
 *
 *  - Angles now referenced with 0deg to the right (not to the top). This is the
 *    more common standard.
 *
 *  - Defined 'jG' as base state for 'this' making code simpler and improving 
 *    readability.
 *
 *  - Fixed canvas element sizing. Now done through DOM, not CSS which never
 *    worked. This was only noticeable in gauges larger than 300x150 (the canvas
 *    element's default size).
 *    See: http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element
 *
 *  - All offsets now relative to gauge center point (not upper left corner).
 *    This has made positioning elements more intuative for a dial/circle gauge.
 *
 *  - Finished the .updateRange() function.
 *
 *  - Created the .resetLayers() function to tidy up after gauge changes that
 *    would otherwise bring the modified layer to front causing design problems.
 *
 *  - Consolidated number precision operations into a new .numberPrecision()
 *    function to eliminate code doubling-up.
 *
 *  - The .findUpperLimit() function has been simplified and now allows for a
 *    'multiple' to be specified to round up to.
 *
 *  - Made use of the .getHiddenDimensions() plugin to correctly layout label 
 *    elements during initialisation even if the jGauge (or parent) is hidden.
 *
 *  - Various other code tweaks.
 *
 * KNOWN ISSUES:
 * =============
 *
 *  - Canvas not working in Internet Explorer (ticks and range) despite 
 *    excanvas.min.js.
 *
 *  - Updating range after initialisation renders arc as black 100% opacity
 *    I've seen this behaviour in Chrome 7.0 and Safari.
 *
 *  - The limitAction only works for the upper bounds, not lower bounds.
 *
 *  - Upon first load (not cached) and using .setValue() for the first time
 *    after .initialize(), the needle animates from 0deg (right-side), not from
 *    the .tickStart value (usually left-side) as it should.
 *
 */


// Global vars...

// Expose the Limit Action Enum globally...
var limitAction = 
{
        spin: 0,
        clamp: 1,
        autoRange: 2
};

var autoPrefix = 
{
        none: 0, // No SI or binary prefixing, normal comma segmented number.
        si: 1, // SI prefixing (i.e. 1000^n) used for SI units / metric.
        binary: 2 // Binary prefixing (i.e. 1024^n) used for computer units.
};

function jGauge()
{
        // Define var of current 'this' state (helps prevent 'this' abuse).
        var jG = this;
        
        jG.version = '0.3.0.3'; // Major, minor, fix, release.
        
        jG.centerX = 0; // Internal use for positioning elements.
        jG.centerY = 0; // Internal use for positioning elements.
        
        // DEFAULT PARAMETERS FOR jGAUGE...
        jG.id = ''; // Default: nothing. Must be unique per jGauge instance.
        jG.segmentStart = -200; // Relative to 0deg (3-o-clock position).
        jG.segmentEnd = 20; // Relative to 0deg (3-o-clock position).
        jG.imagePath = 'img/jgauge_face_default.png'; // Background image path.
        jG.width = 160; // Total width of jGauge.
        jG.height = 114; // Total height of jGauge.
        jG.showAlerts = false; // Show error alerts? Useful when debugging.
        
        jG.autoPrefix = autoPrefix.si; // Automatically assigns prefix on label when approapriate (after value, before suffix) i.e. k, M, G, etc.
        
        jG.siPrefixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
        jG.binaryPrefixes = jG.siPrefixes;
        
        // Define the jGauge.needle object...
        function needle()
        {
                var ndl = this;
                ndl.imagePath = 'img/jgauge_needle_default.png'; // Needle image path.
                ndl.limitAction = limitAction.autoRange; // What to do when the needle hits the limit.
                ndl.xOffset = 0; // Shift needle position horizontally from center.
                ndl.yOffset = 24; // Shift needle position vertically from center.
        }
        
        // Add the needle object to the jGauge object.
        jG.needle = new needle();
        
        // Define the jGauge.label object...
        function label()
        {
                var lbl = this;
                lbl.color = '#144b66'; // Text color applied as CSS.
                lbl.precision = 1; // Value label rounding decimal places.
                lbl.prefix = ''; // Prefix for the value label (i.e. '$').
                lbl.suffix = ''; // Suffic for the value label (i.e. '&deg;C')
                lbl.xOffset = 0; // Shift label horizontally from center.
                lbl.yOffset = 20; // Shift label vertically from center.
        }
        
        // Add the label object to the jGauge object.
        jG.label = new label();
        
        // Define the jGauge.label object...
        function ticks()
        {
                var tks = this;
                tks.count = 11; // Number of tick marks around the gauge face.
                tks.start = 0; // Value of the first tick mark.
                tks.end = 10; // Value of the last tick mark.
                tks.color = 'rgba(255, 255, 255, 1)'; // Tick mark color.
                tks.thickness = 3; // Tick mark thickness.
                tks.radius = 76; // Tick mark radius (from gauge center point).
                tks.labelPrecision = 1; // Rounding decimals for tick labels.
                tks.labelRadius = 63; // Tick label radius (from gauge center).
                tks.labelColor = '#327a9e'; // Text color applied as CSS.
        }
        
        // Add the ticks object to the jGauge object.
        jG.ticks = new ticks();
        
        function range()
        {
                var rng = this;
                rng.radius = 55; // Range arc radius (from gauge center).
                rng.thickness = 36; // Range arc thickness (spread of the arc outwards).
                rng.start = -24; // Range start point as an angle relative to 0deg (pointing right).
                rng.end = 25; // Range end point as an angle relative to 0deg (pointing right).
                rng.color = 'rgba(255, 32, 0, 0.2)'; // Color and alpha (opacity) of the range arc.
        }
        
        jG.range = new range();
        
        jG.value = 0;
        
        // Function calls...
        jG.init = init; // Initialises the gauge and puts it on the page.
        jG.setValue = setValue; // Sets or updates the gauge value.
        jG.getValue = getValue; // Gets the current gauge value.
        jG.updateTicks = updateTicks; // Updates the tick marks and tick labels (call after changing tick parameters).
        jG.updateRange = updateRange; // Updates the range (call after changing range parameters).
        jG.resetLayers = resetLayers; // Puts all jGauge elements in the correct order. Intended for internal use.
        jG.prefixNumber = prefixNumber; // Modifies number to SI/binary prefixing (i.e. 5000 becomes 5k).


	/**
	 * Initialises the gauge.
	 * This creates the gauge and placing it on the page ready for use.
	 * @author Darian Cabot
	 */
        function init()
        {
                var labelCssLeft;  // For horizontally positioning label.
                var labelCssTop;   // For vertically positioning label.
                var needleCssLeft; // For horizontally positioning needle.
                var neeldeCssTop;  // For vertically positioning needle.
                
                // Find center of the gauge for positioning reference...
                // TODO: Verify the .gaugeWidth with the placeholder DIV width (same for height).
                jG.centerX = jG.width / 2;
                jG.centerY = jG.height / 2;
                
                // Update gauge CSS with set jGauge dimensions.
                $('#' + jG.id).css({'width': jG.width, 'height': jG.height});
                
                // Wipe the slate clean in case gauge already initialized.
                $('#' + jG.id).children().remove();
                
                // Add the background image.
                $('#' + jG.id).css('background-image', 'url("' + jG.imagePath + '")');
                
                // Create the range arcs and put them on the gauge.
                jG.updateRange();
                
                // Create the ticks and put them on the gauge.
                jG.updateTicks();
                
                // Add the main label...
                htmlString = '<p id="' + jG.id + '-label" class="label">' + 
                        jG.label.prefix + '<strong>' + jG.ticks.start + 
                        '</strong>' + jG.label.suffix + '</p>';
                        
                $('#' + jG.id).append(htmlString);
                
                // Position the main label...
                labelCssLeft = Math.round(jG.centerX - $('#' + jG.id + '-label').getHiddenDimensions().w / 2 + jG.label.xOffset) + 'px';
                labelCssTop = Math.round(jG.centerY - $('#' + jG.id + '-label').getHiddenDimensions().h / 2 + jG.label.yOffset) + 'px';
                $('#' + jG.id + '-label').css({'left': labelCssLeft, 'top': labelCssTop});
                
                // Apply label color...
                $('#' + jG.id + ' .label').css('color', jG.label.color);
                
                
                // Label created, so reveal it.
                $('#' + jG.id + '-label').fadeIn('slow');
                
                
                // Add the needle...
                htmlString = '<img id="' + jG.id + '-needle" class="needle" src="' + jG.needle.imagePath + '" />';
                $('#' + jG.id).append(htmlString);
                
                $('#' + jG.id + '-needle').load(function() {
                        // Position needle once it's done loading...
                        needleCssLeft = Math.round(jG.centerX - ($('#' + jG.id + '-needle').getHiddenDimensions().w / 2) + jG.needle.xOffset) + 'px';
                        neeldeCssTop = Math.round(jG.centerY - ($('#' + jG.id + '-needle').getHiddenDimensions().h / 2) + jG.needle.yOffset) + 'px';
                        $('#' + jG.id + '-needle').css({'left': needleCssLeft, 'top': neeldeCssTop});
                });
                
                // Needle created, so reveal it.
                $('#' + jG.id + '-needle').fadeIn('slow');
                
                // Ensure everything's in the correct order.
                jG.resetLayers();
                
                // Set the needle to the lowest value.
                // This is initially run TWICE to stop an animation glitch.
                // If it's run only once, the next value will be animated from the needle in
                // the 3-o-clock position even though it should come from it's initial position.
                // I'll look into this further soon but it *may* be caused by jQueryRotate?
                jG.setValue(jG.ticks.start);
                jG.setValue(jG.ticks.start);
        }


	/**
	 * Puts all of the jGauge elements in the correct order.
	 * This is required because updating a single canvas layer was bringing
	 * that layer to top messing up the design.
	 * @author Darian Cabot
	 */
	function resetLayers()
	{
		$('#' + jG.id).css('z-index', 0);
		$('#' + jG.id + '-canvas-ranges').css('z-index', 1);
		$('#' + jG.id + '-canvas-ticks').css('z-index', 2);
		$('#' + jG.id + ' .tick-label').css('z-index', 3);
		$('#' + jG.id + '-label').css('z-index', 4);
		$('#' + jG.id + '-needle').css('z-index', 5); // This one doesn't work (overwritten by jQueryRotate??).
	}
	
	
	/**
	 * Creates the range arcs on the gauge face.
	 * @author Darian Cabot
	 */
	function updateRange()
	{
	        var canvas; // The canvas used for the range.
	        var ctx; // The 2D convas context for drawing.
	        
		// Remove any existing ticks canvas.
		$('#' + jG.id + '-canvas-ranges').remove();
		
		// Create range arcs by drawing on a new canvas...
		htmlString =  '<canvas id="' + jG.id + '-canvas-ranges"></canvas>';
		$('#' + jG.id).append(htmlString);
		
		// Reference the canvas element we just created.
		canvas = document.getElementById(jG.id + '-canvas-ranges');
		
		// Resize canvas...
		canvas.width = jG.width;
		canvas.height = jG.height;
		
		// Make sure we don't execute when canvas isn't supported.
		if (canvas.getContext)
		{
			// Use getContext to use the canvas for drawing.
			ctx = canvas.getContext('2d');
			
			ctx.strokeStyle = jG.range.color;
			ctx.lineWidth = jG.range.thickness;
			
			ctx.beginPath();
			
			// The canvas arc parameters are as follows:...
			// arc(x, y, radius, startAngle, endAngle, anticlockwise).
			ctx.arc(jG.centerX + jG.needle.xOffset, 
				jG.centerY + jG.needle.yOffset, 
				jG.range.radius, 
				(Math.PI / 180) * jG.range.start, 
				(Math.PI / 180) * jG.range.end, 
				false);
			
			// Draw range arc on canvas.
			ctx.stroke();
			jG.resetLayers();
		}
		else
		{
			// Canvas not supported!
			
			/* @TODO: alert() is a bit blunt, some other notification
			 * should be used instead.
			 */
			
			if (jG.showAlerts === true)
			{
				alert('Sorry, canvas is not supported by your browser!');
			}
		}
	}
	
	
	/**
	 * Creates the tick marks and labels on the gauge face.
	 * @author Darian Cabot
	 */
	function updateTicks()
	{
		var gaugeSegmentStep;
		var htmlString;
		var canvas;
		var ctx;
		var startAngle;
		var endAngle;
		var tickStep;
		
                var leftOffset;
                var topOffset;
                var tickLabelCssLeft;
                var tickLabelCssTop;
		
		// FIRST: Draw ticks on gauge...
		
		// Remove any existing ticks canvas.
		$('#' + jG.id + '-canvas-ticks').remove();
		
		// Check if there is actually anything to draw...
		if (jG.ticks.count !== 0 || jG.ticks.thickness !== 0)
		{
			// Create ticks by drawing on a canvas...
			htmlString = '<canvas id="' + jG.id + '-canvas-ticks"></canvas>';
			$('#' + jG.id).append(htmlString);
			
			// Reference the canvas element we just created.
			canvas = document.getElementById(jG.id + '-canvas-ticks');
			
			// Resize canvas...
			canvas.width = jG.width;
			canvas.height = jG.height;

			// Make sure we don't execute when canvas isn't supported
			if (canvas.getContext)
			{
				// use getContext to use the canvas for drawing
				ctx = canvas.getContext('2d');
				
				// Draw ticks
				gaugeSegmentStep = Math.abs(jG.segmentStart - jG.segmentEnd) / (jG.ticks.count - 1);
				ctx.strokeStyle = jG.ticks.color;
				ctx.lineWidth = 5;
				
				for (i = 0; i <= jG.ticks.count - 1; i ++)
				{
					startAngle = (Math.PI / 180) * (jG.segmentStart + (gaugeSegmentStep * i) - (jG.ticks.thickness / 2));
					endAngle = (Math.PI / 180) * (jG.segmentStart + (gaugeSegmentStep * i) + (jG.ticks.thickness / 2));
					
					ctx.beginPath();
					
					ctx.arc(jG.centerX + jG.needle.xOffset, 
						jG.centerY + jG.needle.yOffset, 
						jG.ticks.radius, 
						startAngle, 
						endAngle, 
						false);
					
					ctx.stroke();
				}
				jG.resetLayers();
			}
			else
			{
				// Canvas not supported!
				
				/* @TODO: alert() is a bit blunt, some other notification
				 * should be used instead.
				 */
				 
				if (jG.showAlerts === true)
				{
					alert('Sorry, canvas is not supported by your browser!');
				}
			}
		}
		
		
		// THIRD: Place tick labels on gauge...
		
		// Remove the existing tick labels.
		$('#' + jG.id + ' .tick-label').remove();
		
		// Check if there is actually anything to draw...
		if (jG.tickCount !== 0)
		{
			// Calculate the step value between each tick.
			tickStep = (jG.ticks.end - jG.ticks.start) / (jG.ticks.count - 1);
			gaugeSegmentStep = Math.abs(jG.segmentStart - jG.segmentEnd) / (jG.ticks.count - 1);

			for (i = 0; i <= jG.ticks.count - 1; i ++)
			{
				// Calculate the tick value, round it, stick it in html...
				//var htmlString = '<p class="tick-label">' + addCommas(numberPrecision((i * tickStep), jG.ticks.labelPrecision)) + '</p>';
				htmlString = '<p class="tick-label">' + prefixNumber(jG.ticks.start + i * tickStep, false) + '</p>';
				
				
				// Add the tick label...
				$('#' + jG.id).append(htmlString);
				
				// Calculate the position of the tick label...
				leftOffset = jG.centerX + jG.needle.xOffset - $('#' + jG.id + ' .tick-label').getHiddenDimensions().w / 2;
				topOffset = jG.centerY + jG.needle.yOffset - $('#' + jG.id + ' .tick-label').getHiddenDimensions().h / 2;
				tickLabelCssLeft = Math.round((jG.ticks.labelRadius * Math.cos((jG.segmentStart + (i * gaugeSegmentStep)) * Math.PI / 180)) + leftOffset) + 'px';
				tickLabelCssTop = Math.round(jG.ticks.labelRadius * Math.sin(Math.PI / 180 * (jG.segmentStart + (i * gaugeSegmentStep))) + topOffset) + 'px';
				
				$('#' + jG.id + ' p:last').css({'left': tickLabelCssLeft, 'top': tickLabelCssTop});
			}

                        // Apply label color...
                        $('#' + jG.id + ' .tick-label').css('color', jG.ticks.labelColor);
                        
			// Tick labels are all created, so reveal them together.
			$('#' + jG.id + ' .tick-label').fadeIn('slow');
		}
	}


	/**
	 * Changes the gauge value (needle and read-out label).
	 * The gauge must be initialized with createGauge() before this is called.
	 * @author Darian Cabot
	 * @param {Number} newValue The new value for the gauge.
	 */
	function setValue(newValue)
	{
	        var degreesMult;
	        var valueDegrees;
	        var htmlString;
	        var needleCssLeft;
	        var needleCssTop;
	        
		// First set the internal value variable (so we can return if required).
		jG.value = newValue;
		
		// Scale the 'value' to 'degrees' around the gauge.
		degreesMult = (jG.segmentEnd - jG.segmentStart) / (jG.ticks.end - jG.ticks.start);
		valueDegrees = degreesMult * (newValue - jG.ticks.start);

		// Check the needle is in bounds...
		// TODO: This is only checking the upper limit, we should also be checking the lower limit.
		if (valueDegrees > Math.abs(jG.segmentStart - jG.segmentEnd))
		{
			if (jG.needle.limitAction === limitAction.autoRange)
			{
                                jG.ticks.end = findUpperLimit(newValue, 10);
                                jG.updateTicks();
                                // TODO: update range also (range should be set with gauge values, not degress).

                                // Scale the 'value' to 'degrees' around the gauge AGAIN.
                                valueDegrees = newValue * (jG.segmentEnd - jG.segmentStart) / (jG.ticks.end - jG.ticks.start);
			}
			else if (jG.needle.limitAction === limitAction.clamp)
			{
                                // Clamp needle to gauge limit (stops the needle spinning).
                                valueDegrees = Math.abs(jG.segmentStart - jG.segmentEnd);

                                // Shake the needle to simulate bouncing off the limit...
                                // TODO: wait until needle finished moving before 'bouncing'.
                                $('#' + jG.id + '-needle')
                                        .animate({ top: '+=2', left: '-=2' }, 50)
                                        .animate({ top: '-=2', left: '+=2' }, 50)
                                        .animate({ top: '+=2', left: '-=2' }, 50)
                                        .animate({ top: '-=2', left: '+=2' }, 50);
			}
		}
		
		// Rotate the needle...
		$('#' + jG.id + '-needle').rotateAnimation(jG.segmentStart + valueDegrees);
		$('#' + jG.id + '-needle').css('position', 'absolute'); // This *MUST* be set after image-rotation!
		
		// Reposition needle (sometimes the needle moves off axis - witnessed in Firefox 3.6)...
		needleCssLeft = Math.round(jG.centerX - $('#' + jG.id + '-needle').width() / 2 + jG.needle.xOffset) + 'px';
		needleCssTop = Math.round(jG.centerY - $('#' + jG.id + '-needle').height() / 2 + jG.needle.yOffset) + 'px';
		$('#' + jG.id + '-needle').css({'left': needleCssLeft, 'top': needleCssTop});
		
		// Build the label string (and apply any SI / binary prefix)...
		htmlString = prefixNumber(newValue, true);
		
		// Update label value...
		$('#' + jG.id + '-label').html(htmlString);
	}
	
	
	/**
	 * Gets the gauge value.
	 * @returns The current gauge value.
	 * @type Number
	 */
	function getValue()
	{
		return this.value;
	}
	
	
	/**
	 * Returns a SI / binary prefixed string from a number.
	 * @author Darian Cabot
	 * @param {Number} value A number to be rounded.
	 * @param {Boolean} formatting Whether to include prefix/suffix and bold value (usually true for gauge label and false for tick labels).
	 * @returns the SI/binary prefixed number as a string (i.e. 2500 becomes 2.5k).
	 * @type String
	 */
	function prefixNumber(value, formatting)
	{
		var power = 0;
		var prefix = '';
		
		switch (jG.autoPrefix)
		{
			case autoPrefix.si:
				
				while (value >= 1000)
				{
					power ++;
					value /= 1000;
				}
				
				prefix = jG.siPrefixes[power];
				
				break;
			
			case autoPrefix.binary:
				
				while (value >= 1024)
				{
					power ++;
					value /= 1024;
				}
				
				prefix = jG.binaryPrefixes[power];
				
				break;
		}
		
		// Build the label string (and apply any SI / binary prefix)...
		if (formatting === true)
		{
			return jG.label.prefix + '<strong>' + addCommas(numberPrecision(value, jG.label.precision)) + '</strong> ' + prefix + jG.label.suffix;
		}
		else
		{
			return addCommas(numberPrecision(value, jG.label.precision)) + prefix;
		}
	}
	
	
	/**
	 * Returns an upper limit (range) based on the value and multiple.
	 * It rounds the value up the the closest multiple.
	 * TODO: Factor in the number of ticks and avoid wierd decimal values for ticks.
	 * @author Darian Cabot
	 * @param {Number} value The gauge value that the range is to be suited to.
	 * @param {Number} multiple The multiple to round up to.
	 * @returns the closest multiple above the value.
	 * @type Number
	 */
	function findUpperLimit(value, multiple)
	{
		
		//return Math.ceil(Math.ceil(value) / multiple) * multiple; // Old method (prior to SI/binary prefixing).
		
		var power = 0;
		var bump = 0;
		
		if (jG.autoPrefix === autoPrefix.binary)				
		{
			// Special case for binary mode...
			
			while (value >= 2)
			{
				power ++;
				value /= 2;
			}
			
			return Math.pow(2, power + 1);
		}
		else
		{
			multiple /= 10;
			
			while (value >= 10)
			{
				power ++;
				value /= 10;
			}
			
			while (value > bump)
			{
				bump += multiple;
			}
			
			// parseInt is used to ensure there aren't any wierd float decimals (i.e. 4.999~ instead of 5).
			return parseInt(bump * Math.pow(10, power), 10);
		}
	}
	
}


// Helper functions...

/**
 * Returns a rounded number to the precision specified.
 * @author Darian Cabot
 * @param {Number} value A number to be rounded.
 * @param {Number} decimals The number of decimal places to round to.
 * @returns the value rounded to the number of decimal places specified.
 * @type Number
 */
numberPrecision = function(value, decimals)
{
	return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
};


/**
 * Formats a numeric string by adding commas for cosmetic purposes.
 * @author Keith Jenci
 * @see http://www.mredkj.com/javascript/nfbasic.html
 * @param {String} nStr A number with or without decimals.
 * @returns a nicely formatted number.
 * @type String
 */
addCommas = function(nStr)
{
	nStr += '';
	var x = nStr.split('.');
	var x1 = x[0];
	var x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	
	while (rgx.test(x1))
	{
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	
	return x1 + x2;
};


(function($)
{
	$.fn.getHiddenDimensions = function(boolOuter)
	{
		var $item = this;
		var props = { position: 'absolute', visibility: 'hidden', display: 'block' };
		var dim = { 'w':0, 'h':0 };
		var $hiddenParents = $item.parents().andSelf().not(':visible');
		
		var oldProps = [];
		$hiddenParents.each(function()
		{
			var old = {};
			
			for (var name in props)
			{
				old[ name ] = this.style[ name ];
				this.style[ name ] = props[ name ];
			}
			
			oldProps.push(old);
		});
		
		if (!false === boolOuter)
		{
			dim.w = $item.outerWidth();
			dim.h = $item.outerHeight();
		}
		else
		{
			dim.w = $item.width();
			dim.h = $item.height();
		}
		
		$hiddenParents.each(function(i)
		{
			var old = oldProps[i];
			for (var name in props)
			{
				this.style[ name ] = old[ name ];
			}
		});
		
		return dim;
	};
}(jQuery));


