local taxo = {}

local datafile = mw.loadData('Module:Taxonomy/data')
local korean_rank_name = datafile.korean_rank_name
local taxobox_colormap = datafile.taxobox_color

local major_rank = {regnum = true, phylum = true, divisio = true, classis = true, ordo = true, familia = true, genus = true, species = true}
local minor_rank = {regio = true, subregnum = true, superdivisio = true, superphylum = ture, subdivisio = true, subphylum = true,
 superclassis = true, subclassis = true, superordo = true, subordo = true, superfamilia = true, subfamilia = true }
local italic_rank = {genus = true, subgenus = true, sectio = true, species = true, subspecies = true}
local infraspecific_rank = {species = true, subspecies = true, varietas = true, subvarietas = true, forma = true, subforma = true}

local function loadtaxon(taxon)
 local taxoninfo = {}
 taxoninfo.key = taxon
 local page = mw.title.makeTitle
 if page == nil then
 return nil
 end
 local text = page:getContent
 if text == nil then
 return nil
 end

 for line in mw.text.gsplit do
 local key, value = mw.ustring.match(line, '|([^=]+)=(.+)')
 if key and value then
 key = mw.text.trim(key) -- remove white space
 key = key:gsub
 value = value:gsub
 value = mw.text.trim(value) -- remove comment and white space
 if key ~= '' and value ~= '' then
 taxoninfo[key] = value
 end
 end
 end
 
 if taxoninfo.same_as then
 local taxoninfo2 = loadtaxon(taxoninfo.same_as)
 if taxoninfo2 then
 for k, v in pairs(taxoninfo2) do
 taxoninfo[k] = taxoninfo[k] or v -- overloading info2
 end
 end
 end

 -- if taxon is not given, load from info data
 taxoninfo.taxon = taxoninfo.taxon or taxoninfo.key

 -- split link target and display name
 if taxoninfo.link then
 local v1, v2 = taxoninfo.link:match('(.*)|(.*)')
 if v1 and v2 then
 taxoninfo.link = mw.text.trim(v1)
 taxoninfo.name = mw.text.trim(v2)
 end
 end

 if taxoninfo.always_display or major_rank[taxoninfo.rank] then
 taxoninfo.always_display = 'yes'
 end

 if taxoninfo.extinct then taxoninfo.extinct = 'yes' end

 if taxoninfo.parent then
 return taxoninfo
 else
 return nil
 end
end

local function loadtaxainfo(taxon)
 taxon = mw.text.trim(taxon)
 local taxainfo = {}
 taxainfo.key = {}
 taxainfo.list = {}
 taxainfo.rank = {}
 while true do
 local taxoninfo = loadtaxon(taxon)
 if taxoninfo then
 taxainfo.key[taxoninfo.key] = taxoninfo
 table.insert
 if not taxainfo.rank[taxoninfo.rank] then
 taxainfo.rank[taxoninfo.rank] = taxoninfo.key
 end

 taxon = taxoninfo.parent
 else
 return taxainfo
 end
 end
end

local function koreanrank(rank)
 if korean_rank_name[rank] then
 return korean_rank_name[rank]
 elseif rank:sub == 'unranked' then
 return '(미분류)'
 elseif rank:sub == 'informal' then
 return '(비공식)'
 else
 return "''" .. rank .. "''"
 end
end

local function taxobox_colour(taxainfo)
 if taxobox_colormap[taxainfo.rank.regnum] then
 return taxobox_colormap[taxainfo.rank.regnum]
 elseif taxobox_colormap[taxainfo.rank.unranked_regnum] then
 return taxobox_colormap[taxainfo.rank.unranked_regnum]
 elseif taxobox_colormap[taxainfo.rank.regio] then
 return taxobox_colormap[taxainfo.rank.regio]
 elseif taxainfo.rank.regio then
 return taxobox_colormap.default
 else
 return 'transparent; text-align:center; border: 1px solid red;'
 end
end

local function get_link(taxoninfo)
 local extinct = ''
 
 if taxoninfo.extinct then
 extinct = ''
 end

 if taxoninfo.link then
 if taxoninfo.name or taxoninfo.extinct then
 local displayname = taxoninfo.name or taxoninfo.link
 return string.format
 else
 return string.format
 end
 else
 return extinct .. taxoninfo.taxon
 end
end

local function italic_name(taxoninfo)
 if taxoninfo.rank == 'genus' or taxoninfo.rank == 'subgenus' or taxoninfo.rank == 'sectio' then
 return ''
 elseif taxoninfo.rank == 'species' then
 local genus, species = taxoninfo.taxon:match('(.*) (.*)')
 if genus and species then
 return string.format('', genus:sub, species)
 end
 elseif infraspecific_rank[taxoninfo.rank] then
 local genus, species, connecting, infraspecific = taxoninfo.taxon:match('(.*) (.*) (.*) (.*)') -- 식물 분류명 시도
 if genus and species and connecting and infraspecific then
 return string.format('', genus:sub, species:sub, connecting, infraspecific)
 end
 local genus, species, subspecies = taxoninfo.taxon:match('(.*) (.*) (.*)')
 if genus and species and subspecies then
 return string.format('', genus:sub, species:sub, subspecies)
 end
 end
 return taxoninfo.taxon
end

-- emulate en:Template:Taxonomy links

local function taxonomy_links(taxoninfo)
 if taxoninfo.rank then
 local display_taxon = italic_name(taxoninfo)

 local edit_taxon = string.format
 
 return string.format([==[
]==], koreanrank(taxoninfo.rank), taxoninfo.rank, get_link(taxoninfo), edit_taxon)
 end
end

-- emulate en:Template:Taxonomy lists
local function taxonomy_lists(taxainfo)
 
 local t = {}
 for i = #taxainfo.list, 1, -1 do
 table.insert(t, taxonomy_links(taxainfo.list[i]))
 end
 return table.concat(t)
end

-- emulate en:Template:Taxonomy key
local function taxonomy_key(taxainfo)
 local taxoninfo = taxainfo.list[1]

 local taxa_header = string.format([==[
]==], taxobox_colour(taxainfo))
 local taxa_footer = '|}\n'
 local taxa_list = taxa_header .. taxonomy_lists(taxainfo) .. taxa_footer
 
 -- child taxa 기능 추가
 local display_link
 if taxoninfo.link then
 if taxoninfo.name or taxoninfo.extinct then
 display_link = '' .. taxoninfo.link .. '|'
 if taxoninfo.extinct then
 display_link = display_link .. '&dagger;'
 end
 display_link = display_link .. (taxoninfo.name or taxoninfo.link)
 if taxoninfo.uncertain then
 display_link = display_link .. ' (?)'
 end
 display_link = display_link .. ''
 else
 display_link = '' .. taxoninfo.link .. ''
 end
 else
 display_link = taxoninfo.taxon or '??'
 end
 
 local taxa_body = string.format([==[
]==],
 taxoninfo.parent, taxoninfo.parent,
 taxoninfo.rank, koreanrank(taxoninfo.rank),
 display_link,
 taxoninfo.extinct and 'Yes' or 'no',
 taxoninfo.authority or '',
 taxoninfo.always_display and 'Yes' or 'no',
 major_rank[taxoninfo.rank] and '(기본 계급)' or (taxoninfo.always_display and '(수동 설정)' or ''),
 taxoninfo.refs or '')
 return taxa_list .. taxa_body
end

-- emulate en:Taxobox/taxonomy 
local function taxobox_taxonomy
 local t = {}
 for i = #taxainfo.list, 1, -1 do
 local taxoninfo = taxainfo.list[i]
 local authority, latinname
 if (i <= display_taxa._depth) or taxoninfo.always_display
 or (i <= 5 and minor_rank[taxoninfo.rank] and taxoninfo.link)
 or display_taxa[taxoninfo.rank] or display_taxa[taxoninfo.taxon] then
 if i <= display_authority._depth or display_authority[taxoninfo.rank] or display_authority[taxoninfo.taxon] then
 authority = taxoninfo.authority
 end
 if taxoninfo.link and (i <= display_latin._depth or display_latin[taxoninfo.rank] or display_latin[taxoninfo.taxon]) then
 latinname = '(' .. italic_name(taxoninfo) .. ')'
 end

 if authority then
 authority = ''
 end

 local display_link

 if taxoninfo.link then
 if taxoninfo.name or taxoninfo.extinct then
 display_link = ''
 if taxoninfo.extinct then
 display_link = display_link .. '&dagger;'
 end
 display_link = display_link .. (taxoninfo.name or taxoninfo.link)
 if taxoninfo.uncertain then
 display_link = display_link .. ' (?)'
 end
 display_link = display_link .. ''
 else
 display_link = '' .. taxoninfo.link .. ''
 end
 else
 display_link = taxoninfo.taxon
 end
 table.insert(t, string.format([==[
]==],
 koreanrank(taxoninfo.rank),
 taxoninfo.rank,
 display_link,
 latinname or '',
 authority or ''
 ))
 end -- if taxoninfo.always_display
 end -- for
 return table.concat(t)
end

--[[
function taxo.taxonomy_list(frame)
 local taxon = frame.args[1]
 local taxa = loadtaxainfo(taxon)
 return taxonomy_lists(taxa)
end
]]

function split_comma(str)
 local result = {}
 
 result._depth = 0
 if type(str) ~= 'string' then
 return result
 end

 for segment in mw.text.gsplit do
 if tonumber(segment) then
 result._depth = tonumber(segment)
 else
 result[mw.text.trim(segment)] = true
 end
 end
 return result
end
 
function taxo.taxobox_taxonomy(frame)
 local args = frame.args
 local taxon = args.taxon
 local display_taxa = split_comma(args.display_taxa)
 local display_authority = split_comma(args.display_authority)
 local display_latin = split_comma(args.display_latin)
 local taxa = loadtaxainfo(taxon)
 
 if display_taxa._depth < 1 then
 display_taxa._depth = 1
 end

 return taxobox_taxonomy
end

function taxo.taxobox_colour(frame)
 local taxon = frame.args[1]
 local taxa = loadtaxainfo(taxon)
 return taxobox_colour(taxa)
end

function taxo.taxonomy_key(frame)
 local taxon = frame.args[1]
 local taxa = loadtaxainfo(taxon)
 
 local refs = frame.args.refs -- quick hack
 if refs then
 taxa.list[1].refs = refs
 end

 return taxonomy_key(taxa)
end