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

WFCatImportMetadata.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 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.

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

	-- WF.oz_client.managedCatalog.metadata
local WFCatMetadataSchema = require 'WFCatMetadataSchema'

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

local sf = string.find
local ssub = string.sub

local WFCatImportMetadata = {}

--------------------------------------------------------------------------------
-- @mark Converters
--------------------------------------------------------------------------------

local function textConverter( fieldInfo, value )

	if type( value ) == 'string' then
		return value
	end

end

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

local function rationalConverter( fieldInfo, value )
	if type( value ) ~= 'string' then
		return
	end
	local _, _, num, den = sf( value, "(%--%d+)/(%--%d+)" )
	num = num and tonumber( num )
	den = den and tonumber( den )
	if ( not num ) or ( not den ) then
		return
	end
	local specialXmpToJson = fieldInfo._specialXmpToJson
	if type( specialXmpToJson ) == 'table' then
		local specialValue = specialXmpToJson[ num ]
		if specialValue then
			return specialValue
		end
	end
	if num == 0 then
		return { 0, 1 }
	end
	if den == 0 then
		return
	end
	if den < 0 then
		den = - den
		num = - num
	end
	return { num, den }
end

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

local fixW3DateTime = function( date )
	if date == "" then
		return
	end
	return date
end

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

local function dateConverter( fieldInfo, value )
	if type( value ) == 'string' then
		return fixW3DateTime( value )
	end
end

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

local function booleanConverter( fieldInfo, value )
	if type( value ) == "string" then
		return nil == sf( value, "[Ff0]" )
	end
end

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

local function enumConverter( fieldInfo, value )
	local values = fieldInfo._valuesXmpToJson or {}
	local k = tonumber( value )
	local enumvalue = values[ k ]
	if enumvalue then
		return enumvalue
	end
end

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

local function nilConverter( fieldInfo, value )
	-- Unknown types get dropped.
end

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

local function passThruConverter( fieldInfo, value )
	return value
end

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

local function integerConverter( fieldInfo, value )
	local num = tonumber( value )
	if type( num ) == 'number' then
		return math.floor( num + 0.5 )
	end
end

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

local sConverters = {
	text = textConverter,
	rational = rationalConverter,
	date = dateConverter,
	enum = enumConverter,
	boolean = booleanConverter,
	passThru = passThruConverter,
	integer = integerConverter,
}

--------------------------------------------------------------------------------
-- @mark Extractors
--------------------------------------------------------------------------------

local function valueExtractor( defaultNamespace, defaultFieldName, fieldInfo, metadata )
	local namespace = fieldInfo._namespace or defaultNamespace
	local fieldName = fieldInfo._fieldName or defaultFieldName
	return metadata:get( namespace, fieldName )
end

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

local function fieldExtractor( defaultNamespace, defaultFieldName, parentFieldInfo, metadata )

	local namespace = parentFieldInfo._namespace or defaultNamespace
	local fieldName = parentFieldInfo._fieldName or defaultFieldName
	local subFieldName = parentFieldInfo._xmpSubfield
	local dataType = parentFieldInfo._type

	local converter = sConverters[ dataType ] or nilConverter

	return converter(
		parentFieldInfo,
		metadata:getStruct(
			namespace,
			fieldName,
			namespace, -- Using the same NS as the parent
			subFieldName
		)
	)

end

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

local function firstArrayElementExtractor(
			defaultNamespace,
			defaultFieldName,
			fieldInfo,
			metadata )

	local namespace = fieldInfo._namespace or defaultNamespace
	local fieldName = fieldInfo._fieldName or defaultFieldName
	local index = 1

	local list = metadata:getStringList( namespace, fieldName )

	if list and list[ index ] ~= nil then
		return list[ index ]
	end

end

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

local function stringListExtractor( defaultNamespace, defaultFieldName, fieldInfo, metadata )

	local namespace = fieldInfo._namespace or defaultNamespace
	local fieldName = fieldInfo._fieldName or defaultFieldName

	local list = metadata:getStringList( namespace, fieldName )

	if type( list ) == 'table' then
		return list
	end

end

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

local function stringBagExtractor( defaultNamespace, defaultFieldName, fieldInfo, metadata )

	local namespace = fieldInfo._namespace or defaultNamespace
	local fieldName = fieldInfo._fieldName or defaultFieldName

	local list = metadata:getStringList( namespace, fieldName )

	if type( list ) == 'table' then
		local bag = {}
		for _, v in ipairs( list ) do
			if string.len( v ) > 0 then
				bag[ v ] = true
			end
		end
		return next( bag ) and bag or nil -- don't return an empty table
	end

end

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

local function altLangDefaultExtractor(
			defaultNamespace,
			defaultFieldName,
			fieldInfo,
			metadata )

	local namespace = fieldInfo._namespace or defaultNamespace
	local fieldName = fieldInfo._fieldName or defaultFieldName
	return metadata:getLocalizedText( namespace, fieldName )

end

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

local sExtractors = {
	field = fieldExtractor,
	value = valueExtractor,
	firstArrayElement = firstArrayElementExtractor,
	stringList = stringListExtractor,
	stringBag = stringBagExtractor,
	altLangDefault = altLangDefaultExtractor,
}

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

local function extractFieldsInSection( output, metadata, nsPrefix, section )

	local defaultNamespace = section._namespace
	for fieldName, fieldInfo in pairs( section ) do
		if ssub( fieldName, 1, 1 ) ~= '_' then
			local dataType
			local dataStructure = 'value'
			if type( fieldInfo ) == 'string' then
				dataType = fieldInfo
				fieldInfo = { _type = dataType }
			else
				dataType = fieldInfo._type
			end
			local xmpField = fieldInfo._xmpField or fieldName
			local xmpSubfield = fieldInfo._xmpSubfield
			if xmpSubfield then
				dataStructure = 'field'
				dataType = 'passThru'
			end
			if dataType == 'stringList' then
				dataStructure = 'stringList'
				dataType = 'passThru'
			end
			if dataType == 'stringBag' then
				dataStructure = 'stringBag'
				dataType = 'passThru'
			end
			if dataType == 'firstArrayElementAsInteger' then
				dataStructure = 'firstArrayElement'
				dataType = 'integer'
			end
			if dataType == 'altLangDefault' then
				dataStructure = 'altLangDefault'
				dataType = 'passThru'
			end
			
			local metadataFieldName = xmpField
			local namespace = fieldInfo._namespace or defaultNamespace
			local converter = sConverters[ dataType ] or nilConverter
			local extractor = sExtractors[ dataStructure ]
			output[ fieldName ] = converter( fieldInfo, extractor( namespace, metadataFieldName, fieldInfo, metadata ) )
		end
	end

end

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

local function extractFieldsAccordingToSchema( metadata, schema )
	
	local xmp = {}
	
	for nsPrefix, section in pairs( schema ) do
		
		if ssub( nsPrefix, 1, 1 ) ~= '_' then
			local subdoc = xmp[ nsPrefix ]
			if not subdoc then
				subdoc = {}
			end
			extractFieldsInSection( subdoc, metadata, nsPrefix, section )
			if next( subdoc ) then
				xmp[ nsPrefix ] = subdoc
			end
		end

	end
	
	return xmp

end

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

function WFCatImportMetadata.convertXmpInfo( metadata )

	return extractFieldsAccordingToSchema( metadata, WFCatMetadataSchema.getOzMetadataSchema() )
	
end

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

return WFCatImportMetadata



