local Dialect = {}
function Dialect:new(object)
    object = object or {}
    for k, v in pairs(object) do
        if type(v) == "table" then setmetatable(v, {__index = self[k]}) end
    end
    setmetatable(object, self)
    self.__index = self
    
    object.initialConsonantsToIPA.dz = object.initialConsonantsToIPA.d
    object.initialConsonantsToIPA.gi = object.initialConsonantsToIPA.d
    object.initialConsonantsToIPA.z = object.initialConsonantsToIPA.d
    object.interiorToIPA.y = object.interiorToIPA.i
    
    return object
end

---Table mapping initial consonant clusters to IPA transcriptions.
Dialect.initialConsonantsToIPA = {
    b = "ɓ", c = "k", ch = "ʨ", d = "j", ["đ"] = "ɗ", g = "ɣ",
    gh = "ɣ", gi = "z", h = "h", k = "k", kh = "x", l = "l", m = "m",
    n = "n", ng = "ŋ", ngh = "ŋ", nh = "ɲ", p = "p", ph = "f", qu = "kw", r = "ɹ",
    s = "ʂ", t = "t", th = "tʰ", tr = "tʂ", v = "v", x = "s"
}

---Table mapping interior glide-vowel-glide sequences to IPA transcriptions, or
-- functions that return transcriptions for the given dialect, initial consonant
-- cluster, and final consonant cluster. Transcriptions include underscores as
-- placeholders for combining diacritics.
-- [[Đặc biệt:Tiền tố/Bản mẫu:vie-pron/VieWVG/]]
Dialect.interiorToIPA = {
    a = "a_ː", ai = "a_ːj", ao = "a_ːw", au = "a_w", ay = "a_j", e = "ɛ_",
    eo = "ɛ_w", i = function (ci, cf)
        if cf == "ch" or cf == "nh" then return "ï_"
        else return "i_" end
    end, ia = "i_ə", ie = "jɛ_", ieo = "jɛ_w", iu = "i_w",
    ["iê"] = "iə_", ["iêu"] = "iə_w", o = function (ci, cf)
        if cf == "c" or cf == "ng" then return "a_w"
        else return "ɔ_" end
    end, oa = "wa_", oai = "wa_ːj", oao = "wa_ːw", oay = "wa_j", ["oă"] = "wa",
    oe = "wɛ_", oeo = "wɛ_w", oi = "ɔ_j", oo = "ɔ_", u = "u_",
    ia = function (ci, cf)
        if ci == "gi" then return "aː"
        else return "i_ə" end
    end,
    ua = function (ci, cf)
        if ci == "q" then return "wa_ː"
        else return "u_ə" end
    end,
    uau = "wa_w", ui = function (ci, cf)
        if ci == "q" then return "wi_"
        else return "u_j" end
    end, uy = "wi_", uya = "wiə_", uyu = "wi_w", ["uyê"] = "wiə_", ["uâ"] = "wə_",
    ["uây"] = "wə_j", ["uê"] = "we_", ["uêu"] = "we_w", ["uì"] = "wi_",
    ["uô"] = "uə", ["uôi"] = "uə_j", ["uơ"] = "wə_ː", ["uơi"] = "wə_ːj",
    ["â"] = "ə_", ["âu"] = "ə_w", ["ây"] = "ə_j", ["ê"] = function (ci, cf)
        if ci == "gi" then return "ə_"
        else return "e_" end
    end, ["êu"] = "e_w",
    ["ô"] = function (ci, cf)
        if cf == "c" or cf == "ng" then return "ə_w"
        else return "o_" end
    end, ["ôi"] = "o_j", ["ôô"] = "o_", ["ùa"] = "u_ə", ["ùi"] = "u_j",
    ["ă"] = "a_", ["ơ"] = "ə_ː", ["ơi"] = "ə_ːj", ["ư"] = "ɨ_", ["ưa"] = "ɨ_ə",
    ["ưi"] = "ɨ_j", ["ưu"] = "ɨ_w", ["ươ"] = "ɨə_", ["ươi"] = "ɨə_j",
    ["ươu"] = "ɨə_w"
}

---Table mapping final consonant clusters to IPA transcriptions, or functions
-- that return transcriptions for the given dialect and glide-vowel-glide
-- sequence.
Dialect.finalConsonantsToIPA = {
    c = "k", ch = "k", m = "m", n = "n", ng = "ŋ", nh = "ŋ", p = "p", t = "t"
}

---Table mapping dialects to tables of VIQR tone representations to IPA tone
-- letter sequences.
Dialect.viqrTonesToIPA = {
    [""] = "˧˧", ["'"] = "˧˥", ["`"] = "˨˩", ["?"] = "˧˩˧", ["~"] = "˧˥",
    ["."] = "˨˩"
}

Dialect.toneAttributes = {}

dialects = {}

NorthernDialect = Dialect:new({
    interiorToIPA = {
        a = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "a_j" else return "a_ː" end
        end, ["ê"] = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "ə_j"
            elseif ci == "gi" then return "ə_"
            else return "e_" end
        end,
        oa = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "wa_j" else return "wa_ː" end
        end,
        ua = function (ci, cf)
            if cf == "ch" or ch == "nh" then return "wa_j" else return "wa_ː" end
        end, ["ưu"] = "i_w", ["ươu"] = "iə_w"},
    toneAttributes = {
        ["`"] = {breathy = true}, ["?"] = {creaky = true},
        ["~"] = {glottal = true, repeated = true},
        ["."] = {creaky = true, glottal = true}
    }
})

dialects["Hà Nội"] = NorthernDialect:new({
    initialConsonantsToIPA = {d = "z", gi = "z", r = "z", s = "s", tr = "ʨ"}
})

dialects["Hải Phòng"] = NorthernDialect:new({
    initialConsonantsToIPA = {gi = "j", r = "z"}
})

local NorthCentralDialect = Dialect:new({
    initialConsonantsToIPA = {d = "ɟ", gi = "z"},
    interiorToIPA = {
        a = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "a_j" else return "a_ː" end
        end
    },
    viqrTonesToIPA = {["`"] = "˧˧", ["?"] = "˧˩", ["."] = "˨˨"}
})

dialects["Vinh"] = NorthCentralDialect:new({
    viqrTonesToIPA = {[""] = "˧˥", ["'"] = "˩˩", ["~"] = "˩˧"},
    toneAttributes = {["~"] = {creaky = true}}
})

dialects["Thanh Chương"] = NorthCentralDialect:new({
    viqrTonesToIPA = {[""] = "˧˥", ["'"] = "˩˩", ["~"] = "˧˩"},
    toneAttributes = {["."] = {creaky = true}}
})

dialects["Hà Tĩnh"] = NorthCentralDialect:new({
    viqrTonesToIPA = {[""] = "˧˥˧", ["'"] = "˩˧", ["~"] = "˨˨"},
    toneAttributes = {
        ["'"] = {creaky = true}, ["?"] = {creaky = true, glottal = true},
        ["~"] = {creaky = true}, ["."] = {creaky = true}
    }
})

dialects["Huế"] = Dialect:new({
    initialConsonantsToIPA = {r = "ʐ", v = "v"},
    interiorToIPA = {
        a = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "a_" else return "a_ː" end
        end,
        i = function (ci, cf)
            if cf == "ch" or ch == "nh" then return "ɪ̈_" else return "i_" end
        end,
        oa = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "wa_"
            else return "wa_ː" end
        end
    },
    finalConsonantsToIPA = {
        ch = "t", n = function (ci, gvg)
            if gvg == "ê" or gvg == "i" or gvg == "uy" then return "n"
            else return "ŋ" end
        end,
        nh = "n", t = function (ci, gvg)
            if gvg == "ê" or gvg == "i" or gvg == "uy" then return "t"
            else return "k" end
        end
    },
    viqrTonesToIPA = {
        [""] = "˧˥", ["'"] = "˩˧", ["`"] = "˧˧", ["?"] = "˧˩˨", ["~"] = "˧˩˨",
        ["."] = "˨˨"
    },
    toneAttributes = {["'"] = {creaky = true}, ["."] = {creaky = true}}
})

SouthernDialect = Dialect:new({
    initialConsonantsToIPA = {kh = "kʰ", qu = "ɡw", r = "ɹ"},
    interiorToIPA = {
        a = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "a_" else return "a_ː" end
        end, ["ê"] = function (ci, cf)
            if cf == "ch" or cf == "nh" or cf == "n" or cf == "t" then return "ə_ː"
            elseif ci == "gi" then return "ə_"
            else return "e_" end
        end,
        i = function (ci, cf)
            if cf == "ch" or cf == "nh" or cf == "n" or cf == "t" then return "ɪ̈_"
            else return "i_" end 
        end,
        oa = function (ci, cf)
            if cf == "ch" or cf == "nh" then return "wa_"
            else return "wa_ː" end
        end,
        ["uô"] = "uə",
        ui = function (ci, cf)
            if ci == "q" then
                if cf == "ch" or cf == "nh" or cf == "n" or cf == "t" then return "wɪ̈_̈"
                else return "wi_" end
            else
                return "u_j"
            end
        end,
        uy = function (ci, cf)
            if cf == "ch" or cf == "nh" or cf == "n" or cf == "t" then return "wɪ̈_̈"
            else return "wi_" end
        end
    },
    finalConsonantsToIPA = {
        ch = "t", n = function (ci, gvg)
            if (gvg == "ê" and not ci == "gi") or gvg == "i" or gvg == "uy" then return "n"
            else return "ŋ" end
        end,
        nh = "n", t = function (ci, gvg)
            local last = mw.ustring.sub(gvg, -1)
            if gvg == "ê" or last == "i" or last == "y" then return "t"
            else return "k" end
        end
    },
    viqrTonesToIPA = {["?"] = "˨˩˦", ["~"] = "˨˩˦", ["."] = "˨˩˨"}
})

dialects["Quy Nhơn"] = SouthernDialect:new({
    initialConsonantsToIPA = {
        kh = function (gvg, cf)
            if (mw.ustring.sub(gvg, 1, 2) == "oa" or
                mw.ustring.sub(gvg, 1, 2) == "oe") then
                return "f"
            else return "kʰ" end
        end,
        ng = function (gvg, cf)
            if gvg == "oai" then return "kw" else return "ŋ" end
        end,
        [""] = function (gvg, cf)
            if gvg == "ơi" then return "kw" else return "" end
        end
    },
    interiorToIPA = {
        a = function (ci, cf)
            if #cf < 1 then return "ɛ_a" else return "a_ː" end
        end,
        o = function (ci, cf)
            if cf == "c" or cf == "ng" then
                if ci == "d" or ci == "gi" or ci == "j" then
                    return "a_w"
                else
                    return "ɔ_"
                end
            elseif cf == "m" then return "o_"
            else return "ɔ_" end
        end,
        oo = function (ci, cf)
            if cf == "m" then return "o_" else return "ɔ_" end
        end,
        ["ă"] = "a_", ["ê"] = function (ci, cf)
            if cf == "p" then return "i_"
            elseif ci == "gi" then return "ə_"
            else return "e_" end
        end,
        ["iêu"] = "i_w",
        ["ôi"] = "ə_w", ["ươi"] = "ɨ_", ["uôi"] = "u_j"
    },
    finalConsonantsToIPA = {
        t = function (ci, gvg)
            if gvg == "o" or gvg == "ô" or gvg == "ôô" or gvg == "u" then
                return "t"
            else return "k" end
        end
    }
})
dialects["Quy Nhơn"].interiorToIPA.oa = dialects["Quy Nhơn"].interiorToIPA.a
dialects["Quy Nhơn"].interiorToIPA.oai = dialects["Quy Nhơn"].interiorToIPA.ai
dialects["Quy Nhơn"].interiorToIPA.oao = dialects["Quy Nhơn"].interiorToIPA.ao
dialects["Quy Nhơn"].interiorToIPA.oay = dialects["Quy Nhơn"].interiorToIPA.ay
dialects["Quy Nhơn"].interiorToIPA.oe = dialects["Quy Nhơn"].interiorToIPA.e
dialects["Quy Nhơn"].interiorToIPA.oeo = dialects["Quy Nhơn"].interiorToIPA.eo

dialects["Sài Gòn"] = SouthernDialect:new()

return dialects