Module:ain-dial-map



local export = {}

local m_links = require("Module:links")
local m_lang = require("Module:languages")
local ain = m_lang.getByCode("ain")
local dial_data = mw.loadData("Module:ain-dial-map/data")

local radius = 0.001

local colors = {
	"d2502e", "6941c7", "9fdd42", "e7ff79", "b66063",
	"30bcff", "c6ceff", "02f291", "2e1200", "a4ff46",
	"ffcccf", "63001e", "c124de", "00ae2d", "ff4ce4",
	"6fff8b", "b900b1", "bfff6b", "0035b6", "fffe8d",
	"61008c", "adff9e", "d463ff", "3c8a00", "db0098",
	"00c97f", "a20090", "01a145", "ff5ec8", "59ffc6",
	"e50025", "01c0cc", "a60003", "02b9db", "d37200",
	"0151c6", "949900", "00156f", "ffa938", "290062",
	"b69700", "6d87ff", "c88100", "014592", "ff823e",
	"000f36", "bdffc4", "1e003b", "ffce7a", "320029",
	"d5ffea", "6a0050", "009267", "ff4c61", "019282",
	"fd98ff", "094300", "ad96ff", "965a00", "8eb0ff",
	"761f00", "9bd8ff", "490d00", "fbffe9", "1d000f",
	"feecff", "00141e", "ffddad", "001b14", "ff93ce",
	"004f23", "9d0050", "005e5e", "ffa291", "003e33",
	"ff9cac", "00536c", "ffc594", "0079b1", "5a3600",
	"ff6b6b", "4ecdc4", "f7fff7", "ffe66d", "1a535c",
	"457b9d", "a8dadc", "e63946", "f1faee", "2a9d8f",
	"e9c46a", "f4a261", "e76f51", "264653", "2b2d42",
	"8d99ae", "edf2f4", "ef233c", "d90429", "ffc8dd",
	"ffafcc", "bde0fe", "a2d2ff", "cdb4db", "ffcbf2",
	"f3c4fb", "ecbcfd", "e5dbff", "e2eAFC", "cfbaf0"
}

local symbols = {
	"circle", "star", "square", "triangle", "marker", "rocket", "shop", "school", "park", "music",
	"cemetery", "airport", "rail", "bus", "bicycle", "bar", "cafe", "town-hall", "roadblock"
}

local katakana_map = {
	['トゥ'] = 'tu', ['ドゥ'] = 'du',
	['チャ'] = 'ca', ['チュ'] = 'cu', ['チェ'] = 'ce', ['チョ'] = 'co',
	['ジャ'] = 'ja', ['ジュ'] = 'ju', ['ジェ'] = 'je', ['ジョ'] = 'jo',
	['イェ'] = 'ye',
	['ウィ'] = 'wi', ['ウェ'] = 'we', ['ウォ'] = 'wo',
	['ㇷ゚'] = 'p',
	['ッ'] = 't', ['ㇰ'] = 'k', ['ㇱ'] = 's', ['ㇺ'] = 'm',
	['ㇵ'] = 'h', ['ㇶ'] = 'h', ['ㇷ'] = 'h', ['ㇸ'] = 'h', ['ㇹ'] = 'h',
	['ㇻ'] = 'r', ['ㇼ'] = 'r', ['ㇽ'] = 'r', ['ㇾ'] = 'r', ['ㇿ'] = 'r',
	['ア'] = 'a', ['イ'] = 'i', ['ウ'] = 'u', ['エ'] = 'e', ['オ'] = 'o',
	['カ'] = 'ka', ['キ'] = 'ki', ['ク'] = 'ku', ['ケ'] = 'ke', ['コ'] = 'ko',
	['ガ'] = 'ga', ['ギ'] = 'gi', ['グ'] = 'gu', ['ゲ'] = 'ge', ['ゴ'] = 'go',
	['サ'] = 'sa', ['シ'] = 'si', ['ス'] = 'su', ['セ'] = 'se', ['ソ'] = 'so',
	['ザ'] = 'za', ['ジ'] = 'ji', ['ズ'] = 'zu', ['ゼ'] = 'ze', ['ゾ'] = 'zo',
	['タ'] = 'ta', ['チ'] = 'ci', ['テ'] = 'te', ['ト'] = 'to',
	['ダ'] = 'da', ['ヂ'] = 'di', ['デ'] = 'de', ['ド'] = 'do',
	['ナ'] = 'na', ['ニ'] = 'ni', ['ヌ'] = 'nu', ['ネ'] = 'ne', ['ノ'] = 'no',
	['ハ'] = 'ha', ['ヒ'] = 'hi', ['フ'] = 'hu', ['ヘ'] = 'he', ['ホ'] = 'ho',
	['バ'] = 'ba', ['ビ'] = 'bi', ['ブ'] = 'bu', ['ベ'] = 'be', ['ボ'] = 'bo',
	['パ'] = 'pa', ['ピ'] = 'pi', ['プ'] = 'pu', ['ペ'] = 'pe', ['ポ'] = 'po',
	['マ'] = 'ma', ['ミ'] = 'mi', ['ム'] = 'mu', ['メ'] = 'me', ['モ'] = 'mo',
	['ヤ'] = 'ya', ['ユ'] = 'yu', ['ヨ'] = 'yo',
	['ラ'] = 'ra', ['リ'] = 'ri', ['ル'] = 'ru', ['レ'] = 're', ['ロ'] = 'ro',
	['ワ'] = 'wa', ['ン'] = 'n'
}

local katakana_keys = {}
for k in pairs(katakana_map) do
	table.insert(katakana_keys, k)
end
table.sort(katakana_keys, function(a, b)
	return mw.ustring.len(a) > mw.ustring.len(b)
end)

local function katakanaToAlphabet(text)
	local first_pass_result = ""
	local i = 1
	while i <= mw.ustring.len(text) do
		local found_match = false
		for _, key in ipairs(katakana_keys) do
			local key_len = mw.ustring.len(key)
			if mw.ustring.sub(text, i, i + key_len - 1) == key then
				first_pass_result = first_pass_result .. katakana_map[key]
				i = i + key_len
				found_match = true
				break
			end
		end
		if not found_match then
			first_pass_result = first_pass_result .. mw.ustring.sub(text, i, i)
			i = i + 1
		end
	end

	local second_pass_result = ""
	local last_vowel = ""
	for char in mw.ustring.gmatch(first_pass_result, ".") do
		if char == 'ー' then
			if last_vowel ~= "" then
				second_pass_result = second_pass_result .. last_vowel
			end
		else
			second_pass_result = second_pass_result .. char
			local current_char_as_vowel = char:match("[aiueo]")
			if current_char_as_vowel then
				last_vowel = current_char_as_vowel
			end
		end
	end

	local final_result = second_pass_result
		:gsub("au", "aw")
		:gsub("iu", "iw")
		:gsub("eu", "ew")
		:gsub("ou", "ow")
		:gsub("ai", "ay")
		:gsub("ui", "uy")
		:gsub("ei", "ey")
		:gsub("oi", "oy")

	return final_result
end

local function delink(text)
	text = text:gsub("%[%[[^|%[%]]+|([^|%[%]]+)%]%]","%1")
		:gsub("%[%[([^|%[%]]+)%]%]","%1")
	return text
end

function export.make_list(data)
	return "<ul><li>" .. table.concat(data,"</li><li>") .. "</li></ul>"
end

function export.map_header(text)
	return tostring(
		mw.html.create("h2")
			:wikitext(text)
		:done()
	)
end

function export.get_coords(lat,long,i,n)
	if n > 1 then
		return {long+radius*math.cos(2*math.pi*i/n),lat+radius*math.sin(2*math.pi*i/n)}
	else
		return {long,lat}
	end
end

function export.make_point(lat,long,color,text,i,n,symbol)
	return {
		type = "Feature",
		properties = {
			title = text,
			["marker-color"] = color,
			["marker-size"] = "small",
			["marker-symbol"] = symbol,
		},
		geometry = {
			type = "Point",
			coordinates = export.get_coords(lat,long,i,n)
		}
	}
end

function export.make_polygon(text,color,points)
	local coords = {}
	for _,pt in ipairs(points) do
		table.insert(coords,{pt.long,pt.lat})
	end
	table.insert(coords,{points[1].long,points[1].lat})
	return {
		type = "Feature",
		properties = {
			title = text,
			["stroke-width"] = 0,
			["fill"] = color,
			["fill-opacity"] = 0,
		},
		geometry = {
			type = "Polygon",
			coordinates = {coords},
		}
	}
end

function export.legend(colour, show, cat, hide)
	return tostring(
		mw.html.create("div")
			:addClass("ain-dial-map__legend-row")
			:addClass((colour == grey and "ain-dial-map__legend-row-other" or nil))
			
			:tag("div")
				:addClass("vsSwitcher")
				:attr("data-toggle-category", cat)
				:attr("data-vs-showtext", "lects ▼")
				:attr("data-vs-hidetext", "lects ▲")

				:tag("span")
					:addClass("ain-dial-map__legend-row-dot")
					:css("background-color", "#" .. colour)
					:wikitext("")
				:done()
				
				:tag("span")
					:addClass("vsToggleElement")
					:wikitext("")
				:done()
				
				:wikitext(show)
				
				:tag("div")
					:addClass("vsHide")
					:wikitext(hide)
		:allDone()
	)
end

function export.make_legends(legend)
	local r = #legend%5
	local q = math.floor(#legend/5)
	local d1 = q+(r>0 and 1 or 0)
	local d2 = d1+q+(r>1 and 1 or 0)
	local d3 = d2+q+(r>2 and 1 or 0)
	local d4 = d3+q+(r>3 and 1 or 0)
	local l1 = table.concat(legend,"",1,d1)
	local l2 = table.concat(legend,"",d1+1,d2)
	local l3 = table.concat(legend,"",d2+1,d3)
	local l4 = table.concat(legend,"",d3+1,d4)
	local l5 = table.concat(legend,"",d4+1,#legend)
	local cell = {width="20%",["vertical-align"]="top"}
	return tostring(
		mw.html.create("table"):css("width","100%"):tag("tr")
			:tag("td"):css(cell):wikitext(l1):done()
			:tag("td"):css(cell):wikitext(l2):done()
			:tag("td"):css(cell):wikitext(l3):done()
			:tag("td"):css(cell):wikitext(l4):done()
			:tag("td"):css(cell):wikitext(l5):done()
		:allDone()
	)
end

function export.make_map(frame,geojson,legend)
	return tostring(
		mw.html.create("div")
			:addClass("thumb")
			:addClass("ain-dial-map__container")
			:wikitext(frame:extensionTag("mapframe",mw.text.jsonEncode(geojson),{
				class = "ain-dial-map__map",
				mapstyle = "osm-intl",
				width = 1200,
				height = 650,
				latitude = 46.5,
				longitude = 148,
				zoom = 6
			}))
			:done()

			:tag("div")
				:wikitext(legend)
			:done()
		:done()
	)
end

function export.show(frame)
	local geojson = {}
	local legend = {}
	local dial = mw.loadData("Module:dialect synonyms/ain").varieties
	local syn = mw.loadData("Module:dialect synonyms/ain/"..frame.args[1])
	
	local lects = {}
	local layer = {dial}
	while layer[1] do
		local children = {}
		for _,node in ipairs(layer) do
			if node[1] then
				for _,child in ipairs(node) do
					table.insert(children,child)
				end
			elseif node.long and syn.syns[node.name] and syn.syns[node.name][1] ~= "" then
				table.insert(lects,node)
			end
		end
		layer = children
	end
	
	local locs = {}
	local n = {}
	for _,lect in ipairs(lects) do
		local syn_lect = syn.syns[lect.name]
		n[lect.name] = 0
		local i = 0
		for _,original_form in ipairs(syn_lect) do
			local key_form = original_form:gsub(":.*", "")
			
			i = i + 1
			n[lect.name] = n[lect.name] + 1
			locs[key_form] = locs[key_form] or {}
			table.insert(locs[key_form],{lect, i, original_form})
		end
	end
	
	local forms = {}
	for form,lects in pairs(locs) do
		table.insert(forms,form)
	end
	table.sort(forms, function(a,b) return #locs[a] > #locs[b]
		or (#locs[a] == #locs[b] and a > b) end)
	
	for idx,form in ipairs(forms) do
		local color = colors[idx]
		local legend_lects = {}
		local alphabet_form = katakanaToAlphabet(form)
		local symbol_for_category = symbols[(idx - 1) % #symbols + 1]
		local link = m_links.full_link({
			lang = ain,
			term = form,
		})
		local legend_display = link .. "(" .. alphabet_form .. ")" .. " (" .. #locs[form] .. ")"

		for _,lect_i in ipairs(locs[form]) do
			local lect, i, original_form = lect_i[1], lect_i[2], lect_i[3]
			local display_word = delink(original_form)
			local display = lect.text_display .. ": <br>" .. display_word
			table.insert(geojson,export.make_point(lect.lat,lect.long,color,display,i,n[lect.name],symbol_for_category))
			table.insert(legend_lects, lect.text_display)
		end
		table.insert(legend, export.legend(color, legend_display, form, export.make_list(legend_lects)))
	end
	
	local title = syn.title and syn.title ~= "" and syn.title or frame.args[1]
	title = title:gsub("[0-9%-]", "")
	local map_header = export.map_header(
		"Map of Ainu varieties and languages for " .. m_links.full_link(
			{
				lang = ain,
				term = title,
				gloss = syn.meaning,
			}
		)
	)
	
	for _,fam in ipairs(dial_data.groups) do
		table.insert(geojson,export.make_polygon(fam.name,fam.color,fam.points))
	end
	
	local legends = export.make_legends(legend)
	local map = export.make_map(frame, geojson, legends)
	
	return map_header .. map
end

return export
Category:Templates and modules needing documentation Category:Uncategorized modules