--[[----------------------------------------------------------------------------

WFRatio.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2013 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remains the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and are protected by all applicable
intellectual property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

----------------------------------------------------------------------------]]--

local WFArguments = require 'WFArguments'

local WFRatioImp = require 'WFRatioImp'

local WFRatioImp_reduce = assert( WFRatioImp.reduce, "WFRatioImp_reduce" )
local WFRatioImp_add = assert( WFRatioImp.add, "WFRatioImp_add" )
local WFRatioImp_multiply = assert( WFRatioImp.multiply, "WFRatioImp_multiply" )

--==============================================================================
--[[!

	\brief \c WFRatio
	This namespace provides facility for dealing with fractions.  You can reduce
	fractions, add them and multiply them together.
	
	Ratios are represented simply as two-element arrays.
--]]

local WFRatio = {}

--------------------------------------------------------------------------------

--[[!
	\brief Reduce a ratio.
	\param ratio (table) a two element array
	\return (table) a two element array
--]]
function WFRatio.reduce( ratio )
	
	WFArguments.check( 'table' )
	
	return WFRatioImp_reduce( ratio )
	
end

--------------------------------------------------------------------------------

--[[!
	\brief add two ratios together, returning the result in reduced form
	\param ratioA (table) a two element array
	\param ratioB (table) a two element array
	\return (table) a two element array that is the sum of ratioA and ratioB.
--]]
function WFRatio.add( ratioA, ratioB )
	
	WFArguments.check( 'table', 'table' )
	
	return WFRatioImp_add( ratioA, ratioB )
	
end

--------------------------------------------------------------------------------

--[[!
	\brief Multiply two ratios together, returning the result in reduced form
	\param ratioA (table) a two element array
	\param ratioB (table) a two element array
	\return (table) a two element array that is the product of ratioA and ratioB.
--]]
function WFRatio.multiply( ratioA, ratioB )
	
	WFArguments.check( 'table', 'table' )
	
	return WFRatioImp_multiply( ratioA, ratioB )
	
end

--------------------------------------------------------------------------------

--[[!
	\brief Create a ratio from a rational number
	\param (number) number to convert to ratio
	\return (table) a two element array of numerator and denominator
--]]
function WFRatio.createFromNumber( number, optTolerance )

	-- this tolerance is important for accurate fractional representations
	-- it may need to be tweaked depending on the range of numbers being
	-- converted
	optTolerance = optTolerance or .0000001
	
	local floor =  math.floor( number )
	number = number - floor
	-- handle the round (or nearly round) cases
	if number < optTolerance then
		return { floor, 1 }
	elseif 1 - optTolerance < number then
		return { floor + 1, 1 }
	end
	
	-- lower and upper bounds for the fractional bit
	local lown = 0
	local lowd = 1
	local uppern = 1
	local upperd = 1
	
	while true do
		-- middle estimates for fraction
		local midn = lown + uppern
		local midd = lowd + upperd
		
		if midd * ( number + optTolerance ) < midn then
			uppern = midn
			upperd = midd
			
		elseif midd * ( number - optTolerance ) > midn then
			lown = midn
			lowd = midd
		
		else
			return { midn + ( floor * midd ), midd }
		end
	end
end

--==============================================================================

return WFRatio
