/**
 * Decimal to Fraction
 * 
 * @author reddoor.biz
 *
 * @usage
 *	jQuery.fn.decimal_to_fraction({
 *		decimal: 1.5
 *	});
 */

(function($) {
	var unicode = {
		"0.111":"<sup>1</sup>/<sub>9</sub>",
		"0.125":"&#8539;",
		"0.167":"&#8537;",
		"0.250":"&#188;",
		"0.333":"&#8531;",
		"0.375":"&#8540;",
		"0.500":"&#189;",
		"0.625":"&#8541;",
		"0.667":"&#8532;",
		"0.750":"&#190;",
		"0.833":"&#8538;",
		"0.875":"&#8542;"
	};

	var denom, o, n, dec_i;

	$.fn.decimal_to_fraction = function(options){
		// The jquery objects that contain our ingredient amounts.
		var ingredient = this;
		
		// Merge options with defaults
		o = $.extend({
			decimal: null,
			denominator: null,
			method: null
		}, options);
		
		var decimal_state = o.decimal;
		var denominator_state = o.denominator;
		
		return ingredient.each(function(){
			var item = $(this);
			
			// Reset these on each pass
			o.n = 0;
			dec_i = 0;
			
			// If decimal option is null, use the item's inner html.
			o.decimal = (decimal_state) ? o.decimal : item.html();
			
			// We need a integer from the decimal part here for mod calculation below.
			var dec_f_num = o.decimal + '';
			var dec_parts = dec_f_num.split('.');
			dec_f_num = (dec_parts.length > 1) ? parseInt(dec_parts[1]) : null;

			dec_i = Math.floor(o.decimal);   // Integer part of result
			var dec_f = o.decimal - dec_i;   // Calculate non-integer part of result
			
			//need to account for mor than thirds or eighths
			/*if(!denominator_state) {
				if((dec_f_num) && ((dec_f_num % 5) == 0)) {
					o.denominator = 8; // eighths or quarters
				} else {
					o.denominator = 3; // thirds
				}
			}
			*/			

			if(!denominator_state) {
				
				if((dec_f_num) && ((dec_f_num % 5) == 0)) {
					o.denominator = 8; // eighths or quarters
				} else {

					switch (dec_f_num)
					{
					case 167:
					case 833:
						o.denominator = 6; // sixths
						break;
					case 111:
						o.denominator = 9; //ninths
						break;
					default: 
						o.denominator = 3; // thirds
					}
				}
			}
			// We will express result using '1/$denom'ths of an inch.
			var rnd = 1.0 / o.denominator;
			
			if(dec_f > 0) {
				// How many 'n'ths of an inch?
				var nths = (dec_f / rnd);
				if(nths < 1) {
					o.n = Math.ceil(nths);
				} else {
					o.n = Math.floor(nths);
				}

				// Find gcd of n and denom in order to simplify the fraction.
				// This is only for the nicety of displaying 1/2 instead of 4/8, etc.
				var dv = gcd(o.n, o.denominator);

				// Divide n
				o.n /= dv;

				// and denom by gcd
				denom = o.denominator / dv;
			} else {
				// Show whole numbers and don't display zero
				o.decimal = (o.decimal > 0) ? o.decimal : '';
			}
			
			switch ( o.method ) {
				case 'text':
					item.html(getStrFraction());
					break;
				
				case 'html':
					item.html(getHtmlFraction());
					break;
				
				default:
					item.html(getStrUnicode());
					break;
			};
		});

	};

	/** Private Methods **/

	/**
	 * Returns HTML formatted string of the new fraction
	 */
	function getHtmlFraction() {
		var int = (dec_i > 0) ? dec_i + ' ' : '';
		if(o.n > 0) {
			
			return int + '<sup class="fracNum">' + o.n + '</sup>'
			+ '&#8260;'
			+ '<sub class="fracDen">' + denom + '</sub>';
		}

		return o.decimal;
	}

	/**
	 * Returns unformatted string of the new fraction
	 */
	function getStrFraction() {
		if(o.n > 0) {
			if (dec_i > 0) {
				return dec_i + ' ' + o.n + '/' + denom;
			} else {
				return o.n + '/' + denom;
			}
		}

		return o.decimal;
	}

	/**
	 * Returns unicode fraction entity of the new fraction.
	 * The denominator must be 3 or 8.
	 */
	function getStrUnicode() {
		// if dividing by other than 8, let's default to this.
		if((o.denominator != 3) && (o.denominator != 8)) return getHtmlFraction();
		if(o.n > 0) {
			var dec = o.n / denom;
			if((dec > 0) && (dec < 1)) {
				var index = dec.toFixed(4);
				if(fracEntity = unicode[index]) {
					return (dec_i > 0) ? dec_i + ' ' + fracEntity : fracEntity;
				} else {
					return getHtmlFraction();
				}
			}
		}
		
		return o.decimal;
	}

	// Find greatest common divisor of a and b using Euclid's algorithm
	function gcd(a, b) {
		if (a == 0) return b;
		while(b > 0 && a > 0) {
			if (a > b) {
				a -= b;
			} else {
				b -= a;
			}
		}
		return a;
	}

})(jQuery);

