-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- We keep the original around for a while so that we can check it   --
-- when the above code does it wrong (data tables are not included). --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

-- author    : Kai Eigner, TAT Zetwerk
-- copyright : TAT Zetwerk
-- comment   : see font-odv.lua for current implementation

-- local state = attributes.private('state')
-- local sylnr = attributes.private('syllabe')
--
-- local function install_dev(tfmdata)
--     local features = tfmdata.resources.features
--     local sequences = tfmdata.resources.sequences
--
--     local insertpos = 1
--     for s=1,#sequences do    -- classify chars
--         for k in pairs(basic_shaping_forms) do
--             if sequences[s].features and ( sequences[s].features[k] or sequences[s].features.locl ) then insertpos = s + 1 end
--         end
--     end
--
--     features.gsub["dev2_reorder_matras"] = { ["dev2"] = { ["dflt"] = true } }
--     features.gsub["dev2_reorder_reph"] = { ["dev2"] = { ["dflt"] = true } }
--     features.gsub["dev2_reorder_pre_base_reordering_consonants"] = { ["dev2"] = { ["dflt"] = true } }
--     features.gsub["remove_joiners"] = { ["deva"] = { ["dflt"] = true }, ["dev2"] = { ["dflt"] = true } }
--
--     local sequence_dev2_reorder_matras = {
--         chain = 0,
--         features = { dev2_reorder_matras = { dev2 = { dflt = true } } },
--         flags = { false, false, false, false },
--         name = "dev2_reorder_matras",
--         subtables = { "dev2_reorder_matras" },
--         type = "dev2_reorder_matras",
--     }
--     local sequence_dev2_reorder_reph = {
--         chain = 0,
--         features = { dev2_reorder_reph = { dev2 = { dflt = true } } },
--         flags = { false, false, false, false },
--         name = "dev2_reorder_reph",
--         subtables = { "dev2_reorder_reph" },
--         type = "dev2_reorder_reph",
--     }
--     local sequence_dev2_reorder_pre_base_reordering_consonants = {
--         chain = 0,
--         features = { dev2_reorder_pre_base_reordering_consonants = { dev2 = { dflt = true } } },
--         flags = { false, false, false, false },
--         name = "dev2_reorder_pre_base_reordering_consonants",
--         subtables = { "dev2_reorder_pre_base_reordering_consonants" },
--         type = "dev2_reorder_pre_base_reordering_consonants",
--     }
--     local sequence_remove_joiners = {
--         chain = 0,
--         features = { remove_joiners = { deva = { dflt = true }, dev2 = { dflt = true } } },
--         flags = { false, false, false, false },
--         name = "remove_joiners",
--         subtables = { "remove_joiners" },
--         type = "remove_joiners",
--     }
--     table.insert(sequences, insertpos, sequence_dev2_reorder_pre_base_reordering_consonants)
--     table.insert(sequences, insertpos, sequence_dev2_reorder_reph)
--     table.insert(sequences, insertpos, sequence_dev2_reorder_matras)
--     table.insert(sequences, insertpos, sequence_remove_joiners)
-- end
--
-- local function deva_reorder(head,start,stop,font,attr)
--     local tfmdata = fontdata[font]
--     local lookuphash = tfmdata.resources.lookuphash
--     local sequences = tfmdata.resources.sequences
--
--     if not lookuphash["remove_joiners"] then install_dev(tfmdata) end    --install Devanagari-features
--
--     local sharedfeatures = tfmdata.shared.features
--     sharedfeatures["remove_joiners"] = true
--     local datasets = otf.dataset(tfmdata,font,attr)
--
--     lookuphash["remove_joiners"] = { [0x200C] = true, [0x200D] = true }
--
--     local current, n, base, firstcons, lastcons, basefound = start, start.next, nil, nil, nil, false
--     local reph, vattu = false, false
--     for s=1,#sequences do
--         local dataset = datasets[s]
--         featurevalue = dataset and dataset[1]
--         if featurevalue and dataset[4] == "rphf" then reph = true end
--         if featurevalue and dataset[4] == "blwf" then vattu = true end
--     end
--     if ra[start.char] and halant[n.char] and reph then    -- if syllable starts with Ra + H and script has 'Reph' then exclude Reph from candidates for base consonants
--         if n == stop then return head, stop end
--         if zwj[n.next.char] then
--             current = start
--         else
--             current = n.next
--             set_attribute(start,state,5) -- rphf
--         end
--     end
--
--     if nbsp[current.char] then    --Stand Alone cluster
--         if current == stop then
--             stop = stop.prev
--             head = node.remove(head, current)
--             node.free(current)
--             return head, stop
--         else
--             base, firstcons, lastcons = current, current, current
--             current = current.next
--             if current ~= stop then
--                 if nukta[current.char] then current = current.next end
--                 if zwj[current.char] then
--                     if current ~= stop and current.next ~= stop and halant[current.next.char] then
--                         current = current.next
--                         local tmp = current.next.next
--                         local changestop = current.next == stop
--                         local tempcurrent = node.copy(current.next)
--                         tempcurrent.next = node.copy(current)
--                         tempcurrent.next.prev = tempcurrent
--                         set_attribute(tempcurrent,state,8)    --blwf
--                         tempcurrent = nodes.handlers.characters(tempcurrent)
--                         unset_attribute(tempcurrent,state)
--                         if current.next.char == tempcurrent.char then
--                             node.flush_list(tempcurrent)
--                             local n = node.copy(current)
--                             current.char = dotted_circle
--                             head = node.insert_after(head, current, n)
--                         else
--                             current.char = tempcurrent.char    -- (assumes that result of blwf consists of one node)
--                             local freenode = current.next
--                             current.next = tmp
--                             tmp.prev = current
--                             node.free(freenode)
--                             node.flush_list(tempcurrent)
--                             if changestop then stop = current end
--                         end
--                     end
--                 end
--             end
--         end
--     end
--
--     while not basefound do    -- find base consonant
--         if consonant[current.char] then
--             set_attribute(current, state, 6)    --    half
--             if not firstcons then firstcons = current end
--             lastcons = current
--             if not base then
--                 base = current
--             else    --check whether consonant has below-base (or post-base) form
--                 local baseform = true
--                 for s=1,#sequences do
--                     local sequence = sequences[s]
--                     local dataset = datasets[s]
--                     featurevalue = dataset and dataset[1]
--                     if featurevalue and dataset[4] == "blwf" then
--                         local subtables = sequence.subtables
--                         for i=1,#subtables do
--                             local lookupname = subtables[i]
--                             local lookupcache = lookuphash[lookupname]
--                             if lookupcache then
--                                 local lookupmatch = lookupcache[current.char]
--                                 if lookupmatch then
--                                     set_attribute(current, state, 8)    --    blwf
--                                     baseform = false
--                                 end
--                             end
--                         end
--                     end
--                 end
--                 if baseform then base = current end
--             end
--         end
--         basefound = current == stop
--         current = current.next
--     end
--     if base ~= lastcons then    -- if base consonant is not last one then move halant from base consonant to last one
--         n = base.next
--         if nukta[n.char] then n = n.next end
--         if halant[n.char] then
--             if lastcons ~= stop then
--                 local ln = lastcons.next
--                 if nukta[ln.char] then lastcons = ln end
--             end
--             local np, nn, ln = n.prev, n.next, lastcons.next
--             np.next = n.next
--             nn.prev = n.prev
--             lastcons.next = n
--             if ln then ln.prev = n end
--             n.next = ln
--             n.prev = lastcons
--             if lastcons == stop then stop = n end
--         end
--     end
--
--     n = start.next
--     if ra[start.char] and halant[n.char] and not ( n ~= stop and ( zwj[n.next.char] or zwnj[n.next.char] ) ) then    -- if syllable starts with Ra + H then move this combination so that it follows either: the post-base 'matra' (if any) or the base consonant
--         local matra = base
--         if base ~= stop and dependent_vowel[base.next.char] then matra = base.next end
--         local sp, nn, mn = start.prev, n.next, matra.next
--         if sp then sp.next = nn end
--         nn.prev = sp
--         matra.next = start
--         start.prev = matra
--         n.next = mn
--         if mn then mn.prev = n end
--         if head == start then head = nn end
--         start = nn
--         if matra == stop then stop = n end
--     end
--
--     local current = start
--     while current ~= stop do
--         if halant[current.next.char] and current.next ~= stop and zwnj[current.next.next.char] then unset_attribute(current, state) end
--         current = current.next
--     end
--
--     if has_attribute(base, state) and base ~= stop and halant[base.next.char] and not ( base.next ~= stop and zwj[base.next.next.char] ) then unset_attribute(base, state) end
--
--     local current, allreordered, moved = start, false, { [base] = true }
--     local a, b, p, bn = base, base, base, base.next
--     if base ~= stop and nukta[bn.char] then a, b, p = bn, bn, bn end
--     while not allreordered do
--         local c, n, l = current, current.next, nil    --current is always consonant
--         if c ~= stop and nukta[n.char] then c = n n = n.next end
--         if c ~= stop and halant[n.char] then c = n n = n.next end
--         while c ~= stop and dependent_vowel[n.char] do c = n n = n.next end
--         if c ~= stop and vowel_modifier[n.char] then c = n n = n.next end
--         if c ~= stop and stress_tone_mark[n.char] then c = n n = n.next end
--         local bp, cn = firstcons.prev, current.next
--         while cn ~= c.next do    -- move pre-base matras...
--             if pre_mark[cn.char] then
--                 if bp then bp.next = cn end
--                 cn.prev.next = cn.next
--                 if cn.next then cn.next.prev = cn.prev end
--                 if cn == stop then stop = cn.prev end
--                 cn.prev = bp
--                 cn.next = firstcons
--                 firstcons.prev = cn
--                 if firstcons == start then
--                     if head == start then head = cn end
--                     start = cn
--                 end
--                 break
--             end
--             cn = cn.next
--         end
--         allreordered = c == stop
--         current = c.next
--     end
--
--     if reph or vattu then
--         local current, cns = start, nil
--         while current ~= stop do
--             local c, n = current, current.next
--             if ra[current.char] and halant[n.char] then
--                 c, n = n, n.next
--                 local b, bn = base, base
--                 while bn ~= stop  do
--                     if dependent_vowel[bn.next.char] then b = bn.next end
--                     bn = bn.next
--                 end
--                 if has_attribute(current,state,attribute) == 5 then    -- position Reph (Ra + H) after post-base 'matra' (if any) since these become marks on the 'matra', not on the base glyph
--                     if b ~= current then
--                         if current == start then
--                             if head == start then head = n end
--                             start = n
--                         end
--                         if b == stop then stop = c end
--                         if current.prev then current.prev.next = n end
--                         if n then n.prev = current.prev end
--                         c.next = b.next
--                         if b.next then b.next.prev = c end
--                         b.next = current
--                         current.prev = b
--                     end
--                 elseif cns and cns.next ~= current then    -- position below-base Ra (vattu) following the consonants on which it is placed (either the base consonant or one of the pre-base consonants)
--                     local cp, cnsn = current.prev, cns.next
--                     if cp then cp.next = n end
--                     if n then n.prev = cp end
--                     cns.next = current
--                     current.prev = cns
--                     c.next = cnsn
--                     if cnsn then cnsn.prev = c end
--                     if c == stop then stop = cp break end
--                     current = n.prev
--                 end
--             elseif consonant[current.char] or nbsp[current.char] then
--                 cns = current
--                 if halant[cns.next.char] then cns = cns.next end
--             end
--             current = current.next
--         end
--     end
--
--     if nbsp[base.char] then
--         head = node.remove(head, base)
--         node.free(base)
--     end
--
--     return head, stop
-- end
--
-- function dev2_reorder_matras(start,kind,lookupname,replacement)
--     local current = start
--     while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do
--         if halant[current.char] and not has_attribute(current, state) then
--             if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
--             local sn = start.next
--             start.next.prev = start.prev
--             if start.prev then start.prev.next = start.next end
--             if current.next then current.next.prev = start end
--             start.next = current.next
--             current.next = start
--             start.prev = current
--             start = sn
--             break
--         end
--         current = current.next
--     end
--     return start, true
-- end
--
-- function dev2_reorder_reph(start,kind,lookupname,replacement)
--     local current, sn = start.next, nil
--     while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do    --step 2
--         if halant[current.char] and not has_attribute(current, state) then
--             if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
--             sn = start.next
--             start.next.prev = start.prev
--             if start.prev then start.prev.next = start.next end
--             if current.next then current.next.prev = start end
--             start.next = current.next
--             current.next = start
--             start.prev = current
--             start = sn
--             break
--         end
--         current = current.next
--     end
--     if not sn then
--         current = start.next
--         while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do    --step 4
--             if has_attribute(current, state) == 9 then    --post-base
--                 sn = start.next
--                 start.next.prev = start.prev
--                 if start.prev then start.prev.next = start.next end
--                 start.prev = current.prev
--                 current.prev.next = start
--                 start.next = current
--                 current.prev = start
--                 start = sn
--                 break
--             end
--             current = current.next
--         end
--     end
--     if not sn then
--         current = start.next
--         local c = nil
--         while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do    --step 5
--             if not c and ( above_mark[current.char] or below_mark[current.char] or post_mark[current.char] ) and ReorderClass[current.char] ~= "after subscript" then c = current end
--             current = current.next
--         end
--         if c then
--             sn = start.next
--             start.next.prev = start.prev
--             if start.prev then start.prev.next = start.next end
--             start.prev = c.prev
--             c.prev.next = start
--             start.next = c
--             c.prev = start
--             start = sn
--         end
--     end
--     if not sn then
--         current = start
--         while current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) do    --step 6
--             current = current.next
--         end
--         if start ~= current then
--             sn = start.next
--             start.next.prev = start.prev
--             if start.prev then start.prev.next = start.next end
--             if current.next then current.next.prev = start end
--             start.next = current.next
--             current.next = start
--             start.prev = current
--             start = sn
--         end
--     end
--     return start, true
-- end
--
-- function dev2_reorder_pre_base_reordering_consonants(start,kind,lookupname,replacement)
--     local current, sn = start, nil
--     while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do
--         if halant[current.char] and not has_attribute(current, state) then
--             if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == start.font and has_attribute(current.next, sylnr) == has_attribute(start, sylnr) and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
--             sn = start.next
--             start.next.prev = start.prev
--             if start.prev then start.prev.next = start.next end
--             if current.next then current.next.prev = start end
--             start.next = current.next
--             current.next = start
--             start.prev = current
--             start = sn
--             break
--         end
--         current = current.next
--     end
--     if not sn then
--         current = start.next
--         while current and current.id == glyph and current.subtype<256 and current.font == start.font and has_attribute(current, sylnr) == has_attribute(start, sylnr) do
--             if not consonant[current.char] and has_attribute(current, state) then    --main
--                 sn = start.next
--                 start.next.prev = start.prev
--                 if start.prev then start.prev.next = start.next end
--                 start.prev = current.prev
--                 current.prev.next = start
--                 start.next = current
--                 current.prev = start
--                 start = sn
--                 break
--             end
--             current = current.next
--         end
--     end
--     return start, true
-- end
--
-- function remove_joiners(start,kind,lookupname,replacement)
--     local stop = start.next
--     while stop and stop.id == glyph and stop.subtype<256 and stop.font == start.font and (zwj[stop.char] or zwnj[stop.char]) do stop = stop.next end
--     if stop then stop.prev.next = nil stop.prev = start.prev end
--     if start.prev then start.prev.next = stop end
--     node.flush_list(start)
--     return stop, true
-- end
--
-- local function dev2_reorder(head,start,stop,font,attr)
--     local tfmdata = fontdata[font]
--     local lookuphash = tfmdata.resources.lookuphash
--     local sequences = tfmdata.resources.sequences
--
--     if not lookuphash["remove_joiners"] then install_dev(tfmdata) end    --install Devanagari-features
--
--     local sharedfeatures = tfmdata.shared.features
--     sharedfeatures["dev2_reorder_matras"] = true
--     sharedfeatures["dev2_reorder_reph"] = true
--     sharedfeatures["dev2_reorder_pre_base_reordering_consonants"] = true
--     sharedfeatures["remove_joiners"] = true
--     local datasets = otf.dataset(tfmdata,font,attr)
--
--     local reph, pre_base_reordering_consonants = false, nil
--     local halfpos, basepos, subpos, postpos = nil, nil, nil, nil
--     local locl = { }
--
--     for s=1,#sequences do    -- classify chars
--         local sequence = sequences[s]
--         local dataset = datasets[s]
--         featurevalue = dataset and dataset[1]
--         if featurevalue and dataset[4] then
--             local subtables = sequence.subtables
--             for i=1,#subtables do
--                 local lookupname = subtables[i]
--                 local lookupcache = lookuphash[lookupname]
--                 if lookupcache then
--                     if dataset[4] == "rphf" then
--                         if dataset[3] ~= 0 then --rphf is result of of chain
--                         else
--                             reph = lookupcache[0x0930] and lookupcache[0x0930][0x094D] and lookupcache[0x0930][0x094D]["ligature"]
--                         end
--                     end
--                     if dataset[4] == "pref" and not pre_base_reordering_consonants then
--                         for k, v in pairs(lookupcache[0x094D]) do
--                             pre_base_reordering_consonants[k] = v and v["ligature"]    --ToDo: reph might also be result of chain
--                         end
--                     end
--                     local current = start
--                     while current ~= stop.next do
--                         if dataset[4] == "locl" then locl[current] = lookupcache[current.char] end    --ToDo: locl might also be result of chain
--                         if current ~= stop then
--                             local c, n = locl[current] or current.char, locl[current.next] or current.next.char
--                             if dataset[4] == "rphf" and lookupcache[c] and lookupcache[c][n] then    --above-base: rphf    Consonant + Halant
--                             if current.next ~= stop and ( zwj[current.next.next.char] or zwnj[current.next.next.char] ) then    --ZWJ and ZWNJ prevent creation of reph
--                                 current = current.next
--                             elseif current == start then
--                                 set_attribute(current,state,5)
--                                 end
--                                 current = current.next
--                             end
--                             if dataset[4] == "half" and lookupcache[c] and lookupcache[c][n] then    --half forms: half    Consonant + Halant
--                                 if current.next ~= stop and zwnj[current.next.next.char] then    --ZWNJ prevent creation of half
--                                     current = current.next
--                                 else
--                                     set_attribute(current,state,6)
--                                     if not halfpos then halfpos = current end
--                                 end
--                                 current = current.next
--                             end
--                             if dataset[4] == "pref" and lookupcache[c] and lookupcache[c][n] then    --pre-base: pref    Halant + Consonant
--                                 set_attribute(current,state,7)
--                                 set_attribute(current.next,state,7)
--                                 current = current.next
--                             end
--                             if dataset[4] == "blwf" and lookupcache[c] and lookupcache[c][n] then    --below-base: blwf    Halant + Consonant
--                                 set_attribute(current,state,8)
--                                 set_attribute(current.next,state,8)
--                                 current = current.next
--                                 subpos = current
--                             end
--                             if dataset[4] == "pstf" and lookupcache[c] and lookupcache[c][n] then    --post-base: pstf    Halant + Consonant
--                                 set_attribute(current,state,9)
--                                 set_attribute(current.next,state,9)
--                                 current = current.next
--                                 postpos = current
--                             end
--                         end
--                         current = current.next
--                     end
--                 end
--             end
--         end
--     end
--
--     lookuphash["dev2_reorder_matras"] = pre_mark
--     lookuphash["dev2_reorder_reph"] = { [reph] = true }
--     lookuphash["dev2_reorder_pre_base_reordering_consonants"] = pre_base_reordering_consonants or { }
--     lookuphash["remove_joiners"] = { [0x200C] = true, [0x200D] = true }
--
--     local current, base, firstcons = start, nil, nil
--     if has_attribute(start,state) == 5 then current = start.next.next end    -- if syllable starts with Ra + H and script has 'Reph' then exclude Reph from candidates for base consonants
--
--     if current ~= stop.next and nbsp[current.char] then    --Stand Alone cluster
--         if current == stop then
--             stop = stop.prev
--             head = node.remove(head, current)
--             node.free(current)
--             return head, stop
--         else
--             base = current
--             current = current.next
--             if current ~= stop then
--                 if nukta[current.char] then current = current.next end
--                 if zwj[current.char] then
--                     if current ~= stop and current.next ~= stop and halant[current.next.char] then
--                         current = current.next
--                         local tmp = current.next.next
--                         local changestop = current.next == stop
--                         current.next.next = nil
--                         set_attribute(current,state,7)    --pref
--                         current = nodes.handlers.characters(current)
--                         set_attribute(current,state,8)    --blwf
--                         current = nodes.handlers.characters(current)
--                         set_attribute(current,state,9)    --pstf
--                         current = nodes.handlers.characters(current)
--                         unset_attribute(current,state)
--                         if halant[current.char] then
--                             current.next.next = tmp
--                             local nc = node.copy(current)
--                             current.char = dotted_circle
--                             head = node.insert_after(head, current, nc)
--                         else
--                             current.next = tmp    -- (assumes that result of pref, blwf, or pstf consists of one node)
--                             if changestop then stop = current end
--                         end
--                     end
--                 end
--             end
--         end
--     else    --not Stand Alone cluster
--         while current ~= stop.next do    -- find base consonant
--             if consonant[current.char] and not ( current ~= stop and halant[current.next.char] and current.next ~= stop and zwj[current.next.next.char] ) then
--                 if not firstcons then firstcons = current end
--                 if not ( has_attribute(current, state) == 7 or has_attribute(current, state) == 8 or has_attribute(current, state) == 9 ) then base = current end    --check whether consonant has below-base or post-base form or is pre-base reordering Ra
--             end
--             current = current.next
--         end
--         if not base then
--             base = firstcons
--         end
--     end
--
--     if not base then
--         if has_attribute(start, state) == 5 then unset_attribute(start, state) end
--         return head, stop
--     else
--         if has_attribute(base, state) then unset_attribute(base, state) end
--         basepos = base
--     end
--     if not halfpos then halfpos = base end
--     if not subpos then subpos = base end
--     if not postpos then postpos = subpos or base end
--
--     --Matra characters are classified and reordered by which consonant in a conjunct they have affinity for
--     local moved = { }
--     current = start
--     while current ~= stop.next do
--         local char, target, cn = locl[current] or current.char, nil, current.next
--         if not moved[current] and dependent_vowel[char] then
--             if pre_mark[char] then            -- Before first half form in the syllable
--                 moved[current] = true
--                 if current.prev then current.prev.next = current.next end
--                 if current.next then current.next.prev = current.prev end
--                 if current == stop then stop = current.prev end
--                 if halfpos == start then
--                     if head == start then head = current end
--                     start = current
--                 end
--                 if halfpos.prev then halfpos.prev.next = current end
--                 current.prev = halfpos.prev
--                 halfpos.prev = current
--                 current.next = halfpos
--                 halfpos = current
--             elseif above_mark[char] then    -- After main consonant
--                 target = basepos
--                 if subpos == basepos then subpos = current end
--                 if postpos == basepos then postpos = current end
--                 basepos = current
--             elseif below_mark[char] then    -- After subjoined consonants
--                 target = subpos
--                 if postpos == subpos then postpos = current end
--                 subpos = current
--             elseif post_mark[char] then    -- After post-form consonant
--                 target = postpos
--                 postpos = current
--             end
--             if ( above_mark[char] or below_mark[char] or post_mark[char] ) and current.prev ~= target then
--                 if current.prev then current.prev.next = current.next end
--                 if current.next then current.next.prev = current.prev end
--                 if current == stop then stop = current.prev end
--                 if target.next then target.next.prev = current end
--                 current.next = target.next
--                 target.next = current
--                 current.prev = target
--             end
--         end
--         current = cn
--     end
--
--     --Reorder marks to canonical order: Adjacent nukta and halant or nukta and vedic sign are always repositioned if necessary, so that the nukta is first.
--     local current, c = start, nil
--     while current ~= stop do
--         if halant[current.char] or stress_tone_mark[current.char] then
--             if not c then c = current end
--         else
--             c = nil
--         end
--         if c and nukta[current.next.char] then
--             if head == c then head = current.next end
--             if stop == current.next then stop = current end
--             if c.prev then c.prev.next = current.next end
--             current.next.prev = c.prev
--             current.next = current.next.next
--             if current.next.next then current.next.next.prev = current end
--             c.prev = current.next
--             current.next.next = c
--         end
--         if stop == current then break end
--         current = current.next
--     end
--
--     if nbsp[base.char] then
--         head = node.remove(head, base)
--         node.free(base)
--     end
--
--     return head, stop
-- end
--
-- function fonts.analyzers.methods.deva(head,font,attr)
-- local orighead = head
--     local current, start, done = head, true, false
--     while current do
--         if current.id == glyph and current.subtype<256 and current.font == font then
--             done = true
--             local syllablestart, syllableend = current, nil
--
--             local c = current    --Checking Stand Alone cluster (this behavior is copied from dev2)
--             if ra[c.char] and c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] and c.next.next and c.next.next.id == glyph and c.next.next.subtype<256 and c.next.next.font == font then c = c.next.next end
--             if nbsp[c.char] and ( not current.prev or current.prev.id ~= glyph or current.prev.subtype>=256 or current.prev.font ~= font or
--                                         ( not consonant[current.prev.char] and not independent_vowel[current.prev.char] and not dependent_vowel[current.prev.char] and
--                                         not vowel_modifier[current.prev.char] and not stress_tone_mark[current.prev.char] and not nukta[current.prev.char] and not halant[current.prev.char] )
--                                     ) then    --Stand Alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
--                 local n = c.next
--                 if n and n.id == glyph and n.subtype<256 and n.font == font then
--                     local ni = n.next
--                     if ( zwj[n.char] or zwnj[n.char] ) and ni and ni.id == glyph and ni.subtype<256 and ni.font == font then n = ni ni = ni.next end
--                     if halant[n.char] and ni and ni.id == glyph and ni.subtype<256 and ni.font == font and consonant[ni.char] then c = ni end
--                 end
--                 while c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] do c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 current = c.next
--                 syllableend = c
--                 if syllablestart ~= syllableend then
--                     head, current = deva_reorder(head, syllablestart,syllableend,font,attr)
--                     current = current.next
--                 end
--             elseif consonant[current.char] then    -- syllable containing consonant
--                 prevc = true
--                 while prevc do
--                     prevc = false
--                     local n = current.next
--                     if n and n.id == glyph and n.subtype<256 and n.font == font and nukta[n.char] then n = n.next end
--                     if n and n.id == glyph and n.subtype<256 and n.font == font and halant[n.char] then
--                         local n = n.next
--                         if n and n.id == glyph and n.subtype<256 and n.font == font and ( zwj[n.char] or zwnj[n.char] ) then n = n.next end
--                         if n and n.id == glyph and n.subtype<256 and n.font == font and consonant[n.char] then
--                             prevc = true
--                             current = n
--                         end
--                     end
--                 end
--                 if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == font and nukta[current.next.char] then current = current.next end    -- nukta (not specified in Microsft Devanagari OpenType specification)
--                 syllableend = current
--                 current = current.next
--                 if current and current.id == glyph and current.subtype<256 and current.font == font and halant[current.char] then    -- syllable containing consonant without vowels: {C + [Nukta] + H} + C + H
--                     if current.next and current.next.id == glyph and current.next.subtype<256 and current.next.font == font and ( zwj[current.next.char] or zwnj[current.next.char] ) then current = current.next end
--                     syllableend = current
--                     current = current.next
--                 else    -- syllable containing consonant with vowels: {C + [Nukta] + H} + C + [M] + [VM] + [SM]
--                     if current and current.id == glyph and current.subtype<256 and current.font == font and dependent_vowel[current.char] then
--                         syllableend = current
--                         current = current.next
--                     end
--                     if current and current.id == glyph and current.subtype<256 and current.font == font and vowel_modifier[current.char] then
--                         syllableend = current
--                         current = current.next
--                     end
--                     if current and current.id == glyph and current.subtype<256 and current.font == font and stress_tone_mark[current.char] then
--                         syllableend = current
--                         current = current.next
--                     end
--                 end
--                 if syllablestart ~= syllableend then
--                     head, current = deva_reorder(head,syllablestart,syllableend,font,attr)
--                     current = current.next
--                 end
--             elseif current.id == glyph and current.subtype<256 and current.font == font and independent_vowel[current.char] then -- syllable without consonants: VO + [VM] + [SM]
--                 syllableend = current
--                 current = current.next
--                 if current and current.id == glyph and current.subtype<256 and current.font == font and vowel_modifier[current.char] then
--                     syllableend = current
--                     current = current.next
--                 end
--                 if current and current.id == glyph and current.subtype<256 and current.font == font and stress_tone_mark[current.char] then
--                     syllableend = current
--                     current = current.next
--                 end
--             else    -- Syntax error
--                 if pre_mark[current.char] or above_mark[current.char] or below_mark[current.char] or post_mark[current.char] then
--                     local n = node.copy(current)
--                     if pre_mark[current.char] then
--                         n.char = dotted_circle
--                     else
--                         current.char = dotted_circle
--                     end
--                     head, current = node.insert_after(head, current, n)
--                 end
--                 current = current.next
--             end
--         else
--             current = current.next
--         end
--         start = false
--     end
--
--     return head, done
-- end
--
-- function fonts.analyzers.methods.dev2(head,font,attr)
--     local current, start, done, syl_nr = head, true, false, 0
--     while current do
--         local syllablestart, syllableend = nil, nil
--         if current.id == glyph and current.subtype<256 and current.font == font then
--             syllablestart = current
--             done = true
--             local c, n = current, current.next
--             if ra[current.char] and n and n.id == glyph and n.subtype<256 and n.font == font and halant[n.char] and n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font then c = n.next end
--             if independent_vowel[c.char] then --Vowel-based syllable: [Ra+H]+V+[N]+[<[<ZWJ|ZWNJ>]+H+C|ZWJ+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
--                 n = c.next
--                 local ni, nii = nil, nil
--                 if n and n.id == glyph and n.subtype<256 and n.font == font and nukta[n.char] then n = n.next end
--                 if n and n.id == glyph and n.subtype<256 and n.font == font then local ni = n.next end
--                 if ni and ni.id == glyph and ni.subtype<256 and ni.font == font and ni.next and ni.next.id == glyph and ni.next.subtype<256 and ni.next.font == font then
--                     nii = ni.next
--                     if zwj[ni.char] and consonant[nii.char] then
--                         c = nii
--                     elseif (zwj[ni.char] or zwnj[ni.char]) and halant[nii.char] and nii.next and nii.next.id == glyph and nii.next.subtype<256 and nii.next.font == font and consonant[nii.next.char] then
--                         c = nii.next
--                     end
--                 end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 current = c
--                 syllableend = c
--             elseif nbsp[c.char] and ( not current.prev or current.prev.id ~= glyph or current.prev.subtype>=256 or current.prev.font ~= font or
--                                         ( not consonant[current.prev.char] and not independent_vowel[current.prev.char] and not dependent_vowel[current.prev.char] and
--                                         not vowel_modifier[current.prev.char] and not stress_tone_mark[current.prev.char] and not nukta[current.prev.char] and not halant[current.prev.char] )
--                                     ) then    --Stand Alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
--                 n = c.next
--                 if n and n.id == glyph and n.subtype<256 and n.font == font then
--                     local ni = n.next
--                     if ( zwj[n.char] or zwnj[n.char] ) and ni and ni.id == glyph and ni.subtype<256 and ni.font == font then n = ni ni = ni.next end
--                     if halant[n.char] and ni and ni.id == glyph and ni.subtype<256 and ni.font == font and consonant[ni.char] then c = ni end
--                 end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 current = c
--                 syllableend = c
--             elseif consonant[current.char] then    --Consonant syllable: {C+[N]+<H+[<ZWNJ|ZWJ>]|<ZWNJ|ZWJ>+H>} + C+[N]+[A] + [< H+[<ZWNJ|ZWJ>] | {M}+[N]+[H]>]+[SM]+[(VD)]
--                 c = current
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
--                 n = c
--                 while n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and ( halant[n.next.char] or zwnj[n.next.char] or zwj[n.next.char] ) do
--                     if halant[n.next.char] then
--                         n = n.next
--                         if n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and ( zwnj[n.next.char] or zwj[n.next.char] ) then n = n.next end
--                     else
--                         if n.next.next and n.next.next.id == glyph and n.next.next.subtype<256 and n.next.next.font == font and halant[n.next.next.char] then n = n.next.next end
--                     end
--                     if n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and consonant[n.next.char] then
--                         n = n.next
--                         if n.next and n.next.id == glyph and n.next.subtype<256 and n.next.font == font and nukta[n.next.char] then n = n.next end
--                         c = n
--                     else
--                         break
--                     end
--                 end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and anudatta[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then
--                     c = c.next
--                     if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and ( zwnj[c.next.char] or zwj[c.next.char] ) then c = c.next end
--                 else
--                     if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and dependent_vowel[c.next.char] then c = c.next end
--                     if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and nukta[c.next.char] then c = c.next end
--                     if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and halant[c.next.char] then c = c.next end
--                 end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and vowel_modifier[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 if c.next and c.next.id == glyph and c.next.subtype<256 and c.next.font == font and stress_tone_mark[c.next.char] then c = c.next end
--                 current = c
--                 syllableend = c
--             end
--         end
--
--         if syllableend then
--             syl_nr = syl_nr + 1
--             c = syllablestart
--             while c ~= syllableend.next do
--                 set_attribute(c,sylnr,syl_nr)
--                 c = c.next
--             end
--         end
--         if syllableend and syllablestart ~= syllableend then
--             head, current = dev2_reorder(head,syllablestart,syllableend,font,attr)
--         end
--
--         if not syllableend and not has_attribute(current, state) and current.id == glyph and current.subtype<256 and current.font == font then    -- Syntax error
--             if pre_mark[current.char] or above_mark[current.char] or below_mark[current.char] or post_mark[current.char] then
--                 local n = node.copy(current)
--                 if pre_mark[current.char] then
--                     n.char = dotted_circle
--                 else
--                     current.char = dotted_circle
--                 end
--                 head, current = node.insert_after(head, current, n)
--             end
--         end
--
--         start = false
--         current = current.next
--     end
--
--     return head, done
-- end
--
-- function otf.handlers.dev2_reorder_matras(start,kind,lookupname,replacement)
--     return dev2_reorder_matras(start,kind,lookupname,replacement)
-- end
--
-- function otf.handlers.dev2_reorder_reph(start,kind,lookupname,replacement)
--     return dev2_reorder_reph(start,kind,lookupname,replacement)
-- end
--
-- function otf.handlers.dev2_reorder_pre_base_reordering_consonants(start,kind,lookupname,replacement)
--     return dev2_reorder_pre_base_reordering_consonants(start,kind,lookupname,replacement)
-- end
--
-- function otf.handlers.remove_joiners(start,kind,lookupname,replacement)
--     return remove_joiners(start,kind,lookupname,replacement)
-- end
