--[=[
Implementation logic for [[Template:Article Link]]
]=]
require('strict')

local p = {} --p stands for package

local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local Error = require('Module:Error')

local function ordinal(n)
	local unit = n % 10
    local hundredth = n % 100
	local ord
	if unit == 1 and (hundredth ~= 11) then
		ord = 'st'
	elseif unit == 2 and (hundredth ~= 12) then
		ord = 'nd'
	elseif unit == 3 and (hundredth ~= 13) then
		ord = 'rd'
	else
		ord = 'th'
	end
	return n .. '<sup>' .. ord .. '</sup>'
end

local function make_link(target, disp, suppressIfTargetMissing)
	
	mw.logObject(target)
	
	if suppressIfTargetMissing then
		local targetTitle = mw.title.new( target )
		if targetTitle == nil or not targetTitle.exists then
			-- page is missing: just return the text
			return (disp or target)	
		end
	end
	
	return '[[' .. target .. '|' .. (disp or target) .. ']]'
end

local function make_article_components(args)
	local parts = { args['periodical'] }
	
	if args['series'] or args['volume'] or args['issue'] then
		-- Series/Volume/Issue layout
		if args['series'] then
			table.insert(parts, 'Series ' .. args['series'])
		end	
	
		if args['volume'] then
			table.insert(parts, 'Volume ' .. args['volume'])
		end
	
		if args['issue'] then
			local rank = ''
			if args['issue_rank'] ~= 'blank' then
				rank = (args['issue_rank'] or 'Issue') .. ' ' 
			end
			table.insert(parts, rank .. args['issue'])
		end
	else
		table.insert(parts, args['year'])

		if args['month'] then
			table.insert(parts, string.format("%02d", args['month']))
		end

		if args['day'] then
			table.insert(parts, string.format("%02d", args['day']))
		end
	end

	return parts
end

local function make_date_str(args)
	
	local dstamp = os.time({
		year = args['year'],
		month = args['month'] or 1,
		day = args['day'] or 1
	})
	
	local out = ''
	if args['day'] then
		out = out .. ordinal(args['day']) .. ' '
	end
	
	if args['month'] then
		out = out .. os.date('%B', dstamp) .. ', '
	end

	if args['year'] then
		out = out .. args['year'] 
	end
	
	return out
end

local function make_span(class, content)
	local span = mw.html.create('span')
		:addClass(class)
		:wikitext(content)
		
	return tostring(span)	
end

local function make_article_link_output(args, frame)
	local parts = make_article_components(args)
	local out = ''
	local in_copyright = false
	
	-- checking copyright status
	if args['copyright_until'] then
		local copyright_until = tonumber(args['copyright_until'])
		if copyright_until == nil then
			return Error.error({"The 'copyright_until' argument must be integer."})
		end
		local current_year = tonumber(os.date("%Y"))
		if current_year < copyright_until then
			in_copyright = true
		end
	end
	
	-- link to the article
	if args['direct_link'] then
		-- assume nothing and just output the link
		out = out .. args['direct_link']
	elseif args['no_link'] or in_copyright then
		-- if the article link is suppressed (e.g. a non-PD article but still
		-- in a portal or author listing because it has a valid (legal) off-wiki link
		out = out .. '"' .. args['article'] .. '"'
	else
		local art_page = args['link'] or args['article']
		
		-- drop the issue if it doesn't feature in an article link
		-- (note: it could still exist as a sibling to the articles)
		if not yesno(args['issue_in_title']) then
			mw.log("dropping issue from article")
			table.remove(parts)
		end
		
		local target = table.concat(parts, '/') .. '/' .. art_page
		out = out .. '"' .. make_link(target, args['article']) .. '"'
	end

	local authors = {}
	if args['author'] then
		table.insert(authors, args['author'])
		out = out .. ' by ' .. make_span('wst-artlink-author', args['author'])
	elseif args['author1'] then
		-- At least one author is given, so loop to find all of them.
		local i = 0
		while true do
			i = i + 1
			local authorX = args['author' .. i]
			if not authorX then break end
			local displayX = args['author' .. i .. '-display']
			if not displayX then
				displayX = authorX
			end
			table.insert(authors, {link = authorX, display = displayX})
		end
		if #authors >= 1 then
			out = out .. ' by '
			for i, author in ipairs(authors) do
				local linkedAuthor = '[[Author:' .. author.link .. '|' .. author.display .. ']]'
				out = out .. make_span('wst-artlink-author', linkedAuthor)
				if i == #authors then
					out = out .. '.'
				elseif i == #authors - 1 then
					if #authors == 2 then
						out = out .. ' and '
					else
						out = out .. ', and '
					end
				else
					out = out .. ', '
				end
			end
		end
	end

	if args['coauthor'] and not args['author1'] then
		if args['author'] then
			out = out .. ','
		end
		out = out .. ' with ' .. make_span('wst-artlink-coauthor', args['coauthor'])
	end
	
	local date_str
	
	if args['override_date'] then
		date_str = args['override_date']
		-- override dates can still have the year, optionally
		if args['year'] then
			date_str = date_str .. ', ' .. args['year']
		end
	else
		-- assume YYYY, YYYY-MM or YYYY-MM-DD
		if args['year'] then
			date_str = make_date_str(args)
		end
	end
	
	out = out .. ' in ' .. make_span('wst-artlink-periodical',
		make_link(args['periodical'], args['display_periodical'])
	)
	
	local parts = make_article_components(args)

	if args['series'] or args['volume'] or args['issue'] then
		local num_comps = 1
		if args['series'] then
			num_comps = num_comps + 1
			local ser_target = table.concat(parts, '/', 1, num_comps )
			local ser_link = make_link(ser_target, 'Series ' .. args['series'], true)
			out = out .. ', ' .. make_span('wst-artlink-midlevel wst-artlink-series', ser_link)
		end
		
		if args['volume'] then
			num_comps = num_comps + 1
			local vol_target = table.concat(parts, '/', 1, num_comps )
			local vol_link =  make_link(vol_target,  args['volume'], true)
			out = out .. ', ' .. make_span('wst-artlink-midlevel wst-artlink-volnum', vol_link)
		end
		
		if args['issue'] then
			if args['issue_in_title'] then
				num_comps = num_comps + 1
			end
			local text = ''
			if yesno(args['issue_link']) then
				local iss_target = table.concat(parts, '/', 1, num_comps )
				text = make_link(iss_target, args['issue'], true)
			else
				text = args['issue']
			end
			out = out .. ' ' .. '(' .. make_span('wst-artlink-midlevel wst-artlink-issnum', text) .. ')'
		end
		
		if date_str then
			out = out .. ' (' .. make_span('wst-artlink-date', date_str) .. ')'
		end
	else
		-- date style
		if date_str then
			local target = table.concat(parts, '/', 1, #parts)
			local date_link = make_link(target, date_str, true)
			out = out .. ', ' .. make_span('wst-artlink-midlevel wst-artlink-date', date_link)
		end
	end
	
	if args['section'] then
		out = out .. ', in section "' .. make_span('wst-artlink-section', args['section']) .. '"'
	end
	
	-- pages
	if args['p'] then
		if args['pp'] then
			out = out .. ', pp.&nbsp;' .. args['p'] .. '–' .. args['pp']
		else
			out = out .. ', p.&nbsp;' .. args['p']
		end
	end
	
	if args['editor'] then
		if args['author'] or args['coauthor'] then
			out = out .. ', ed. '
		else
			out = out .. ' Ed. '
		end
		
		out = out .. make_span('wst-artlink-editor', args['editor'])
	end
	
	-- append copyright expiration notice
	if in_copyright then
		out = out .. ' — Copyrighted in the United States until ' .. args['copyright_until']
		if args['renewal'] then
			local renewal = args['renewal']
			if string.len(renewal) == 12 then
				renewal = frame:expandTemplate{ title = 'CO Copyright renewal', args = { renewal } }
			else
				renewal = frame:expandTemplate{ title = 'Copyright renewal', args = { renewal } }
			end
			out = out .. ' due to ' .. renewal
		end
	end
	
	return make_span('wst-artlink', out)
end

--[=[
Construct the link from arguments
]=]
function p.article_link(frame)
	local args = getArgs(frame)
	
	-- check parameters
	if args.periodical == nil then
		return Error.error({"The 'periodical' argument must be given."})
	end
	if args.article == nil and args.direct_link == nil then
		return Error.error({"One of the arguments 'article' or 'direct_link' must be given."})
	end
	
	-- set defaults
	if args.issue_in_title == nil then
		args.issue_in_title = true
	end
	
	if args.issue_link == nil then
		args.issue_link = true
	end
	
	-- number sets issue and issue_rank
	if args.number ~= nil then
		args.issue_rank = "Number"
		args.issue = args.number
	end
	
	return make_article_link_output(args, frame)
end

return p