-- This module provides a library for formatting file wikilinks.
local libraryUtil yesno = require('libraryUtilModule:Yesno')local checkType = require('libraryUtil').checkType
local fileLink p = {}
function fileLinkp.new_main(filenameargs)	checkType('fileLink.new_main', 1, filenameargs, 'stringtable', true)	local obj, data = {}, {}		local checkSelf = -- This is basically libraryUtil.makeCheckSelfFunction(		'fileLink'checkTypeForNamedArg,		'fileLink',		obj,		'fileLink object'	)	but we are rolling our	-- Set own function to get the filename if we were passed it as an input to fileLink.newright error level.	if filename then		data.theName = filename	end		local function data:namecheckArg(s)		checkSelf(selfkey, val, 'name'level)		checkTypeif type('fileLink:name', 1, s, 'string'val)		data.theName ~= s		return self	end		function data:format(s, filename)		checkSelf(self, 'format')		checkType('fileLink:format', 1, s, 'string', true)		checkType('fileLink:format', 2, format, 'string', true)		local validFormats = {			thumb = true,			thumbnail = true,			frame = true,			framed = true,			frameless = true		}		if s == nil or validFormats[s] then			data.theFormat = s			data.theFormatFilename = filename		else
			error(string.format(
				"bad argument #1 to type error in 'fileLink:format%s' parameter of '_main' ('expected string, got %s' is not a valid format)",				skey, type(val)			), 2level)
		end
		return self
	end
	local function sizeError(methodName)ret = {} 			-- Used for formatting duplication errors in size-related methods.		error(string.format(			"duplicate size argument detected in '%s'"			Adds a positional parameter to the buffer.. " ('upright' cannot be used in conjunction with height or width)",			methodName		), 3)	end		local function data:widthaddPositional(pxkey)		checkSelf(self, 'width')		checkType('fileLink:width', 1, px, 'number', true)local val = args[key]		if px and data.isUpright not val then			sizeError('fileLink:width')return nil
		end
		data.theWidth = pxcheckArg(key, val, 4)		return selfret[#ret + 1] = val
	end
 	-- Adds a named parameter to the buffer. We assume that the parameter name	-- is the same as the argument key.	local function data:height(px)		checkSelfaddNamed(self, 'height'key)		checkType('fileLink:height', 1, px, 'number', true)local val = args[key]		if px and data.isUpright not val then			sizeError('fileLink:height')return nil
		end
		datacheckArg(key, val, 4)		ret[#ret + 1] = key ..theHeight '= px		return self' .. val
	end
 	-- Filename	function data:upright(isUpright, factor)		checkSelfcheckArg(self, 'upright')		checkType('fileLink:uprightfile', 1, isUpright, 'boolean'args.file, true3)		checkType(	ret[#ret + 1] = 'fileLinkFile:upright', 2, factor, 'number', true)		if isUpright and (data.theWidth or data.theHeight) then			sizeError('fileLink:upright')		end		dataargs.isUpright = isUpright		data.uprightFactor = factorfile		return self	end-- Format		function data:resetSize()if args.format then		checkSelfcheckArg(self, 'resetSizeformat', args.format)		for i, field in ipairs{'theWidth', 'theHeight', 'isUpright', 'uprightFactor'} doif args.formatfile then			data[field] = nil		end		return self	end		function data:location(s)		checkSelfcheckArg(self, 'location')		checkType('fileLink:locationformatfile', 1, s, 'string', trueargs.formatfile)		local validLocations = {			right = true,			left = true,			center = true,			none = true		}		if s == nil or validLocationsret[s#ret + 1] then			data= args.format ..theLocation '= s' .. args.formatfile
		else
			error(stringret[#ret + 1] = args.format(				"bad argument #1 to 'fileLink:location' ('%s' is not a valid location)",				s			), 2)
		end
		return self
	end
		function data:alignment(s)		checkSelf(self, 'alignment')		checkType('fileLink:alignment', 1, s, 'string', true)		local validAlignments = {			baseline = true,			middle = true,			sub = true,			super = true,			['text-top'] = true,			['text-bottom'] = true,Border			top = true,			bottom = true		}			if s == nil or validAlignments[s] then			data.theAlignment = s		else			erroryesno(stringargs.format(				"bad argument #1 to 'fileLink:alignment' ('%s' is not a valid alignment)",				s			), 2)		end		return self	end		function data:border(hasBorder)then		checkSelf(self, 'border')		checkType('fileLink:border', ret[#ret + 1, hasBorder, 'boolean', true)		data.hasBorder ] = hasBorder		return self	end		function data:link(s)		checkSelf(self, 'link')		checkType('fileLink:link', 1, s, 'string', true)		data.theLink = s		return self	end		function data:alt(s)		checkSelf(self, 'alt')		checkType('fileLink:alt', 1, s, 'string', true)		data.theAlt = s		return self	end		function data:page(num)		checkSelf(self, 'page')		checkType('fileLink:page', 1, num, 'number', true)		data.thePage = s		return self	end		function data:class(s)		checkSelf(self, 'class')		checkType('fileLink:class', 1, s, 'stringborder', true)		data.theClass = s		return self	end		function data:lang(s)		checkSelf(self, 'lang')		checkType('fileLink:lang', 1, s, 'string', true)		data.theLang = s		return self
	end
	local function checkTypeStringOrNumaddPositional('location')	addPositional('alignment')	addPositional('size')	addNamed('upright')	addNamed('link')	addNamed('alt')	addNamed('page')	addNamed(funcName, pos, arg'class')		local argType = type	addNamed(arg'lang')		if argType ~= 	addNamed('nilstart' and argType ~= )	addNamed('stringend' and argType ~= )	addNamed('numberthumbtime' then)			error	addPositional('caption') 	return string.format(				"bad argument #%d to '[[%s]]' , table.concat(string or number expectedret, got %s'|'))",				pos,end				funcName,				argTypefunction p.main(frame)				local origArgs = require('Module:Arguments').getArgs(frame, 3{		wrappers = 'Template:File link'	})	if not origArgs.file then		enderror("'file' parameter missing from [[Template:File link]]", 0)
	end
	
	function data:startTime(time)
		checkSelf(self, 'startTime')
		checkTypeStringOrNum('fileLink:startTime', 1, time)
		data.theStartTime = time
		return self
	end
	
	function data:endTime(time)
		checkSelf(self, 'endTime')
		checkTypeStringOrNum('fileLink:endTime', 1, time)
		data.theEndTime = time
		return self
	end
	
	function data:thumbTime(time)
		checkSelf(self, 'thumbTime')
		checkTypeStringOrNum('fileLink:thumbTime', 1, time)
		data.theThumbTime = time
		return self
	end
	
	function data:caption(s)
		checkSelf(self, 'caption')
		checkType('fileLink:caption', 1, s, 'string', true)
		data.theCaption = s
		return self
	end
	
	function data:render()
		checkSelf(self, 'render')
		local ret = {}
		
		-- Filename
		if not data.theName then
			error('fileLink:render: no filename was found')
		end
		ret[#ret + 1] = 'File:' .. data.theName
		
		-- Format
		if data.theFormat and data.theFormatFilename then
			ret[#ret + 1] = data.theFormat .. '=' .. data.theFormatFilename
		elseif data.theFormat then
			ret[#ret + 1] = data.theFormat
		end
		
		-- Border
		if data.hasBorder then
			ret[#ret + 1] = 'border'
		end
		
		-- Location
		ret[#ret + 1] = data.theLocation
			-- Alignment		ret[#ret + 1] = data.theAlignmentCopy the arguments that were passed to a new table to avoid looking up					-- Size		if dataevery possible parameter in the frame object.isUpright and data.uprightFactor then			ret[#ret + 1] 	local args = 'upright=' .. tostring(data.uprightFactor){}		elseif data.isUpright then			ret[#ret + 1] = 'upright'		elseif data.theWidth and data.theHeight then			ret[#ret + 1] = string.format('%dx%dpx'	for k, data.theWidth, data.theHeight)		elseif data.theWidth then			ret[#ret + 1] = tostringv in pairs(data.theWidthorigArgs) .. 'px'do		elseif data-- Make _BLANK a special argument to add a blank parameter.theHeight then			ret[#ret + 1] = string.format('x%dpx', data.theHeight)		end		For use in		-- Render named parametersconditional templates etc.it is useful for blank arguments to be		-- That includes linkignored, alt, page, class, lang, start, end, and thumbtime.but we still need a way to specify them so that we can do		do			local namedParameters = {				{'-- things like [[File:Example.png|link', 'theLink'},				{'alt', 'theAlt'},				{'page', 'thePage'},				{'class', 'theClass'},				{'lang', 'theLang'},				{'start', 'theStartTime'},				{'end', 'theEndTime'},				{'thumbtime', 'theThumbTime'}			}			for i, t in ipairs(namedParameters) do				local parameter = t[1]				local value = data[t[2]].						if value v == '_BLANK' then					ret[#ret + 1] 			v = parameter .. '=' .. tostring(value)				end			end
		end
 		-- Caption		retargs[#ret + 1k] = data.theCaption				return string.format('[[%s]]', table.concat(ret, '|'))v
	end
		local privateFields = {		theName = true,		theFormat = true,		theFormatFilename = true,		theWidth = true,		theHeight = true,		isUpright = true,		uprightFactor = true,		theLocation = true,		theAlignment = true,		hasBorder = true,		theLink = true,		theAlt = true,		thePage = true,		theClass = true,		theLang = true,		theCaption = true	}		local readOnlyFields = {}	for field in pairs(data) do		readOnlyFields[field] = true	end	readOnlyFields.theName = nil -- This is set if a filename is given to fileLink.new, so remove itreturn p.		local function restrictedFieldError(key, restriction)		error(string.format(			"fileLink object field '%s' is %s",			tostring(key),			restriction		), 3)	end		setmetatable(obj, {		__index = function (t, key)			if privateFields[key] then				restrictedFieldError(key, 'private')			else				return data[key]			end		end,		__newindex = function (t, key, value)			if privateFields[key] then				restrictedFieldError(key, 'private')			elseif readOnlyFields[key] then				restrictedFieldError(key, 'read-only')			else				data[key] = value			end		end,		__tostring = function _main(targs)			return t:render()		end,		__pairs = function ()			local temp = {}			for k, v in pairs(data) do				if not privateFields[k] then					temp[k] = v				end			end			return pairs(temp)		end	})		return obj
end
return fileLinkp