This module provides various function to be used in Chess templates. The functions can be called with {{#invoke:Chess|functionname|arguments}}.


local p = {};

local function pagename2pgn()
	local pagename = mw.title.getCurrentTitle().text
	if pagename:sub(1, 23) == "Chess Opening Theory/1." then
		return pagename:sub(22):gsub("/", " "):gsub("[0-9]+%.%.%.", "")
	else
		return ''
	end
end

function p.pagename2pgn( frame )
	local pgn = frame.args[1] or ''
	if pgn == '' then
		pgn = pagename2pgn()
	end
	local enc = mw.uri.encode( pgn )
	return string.format( '[https://lichess.org/analysis/pgn/%s %s]', enc, pgn )
end

-- Determines whether it's White's or Black's turn. Returns ' w' if arg contains
-- three dots, ' b' if arg contains one dot, or '' otherwise.
local function whoseTurn( subpagename )
	local _, count = subpagename:gsub( "%.", "" )
	if count == 3 then
		return " w"  -- White
	elseif count == 1 then
		return " b"  -- Black
	else
		return ""
	end
end

-- From [[w:Module:Chessboard]].
-- Generates "rnbqkbnr/pppp1ppp/8/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R b" if args = 
-- {'rd','nd','bd','qd','kd','bd','nd','rd',
--  'pd','pd','pd','pd','  ','pd','pd','pd',
--  '  ','  ','  ','  ','  ','  ','  ','  ',
--  '  ','  ','  ','  ','pd','  ','  ','  ',
--  '  ','  ','  ','  ','pl','  ','  ','  ',
--  '  ','  ','  ','  ','  ','nl','  ','  ',
--  'pl','pl','pl','pl','  ','pl','pl','pl',
--  'rl','nl','bl','ql','kl','bl','  ','rl',}
local function convertArgsToFen( args, offset )
	local function nullOrWhitespace( s ) return not s or s:match( '^%s*(.-)%s*$' ) == '' end
	local function piece( s )
		return nullOrWhitespace( s ) and 1
		or s:gsub( '%s*(%a)(%a)%s*', function( a, b ) return b == 'l' and a:upper() or a end )
	end

	local res = ''
	for row = 1, 8 do
		for file = 1, 8 do
			res = res .. piece( args[ 8*(row-1) + file + offset ] )
		end
		if row < 8 then res = res .. '/' end
	end
	res = mw.ustring.gsub( res, '1+', function( s ) return #s end )
	return res .. whoseTurn( mw.title.getCurrentTitle().subpageText )
end

-- From [[w:Module:Chessboard]].
-- Inverse function of convertArgsToFen
function convertFenToArgs( fen )
	-- converts FEN notation to 64 entry array of positions, offset by 2
	local res = { ' ', ' ' }
	-- Loop over rows, which are delimited by /
	for srow in string.gmatch( "/" .. fen, "/%w+" ) do
		-- Loop over all letters and numbers in the row
		for piece in srow:gmatch( "%w" ) do
			if piece:match( "%d" ) then -- if a digit
				for k=1,piece do
					table.insert(res,' ')
				end
			else -- not a digit
				local color = piece:match( '%u' ) and 'l' or 'd'
				piece = piece:lower()
				table.insert( res, piece .. color )
			end
		end
	end

	return res
end

function p.ascii2fen( frame )
	local pargs = frame:getParent().args
	local fen
	if pargs[3] then
		fen = convertArgsToFen( pargs, 2 )
	else
		local moves = require('Module:Pgn2fen').pgn2fen( pagename2pgn() )
		fen = moves[#moves]
	end
	local enc = mw.uri.encode( fen, 'WIKI' )
	return string.format('[https://lichess.org/analysis/standard/%s#explorer %s]', enc, fen)
end

function p.board( frame )
	local pargs = frame:getParent().args
	if pargs[3] then
		return frame:expandTemplate{ title='Chess diagram', args=pargs }
	else
		local moves = require('Module:Pgn2fen').pgn2fen( pagename2pgn() )
		local fen = moves[#moves]
		if fen and fen ~= '' then
			return frame:expandTemplate{ title='Chess diagram', args=convertFenToArgs(fen) }
		end
	end
end

return p