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

WFCatFormatterUtils.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 Adobe Systems IncorporatedAll Rights Reserved.

NOTICE: All information contained herein is, and remain 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 may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

	-- WF.core.utils
local KSTableUtils = require 'KSTableUtils'
local KSStringUtils = require 'KSStringUtils'

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

local WFCatFormatterUtils = {}

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

function WFCatFormatterUtils.extractNumeratorDenominator( val )
	
	if not val then return end

	local _, numerator, denominator

	if type( val ) == 'string' then
		_, _, numerator, denominator = string.find( val, "(-?[0-9]+)/([0-9]+)")
	end

	if type( val ) == 'table' then
		numerator, denominator = val[ 1 ], val[ 2 ]
	end

	if numerator then

		numerator = tonumber( numerator )
		denominator = tonumber( denominator )

		if numerator > 0 and denominator > 0 then

			-- Fix 2436050 : For fractions that are sufficiently close to 1/3 or 2/3

			local realValueX100 = math.floor( 30000 * numerator / denominator )

			if realValueX100 == 10000 then
				return 1, 3
			elseif realValueX100 == 20000 then
				return 2, 3
			end

		end

		return numerator, denominator

	end

	return nil

end

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

function WFCatFormatterUtils.convertToNumericValue( val )

	if type( val ) == "number" then

		return val

	end

	if type( val ) == "table" then

		local numerator = val[ 1 ]
		local denominator = val[ 2 ]

		if type( numerator ) == "number"  and type( denominator ) == "number" and denominator ~= 0 then

			return numerator / denominator

		end

	end

end

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

function WFCatFormatterUtils.localizedFStopString( stopVal, preferASCII )

	local result = ""

	if stopVal < 1.0 then
		result = { "number", stopVal, 2 }
	elseif stopVal < 10.0 then
		result = { "number", stopVal, 1 }
	else
		result = { "number", stopVal, 0 }
	end

	local template

	if preferASCII then
		template = "$$$/AgLibrary/Exif/FStopTemplate/ASCII=f / ^0"
	else
		template = "$$$/AgLibrary/Exif/FStopTemplate=^U+0192 / ^0"

	end

	return 'ZSTR', template, result
end

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

function WFCatFormatterUtils.convertAPEXToAperture( apertureValue, preferASCII )

	local numResult = WFCatFormatterUtils.convertToNumericValue( apertureValue ) or 0
	numResult = math.pow( 2.0, numResult / 2.0 )

	-- round it to two decimal places in case it is a number
	-- like 10.9999999 which should be displayed as 11

	numResult = math.floor( numResult * 100 + 0.5 ) / 100
	return WFCatFormatterUtils.localizedFStopString( numResult, preferASCII )
end

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

local pointThreeBot = 0.275
local pointThreeTop = 0.31667

local function getDecimalBasedDisplayValue( dec )

	if 0.95 < dec and dec < 1.0 then
		return 1
	elseif 0.85 <= dec and dec < 0.95 then
		return 0.9
	elseif 0.75 <= dec and dec < 0.85 then
		return 0.8
	elseif 0.65 <= dec and dec < 0.75 then
		return 0.7
	elseif 0.55 <= dec and dec < 0.65 then
		return 0.6
	elseif 0.45 <= dec and dec < 0.55 then
		return 0.5
	elseif 0.35 <= dec and dec < 0.45 then
		return 0.4
	elseif pointThreeBot <= dec and dec < pointThreeTop then
		return 0.3
	end

end

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

local function apexToNumDenom( n )
	return 1, math.pow( 2, n )
end

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

function WFCatFormatterUtils.formatNumeratorDenominator( num, den, preferASCII )

	if den == 0 then

		return ""

	end

	den = math.floor( den + 0.5 )
	num = math.floor( num + 0.5 )

	return { 'formattedFraction', num, den, preferASCII }

end

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

function WFCatFormatterUtils.localizedFractionalSeconds( val, preferASCII )

	local numerator, denominator = WFCatFormatterUtils.extractNumeratorDenominator( val )
	
	if numerator then

		local fractionString = 0
		
		if numerator > denominator then
			fractionString = KSStringUtils.numberToString( numerator/denominator, 1 )
		else
			fractionString = WFCatFormatterUtils.formatNumeratorDenominator( numerator, denominator, preferASCII )
		end
		
		return 'ZSTR', "$$$/AgMetadataFormatter/NumSecondsTemplate=^1 sec", fractionString

	end

end

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

function WFCatFormatterUtils.convertAPEXToShutterSpeed( shutterSpeedVal, preferASCII )

	local numResult = 0

	if type( shutterSpeedVal ) == "number" then

		numResult = shutterSpeedVal

	else

		local denominator = shutterSpeedVal[ 2 ]

		if denominator ~= 0 then
			numResult = WFCatFormatterUtils.convertToNumericValue( shutterSpeedVal ) or 0
		else
			return ""
		end

	end

	local result = ""

	if numResult < 1 and numResult > 0 then

		numResult = math.pow( 2 , -numResult )
		local decimalValue = getDecimalBasedDisplayValue( numResult )
		result = { "number", decimalValue, 1 }
		return 'ZSTR', "$$$/AgMetadataFormatter/NumSecondsTemplate=^1 sec", result
		
	elseif numResult < 0 then
	
		numResult = math.pow( 2 , -numResult )
		result = { "number", numResult, 1 }
		return 'ZSTR', "$$$/AgMetadataFormatter/NumSecondsTemplate=^1 sec", result
		
	else

		local n, d = apexToNumDenom( numResult )
		local decimalValue = getDecimalBasedDisplayValue( n / d )

		if decimalValue then
			result = { "number", decimalValue, 1 }
			return 'ZSTR', "$$$/AgMetadataFormatter/NumSecondsTemplate=^1 sec", result
		else
			numResult = math.pow( 2, numResult )
			return WFCatFormatterUtils.localizedFractionalSeconds( { 1, numResult }, preferASCII )
		end

	end

end

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

function WFCatFormatterUtils.formatFocalLengthValue( val, optPrecision )

	if val then

		local focalLength = WFCatFormatterUtils.convertToNumericValue( val ) or 0
				
		if optPrecision then
		
			local focalLengthFormat = { 'number', focalLength, optPrecision, true }
			
			return 'ZSTR', "$$$/AgLibrary/Exif/FocalLengthTemplate=^1 mm", focalLengthFormat
			
		else
		
			-- match formatting of focal length string generation implemented in
			-- cr_sdk's cr_exif::MakeFocalLengthStringForUX()
			--
			-- ~ to truncate any value >= 20 to an integer, and show once place of precision
			-- for anything else.
			
			local roundedFocalLength = math.floor(focalLength >= 0.0 and focalLength + 0.5 or focalLength - 0.5)
	
			if focalLength == 0 then
	
				return 'ZSTR', "$$$/AgLibrary/Exif/FocalLengthTemplate=^1 mm", "0"
	
			elseif roundedFocalLength >= 20 then
						
				local focalLengthFormat = { 'number', roundedFocalLength, 0, true }
	
				return 'ZSTR', "$$$/AgLibrary/Exif/FocalLengthTemplate=^1 mm", focalLengthFormat
			
			else
	
				local focalLengthFormat = { 'number', focalLength, 1, true }
	
				return 'ZSTR', "$$$/AgLibrary/Exif/FocalLengthTemplate=^1 mm", focalLengthFormat
	
			end
		end
	end
end

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

local kSwapOrientations = {
	AD = true,
	DA = true,
	BC = true,
	CB = true,
}

function WFCatFormatterUtils.formatDimensions( width, height, orientation )

	if width and height then

		if orientation and kSwapOrientations[ orientation ] then
			width, height = height, width
		end
	
		return 'ZSTR', "$$$/AgLibrary/Exif/DimensionsTemplate=^1 x ^2",
							tostring( width ), tostring( height )

	end

end

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

function WFCatFormatterUtils.formatISOSpeedRating( value )

	if value then
	
		return 'ZSTR', "$$$/AgMetadataFormatters/exif/ISOSpeedRating=ISO ^1", { 'number', value, 0 }
	
	end

end

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

function WFCatFormatterUtils.newSuite( formatters )
	
	local function add( f )
		if f.ids then
			for _, id in ipairs( f.ids ) do
				local copy = KSTableUtils.shallowcopy( f )
				copy.ids = nil
				copy.id = id
				add( copy )
			end
		else
			formatters[ #formatters + 1 ] = f
		end
	end
	
	
	local function unused( id )
		formatters[ #formatters + 1 ] = {
			id = id,
		}
	end
	
	return formatters, add, unused
	
end

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

return WFCatFormatterUtils
