content: module Main where
  
  import Data.Char
  import Data.List
  import qualified Data.Map as Map
  import System
  
  -- convert all files *Tha.gf into *ThP.gf with "t" changed to (thpron "t" "p")
  
  main = allThpron
  
  allThpron = do
    System.system "ls *Tha*.gf ../api/*Tha*.gf >srcThai.txt"
    files <- readFile "srcThai.txt" >>= return . lines
    mapM_ fileThpron files
    return ()
  
  fileThpron file = do
    s <- readFile file
    let tgt = appThpron file
    writeFile tgt (appThpron s)
    putStrLn ("wrote " ++ tgt)
  
  -- thb = IPA Thai; not used in ISO-639-3 like Thp 
  appThpron s = case s of
    '"':cs -> let (w,_:rest) = break (=='"') cs in mkThpron w ++ appThpron rest
    'T':'h':'a':'A':rest             -> "Thb" ++ appThpron rest  -- AllThaAbs
    'T':'h':'a':c:rest   | isAlpha c -> "Tha" ++ c : appThpron rest  -- Thank
    'T':'h':'a':rest -> "Thb" ++ appThpron rest
    c:cs -> c:appThpron cs
    _ -> s
  
  mkThpron s = "(thpron \"" ++ s ++ "\" \"" ++ thai2pron s ++ "\")"
  
  
  -- the following functions involving pron (=pronunciation) work on syllables
  
  thai2pron  = uni2pron . thai2uni
  trans2pron = uni2pron . trans2uni
  trans2thai = uni2thai . trans2uni
  trans2dat  = uni2dat  . trans2uni
  
  thai2uni :: String -> [Int]
  thai2uni = map fromEnum
  
  uni2thai :: [Int] -> String
  uni2thai = map toEnum
  
  uni2pron :: [Int] -> String
  uni2pron = dat2pron . uni2dat
  
  uni2dat = map (maybe CR dat . (\u -> Map.lookup u uniMap))  --- CR as exception value
  
  --high = accent '\x301'
  --low  = accent '\x300'
  --rising = accent '\x306'
  --falling = accent '\x302'
  
  dat2pron :: [ThaiDat] -> String
  dat2pron is = case is of
  
  -- exceptional words
   [Ce,Ck1,CaL]    -> "kha\x301w"
   [Cc1,Ca,Cn]     -> "cha\x301n"
   [CaE,Ch,Cm]     -> "m" ++ high "ay"
   [Ct,CT2,CO,Cg]  -> "t" ++ falling i_O ++ i_ng 
   [Ce,Cg,Ci,Cn]   -> i_ng ++ i_oe ++ "n"
   [CaE,Cd,CT2]    -> "d" ++ falling "aay"
   [Ce,Ck,CT2,CaL] -> "k" ++ falling "aaw"
   [CaE,Cm,CT2]    -> "m" ++ high "aay"
   [CO,Cy,CaL,Ck]  -> "y" ++ low "aak"
   [CO,Cy,CT1,CaL] -> "y" ++ low "aa"
   [CO,Cy,CT1,CaL,Cg] -> "y" ++ low "aa" ++ i_ng
   [CO,Cy,CT1,CuL] -> "y" ++ low "uu"
   [Cp3,Cr]        -> "phan" --- not in Smyth
   [Cp2,Cw,Ck]     -> "phw" ++ falling "ak" -- not in Smyth
   [Cc2,CvL,CT1,CO] -> "ch" ++ falling i_uue --- to get rid of final O
   [CO,Cg,CT1,Cu,Cn] -> low "a" ++ i_ng ++ low "un" --- probably there is a rule for leading vowelless O
  
  -- words following the rules (mostly from Smyth's Essential Grammar)
   _ -> case getSyllable is of
    [Ce]  : cc : [] : d : cs | brev d -> prons cc ++ tone cc d cs "e"         ++ endWith cs  -- e-8  -> e
    [Ce'] : cc : [] : d : cs | brev d -> prons cc ++ tone cc d cs i_ae        ++ endWith cs  -- ä-8 -> ä
    [v]   :[CO]: []          : d : cs ->             tone[CO]d cs (pron v)    ++ endWith cs  -- e/ä/o/ay/ay
    [v]   : cc : []          : d : cs -> prons cc ++ tone cc d cs (pron v)    ++ endWith cs  -- e/ä/o/ay/ay
    [Ce]  : cc : [Cy]        : d : cs -> prons cc ++ tone cc d cs (i_ooe++"y")++ endWith cs  -- e-y  -> ööy
    [Ce]  : cc : [CO]        : d : cs -> prons cc ++ tone cc d cs i_ooe       ++ endWith cs  -- e-O  -> öö
    [Ce]  : cc : [CO,CaP]    : d : cs -> prons cc ++ tone cc d cs i_oe        ++ endWith cs  -- e-Oa -> ö
    [Ce]  : cc : [CaP]       : d : cs -> prons cc ++ tone cc d cs "e"         ++ endWith cs  -- e-a
    [Ce]  : cc : [CaL]       : d : cs -> prons cc ++ tone cc d cs "aw"        ++ endWith cs  -- e-a
    [Ce]  : cc : [CaL,CaP]   : d : cs -> prons cc ++ tone cc d cs i_O         ++ endWith cs  -- e-Aa -> O
    [Ce]  : cc : [Ci]        : d : cs -> prons cc ++ tone cc d cs i_ooe       ++ endWith cs  -- e-i  -> öö
    [Ce]  : cc : [CiL,Cy]    : d : cs -> prons cc ++ tone cc d cs "ia"        ++ endWith cs  -- e-iiy-> ia
    [Ce]  : cc : [Ci,Cy,CaP] : d : cs -> prons cc ++ tone cc d cs "ia"        ++ endWith cs  -- e-iya-> ia
    [Ce]  : cc : [CiL,CO]    : d : cs -> prons cc ++ tone cc d cs "ia"        ++ endWith cs  -- e-iiO-> üa
    [Ce]  : cc : [CvL,CO]    : d : cs -> prons cc ++ tone cc d cs (i_ue++"a") ++ endWith cs  -- e-vvO-> üa
    [Ce]  : cc : [CvL,CO,Cy] : d : cs -> prons cc ++ tone cc d cs (i_ue++"ay")++ endWith cs  -- e-vvOy-> üay
    [Ce'] : cc : [CaP]       : d : cs -> prons cc ++ tone cc d cs i_ae        ++ endWith cs  -- ä-a -> ä
    [CoL] : cc : [CaP]       : d : cs -> prons cc ++ tone cc d cs "o"         ++ endWith cs  -- o-a -> o
    []    :[CO]: v           : d : cs ->             tone[CO]d cs (prons v)   ++ endWith cs  -- Ov  -> v
    []    : cc : [Ca,Cw]     : d : cs -> prons cc ++ tone cc d cs "ua"        ++ endWith cs  -- Caw -> Cua
    []    : cc : v           :[CK]:cs -> endWith cs                                          -- swas(di:K)
    []    : bb : [] : cc : []: d : cs -> prons bb ++ "a" ++ prons cc ++ tone cc [] cs "o" ++ endWith (d:cs) -- CaCoC
    []    : bb : [] : cc : []         -> prons bb ++                    tone bb [] [cc] "o" ++ endWith [cc]  -- CoC
    []    : bb : [] : cc : v : d : cs -> prons bb ++ "a" ++ prons cc ++ tone cc [] cs (prons v) ++ endWith cs -- CaCvC
    []    : cc : v           : d : cs -> prons cc ++ tone cc d cs (prons v)               ++ endWith cs  -- Cv- (normal)
  
    _ -> prons is --- shouldn't happen
  
   where
     prons cc = case cc of
       _ :CK:cs -> prons cs -- killer 
       Ch:c:cs | isConsonant c -> concatMap pron (c:cs) -- hC, ---- only some conss
       _       -> concatMap pron cc
     endWith ss = case concat ss of
       _:CK:cs  -> dat2pron cs
       c   :cs  -> enc c ++ dat2pron cs
       _        -> []
  
     enc  c = lookThai [] enp c
     pron c = lookThai [] pro c
     brev d = elem CS d  -- shortener
  
  getSyllable :: [ThaiDat] -> [[ThaiDat]]  -- (V?),(C|CC|hC),(V*),(D*),(C*),[[],C]?
  getSyllable s = case s of
    v:cs | isPreVowel v -> [v]:getCons v cs
    []  -> []
    c:_ -> []:getCons c s
   where
     getCons v s = case s of
       Ch:c:cs     | isConsonant c && isLow c -> let (cc:ccs) = getCons v (c:cs) in (Ch:cc):ccs -- hC
       CO:cs                                  -> [CO]  :getVow v cs      -- O
       Cs:Cr:cs                               -> [Cs]  :getVow v cs      -- sr -> s
       _:CK:[]                                -> []
       b:Cr:Cr:[]  | isConsonant b            -> [b]   :[Ca]:[]:[Cr]:[]  -- Crr  -> Can
       b:Cr:Cr:[c] | all isConsonant [b,c]    -> [b]   :[Ca]:[]:[c]:[]   -- CrrC -> CaC  
       b:c:cs      | isCluster b c            -> [b,c] :getVow v cs      -- C(l|r|w) cluster
       b:cs        | isPreVowel v             -> [b]   :getVow v cs
       b:c:Cw:Cy:[]| isConsonant b && isDiacritic c -> [b]:[Cu,Ca]:[c]:[Cy]:[] -- CTuay
       b:Cw:Cy:[]  | isConsonant b            -> [b]   :[Cu,Ca]:[]:[Cy]:[] -- Cuay
       b:c:d:[]    | all isConsonant [b,c,d]  -> [b]   :[]:[c]:[]:[d]:[] -- CaCoC
       b:c:[]      | all isConsonant [b,c]    -> [b]   :[]:[c]:[]        -- CoC
       b:c:cs      | all isConsonant [b,c]    -> [b]   :[]:[c]:getVow c cs -- CaCvC
       b:cs        | isConsonant b            -> [b]   :getVow v cs      -- C
       _ -> [s] --- shouldn't happen ??
     getVow v0 s = case span (\x -> inVow v0 x || isDiacritic x) s of
       (v,c:cs) -> let (d,w) = partition isDiacritic v in w:d:[c]:getSyllable cs
       (v,_)    -> let (d,w) = partition isDiacritic v in [w,d]
     inVow v0 x = isInVowel x || case v0 of
       Ce -> elem x [Cy]  -- after e-, also y is a part of a vowel
       _  -> False --- elem x [Cw]
     isLow c = lookThai Low ccl c == Low
  
  isCluster b c = 
        (pronTha c == "r"  && elem (pronTha b) ["k","kh","p","ph","t"])
     || (pronTha c == "ri" && elem (pronTha b) ["k","kh","p","ph","t"])
     || (pronTha c == "l" && elem (pronTha b) ["k","kh","p","ph"])
     || (pronTha c == "w" && elem (pronTha b) ["k","kh"])
  
  pronTha c = lookThai [] pro c
  
  isInVowel :: ThaiDat -> Bool
  isInVowel v  = (CaP <= v && v <= CuL) || v == CO -- infix vowels
  
  isPreVowel :: ThaiDat -> Bool
  isPreVowel i = Ce <= i && i <= CaE
  
  isVowel :: ThaiDat -> Bool
  isVowel i = CaP <= i && i <= CaE
  
  isConsonant :: ThaiDat -> Bool
  isConsonant i = Ck <= i && i <= Ch' && i /= CO
  
  isDiacritic :: ThaiDat -> Bool
  isDiacritic i = CS <= i && i <= CK
  
  tone :: [ThaiDat] -> [ThaiDat] -> [[ThaiDat]] -> String -> String
  tone cc@(c:_) d cs v = case (lookThai Low ccl c, isLive cs1, toneMark d) of
    (_,_,3) -> high v
    (_,_,4) -> rising v
    (Low,_,1) -> falling v
    (Low,_,2) -> high v
    (Low,True,_)  -> mid v
    (Low,False,_) -> case isLong v of
       False -> high v
       True  -> falling v
    (_,_,1) -> low v
    (_,_,2) -> falling v
    (Mid,True,_)   -> mid v
    (Mid,False,_)  -> low v
    (High,True,_)  -> rising v
    (High,False,_) -> low v
   where
    cs1 = concat (take 1 cs)
  tone _ _ _ v = mid v
  
  toneMark :: [ThaiDat] -> Int
  toneMark is = case is of
    CT1:is -> 1
    CT2:is -> 2
    CT3:is -> 3
    CT4:is -> 4
    _  :is -> toneMark is
    _      -> 0  -- no tone mark in is
  
  isLong :: String -> Bool
  isLong s = case s of
    'i':'a':_   -> True
    'u':'a':_   -> True
    '\x289':a:_ -> True     -- uea
    c:d:_ | c == d -> True  --- must be vowels
    _:cs           -> isLong cs
    _ -> False 
  
  isLive :: [ThaiDat] -> Bool
  isLive is = case is of
    [i] -> lookThai False liv i
    []  -> True
    _   -> False
  
  mid, high, low, falling, rising :: String -> String
  mid s = s
  high = accent '\x301'
  low  = accent '\x300'
  rising = accent '\x306'
  falling = accent '\x302'
  
  accent a s = case s of
    c:cs -> c:a:cs
    _ -> s
  
  trans2uni :: String -> [Int]
  trans2uni = 
    map (\c -> maybe 0 id $ Map.lookup c trans) . 
    unchar
   where
    trans = Map.fromList [(tra c, uni c) | c <- allThaiChars]
    
  unchar :: String -> [String]  
  unchar s = case s of
      c:d:cs 
       | isAlpha d -> [c]    : unchar (d:cs)
       | isSpace d -> [c]:[d]: unchar cs
       | otherwise -> let (ds,cs2) = break (\x -> isAlpha x || isSpace x) cs in
                      (c:d:ds) : unchar cs2
      [_]          -> [s]
      _            -> []
  
  
  thaiMap :: Map.Map ThaiDat ThaiChar
  thaiMap = Map.fromList [(dat c,c) | c <- allThaiChars]
  
  uniMap :: Map.Map Int ThaiChar
  uniMap  = Map.fromList [(uni c,c) | c <- allThaiChars]
  
  lookThai :: a -> (ThaiChar -> a) -> ThaiDat -> a
  lookThai v f i = maybe v f (Map.lookup i thaiMap)
  
  data ThaiChar = TC {
    dat :: ThaiDat,
    uni :: Int,
    tra :: String,
    ccl :: CClass,
    liv :: Bool,
    pro :: String,
    enp :: String
    }
    deriving Show
  
  data CClass = Low | Mid | High
    deriving (Show, Eq)
  
  -- IPA sounds
  i_ng = "\331"
  i_O  = "\596"
  i_ue = "\x289"
  i_ae = "\x25b"
  i_oe = "\601"
  i_ooe = i_oe ++ i_oe
  i_uue = i_ue ++ i_ue
  i_aae = i_ae ++ i_ae
  i_OO  = i_O  ++ i_O
  
  allThaiChars :: [ThaiChar]
  allThaiChars = [
    TC {dat = Ck,  uni = 3585, tra = "k", ccl = Mid, liv = False, pro = "k", enp = "k"},
    TC {dat = Ck1, uni = 3586, tra = "k1", ccl = High, liv = False, pro = "kh", enp = "k"},
    TC {dat = Ck2, uni = 3588, tra = "k2", ccl = Low, liv = False, pro = "kh", enp = "k"},
    TC {dat = Ck3, uni = 3590, tra = "k3", ccl = Low, liv = False, pro = "kh", enp = "k"},
    TC {dat = Cg,  uni = 3591, tra = "g", ccl = Low, liv = True, pro = i_ng, enp = i_ng},
    TC {dat = Cc,  uni = 3592, tra = "c", ccl = Mid, liv = False, pro = "c", enp = "t"},
    TC {dat = Cc1, uni = 3593, tra = "c1", ccl = High, liv = False, pro = "ch", enp = "t"},
    TC {dat = Cc2, uni = 3594, tra = "c2", ccl = Low, liv = False, pro = "ch", enp = "t"},
    TC {dat = Cs', uni = 3595, tra = "s'", ccl = Low, liv = False, pro = "s", enp = "t"},
    TC {dat = Cc3, uni = 3596, tra = "c3", ccl = Low, liv = False, pro = "ch", enp = "t"},
    TC {dat = Cy', uni = 3597, tra = "y'", ccl = Low, liv = False, pro = "y", enp = "n"},
    TC {dat = Cd', uni = 3598, tra = "d'", ccl = Mid, liv = False, pro = "d", enp = "t"},
    TC {dat = Ct', uni = 3599, tra = "t'", ccl = Mid, liv = False, pro = "t", enp = "t"},
    TC {dat = Ct1, uni = 3600, tra = "t1", ccl = High, liv = False, pro = "th", enp = "t"},
    TC {dat = Ct2, uni = 3601, tra = "t2", ccl = Low, liv = False, pro = "th", enp = "t"},
    TC {dat = Ct3, uni = 3602, tra = "t3", ccl = Low, liv = False, pro = "th", enp = "t"},
    TC {dat = Cn', uni = 3603, tra = "n'", ccl = Low, liv = True, pro = "n", enp = "n"},
    TC {dat = Cd,  uni = 3604, tra = "d", ccl = Mid, liv = False, pro = "d", enp = "t"},
    TC {dat = Ct,  uni = 3605, tra = "t", ccl = Mid, liv = False, pro = "t", enp = "t"},
    TC {dat = Ct4, uni = 3606, tra = "t4", ccl = High, liv = False, pro = "th", enp = "t"},
    TC {dat = Ct5, uni = 3607, tra = "t5", ccl = Low, liv = False, pro = "th", enp = "t"},
    TC {dat = Ct6, uni = 3608, tra = "t6", ccl = Low, liv = False, pro = "th", enp = "t"},
    TC {dat = Cn,  uni = 3609, tra = "n", ccl = Low, liv = True, pro = "n", enp = "n"},
    TC {dat = Cb,  uni = 3610, tra = "b", ccl = Mid, liv = False, pro = "b", enp = "p"},
    TC {dat = Cp,  uni = 3611, tra = "p", ccl = Mid, liv = False, pro = "p", enp = "p"},
    TC {dat = Cp1, uni = 3612, tra = "p1", ccl = High, liv = False, pro = "ph", enp = "p"},
    TC {dat = Cf,  uni = 3613, tra = "f", ccl = High, liv = False, pro = "f", enp = "p"},
    TC {dat = Cp2, uni = 3614, tra = "p2", ccl = Low, liv = False, pro = "ph", enp = "p"},
    TC {dat = Cf', uni = 3615, tra = "f'", ccl = Low, liv = False, pro = "f", enp = "p"},
    TC {dat = Cp3, uni = 3616, tra = "p3", ccl = Low, liv = False, pro = "ph", enp = "p"},
    TC {dat = Cm,  uni = 3617, tra = "m", ccl = Low, liv = True, pro = "m", enp = "m"},
    TC {dat = Cy,  uni = 3618, tra = "y", ccl = Low, liv = True, pro = "y", enp = "y"},
    TC {dat = Cr,  uni = 3619, tra = "r", ccl = Low, liv = True, pro = "r", enp = "n"},
    TC {dat = Cl,  uni = 3621, tra = "l", ccl = Low, liv = True, pro = "l", enp = "n"},
    TC {dat = Cw,  uni = 3623, tra = "w", ccl = Low, liv = True, pro = "w", enp = "w"},
    TC {dat = CsM, uni = 3624, tra = "s-", ccl = High, liv = False, pro = "s", enp = "t"},
    TC {dat = CsP, uni = 3625, tra = "s.", ccl = High, liv = False, pro = "s", enp = "t"},
    TC {dat = Cs,  uni = 3626, tra = "s", ccl = High, liv = False, pro = "s", enp = "t"},
    TC {dat = Ch,  uni = 3627, tra = "h", ccl = High, liv = True, pro = "h", enp = ""},
    TC {dat = Cl,  uni = 3628, tra = "l'", ccl = Low, liv = True, pro = "l", enp = "n"},
    TC {dat = CO,  uni = 3629, tra = "O", ccl = Mid, liv = True, pro = i_OO, enp = i_OO},
    TC {dat = Ch', uni = 3630, tra = "h'", ccl = Low, liv = True, pro = "h", enp = ""},
  
    TC {dat = CaP, uni = 3632, tra = "a.", ccl = Low, liv = False, pro = "a", enp = "a"},
    TC {dat = Ca,  uni = 3633, tra = "a",  ccl = Low, liv = False, pro = "a", enp = "a"},
    TC {dat = CaL, uni = 3634, tra = "a:", ccl = Low, liv = True, pro = "aa", enp = "aa"},
    TC {dat = Cam, uni = 3635, tra = "a+", ccl = Low, liv = True, pro = "am", enp = "am"},
    TC {dat = Ci,  uni = 3636, tra = "i",  ccl = Low, liv = False, pro = "i", enp = "i"},
    TC {dat = CiL, uni = 3637, tra = "i:", ccl = Low, liv = True, pro = "ii", enp = "ii"},
    TC {dat = Cv,  uni = 3638, tra = "v",  ccl = Low, liv = False, pro = i_ue, enp = i_ue},
    TC {dat = CvL, uni = 3639, tra = "v:", ccl = Low, liv = True,  pro = i_uue, enp = i_uue},
    TC {dat = Cu,  uni = 3640, tra = "u",  ccl = Low, liv = False, pro = "u", enp = "u"},
    TC {dat = CuL, uni = 3641, tra = "u:", ccl = Low, liv = True, pro = "uu", enp = "uu"},
    TC {dat = Ce,  uni = 3648, tra = "e",  ccl = Low, liv = True, pro = "ee", enp = "ee"},
    TC {dat = Ce', uni = 3649, tra = "e'", ccl = Low, liv = True, pro = i_aae, enp = i_aae},
    TC {dat = CoL, uni = 3650, tra = "o:", ccl = Low, liv = True, pro = "oo", enp = "oo"},
    TC {dat = CaH, uni = 3651, tra = "a%", ccl = Low, liv = True, pro = "ay", enp = "ay"},
    TC {dat = CaE, uni = 3652, tra = "a&", ccl = Low, liv = True, pro = "ay", enp = "ay"},
    TC {dat = CL,  uni = 3653, tra = "L",  ccl = Low, liv = True, pro = "li", enp = "n"},
    TC {dat = CR,  uni = 3654, tra = "R",  ccl = Low, liv = True, pro = "ri", enp = "n"},
    TC {dat = CS,  uni = 3655, tra = "S",  ccl = Low, liv = True, pro = "", enp = ""},
    TC {dat = CT1, uni = 3656, tra = "T1", ccl = Low, liv = True, pro = "", enp = ""},
    TC {dat = CT2, uni = 3657, tra = "T2", ccl = Low, liv = True, pro = "", enp = ""},
    TC {dat = CT3, uni = 3658, tra = "T3", ccl = Low, liv = True, pro = "", enp = ""},
    TC {dat = CT4, uni = 3659, tra = "T4", ccl = Low, liv = True, pro = "", enp = ""},
    TC {dat = CK,  uni = 3660, tra = "K",  ccl = Low, liv = True, pro = "", enp = ""},
    TC {dat = CN0, uni = 3664, tra = "N0", ccl = Low, liv = False, pro = "0", enp = "0"},
    TC {dat = CN1, uni = 3665, tra = "N1", ccl = Low, liv = False, pro = "1", enp = "1"},
    TC {dat = CN2, uni = 3666, tra = "N2", ccl = Low, liv = False, pro = "2", enp = "2"},
    TC {dat = CN3, uni = 3667, tra = "N3", ccl = Low, liv = False, pro = "3", enp = "3"},
    TC {dat = CN4, uni = 3668, tra = "N4", ccl = Low, liv = False, pro = "4", enp = "4"},
    TC {dat = CN5, uni = 3669, tra = "N5", ccl = Low, liv = False, pro = "5", enp = "5"},
    TC {dat = CN6, uni = 3670, tra = "N6", ccl = Low, liv = False, pro = "6", enp = "6"},
    TC {dat = CN7, uni = 3671, tra = "N7", ccl = Low, liv = False, pro = "7", enp = "7"},
    TC {dat = CN8, uni = 3672, tra = "N8", ccl = Low, liv = False, pro = "8", enp = "8"},
    TC {dat = CN9, uni = 3673, tra = "N9", ccl = Low, liv = False, pro = "9", enp = "9"}
   ]
  
  data ThaiDat =
    Ck  | Ck1 | Ck2 | Ck3 | Cg  | Cc  | Cc1 | Cc2 | Cs' | 
    Cc3 | Cy' | Cd' | Ct' | Ct1 | Ct2 | Ct3 | Cn' | Cd  | 
    Ct  | Ct4 | Ct5 | Ct6 | Cn  | Cb  | Cp  | Cp1 | Cf  | 
    Cp2 | Cf' | Cp3 | Cm  | Cy  | Cr  | Cl  | Cw  | CsM |
    CsP | Cs  | Ch  | Cl' | CO  | Ch' | CaP | Ca  | CaL |
    Cam | Ci  | CiL | Cv  | CvL | Cu  | CuL | Ce  | Ce' |
    CoL | CaH | CaE | CL  | CR  | CS  | CT1 | CT2 | CT3 |
    CT4 | CK  | CN0 | CN1 | CN2 | CN3 | CN4 | CN5 | CN6 |
    CN7 | CN8 | CN9
   deriving (Eq,Ord,Show)
  
  -- testing with Wikipedia Swadesh list
  
  testFile   = "src/test.txt"
  resultFile = "src/results.txt"
  
  test = do
    s <- readFile testFile
    writeFile resultFile []
    mapM_ (testOne . tabs) $ lines s
  
  testOne ws = case ws of
    m:t:p:r:_ -> appendFile resultFile $ concat [mn,"\t",t,"\t",p,"\t",r,"\t",result,"\n"] where
                     result = unwords (intersperse "," (map thai2pron (filter (/=",") (words t))))
                     mn = if result == r 
                        then m
                        else if result == p then (m ++ "+") else (m ++ "-") 
    _ -> return ()
  
  testOneS ws = case ws of
    m:t:p:r:_ -> appendFile resultFile $ concat [m,"\t",t,"\t",pn,"\t",r,"\n"] where
                     result = unwords (intersperse "," (map thai2pron (filter (/=",") (words t))))
                     pn = if m == "+" 
                        then r
                        else p
    _ -> return ()
  
  tabs s = case break (=='\t') s of
    ([], _:ws) -> tabs ws
    (w , _:ws) -> w:tabs ws
    _ -> [s]
  
  
  -- heuristics for finding syllables - unreliable, unfinished
  uniSyllables :: [ThaiDat] -> [[ThaiDat]]
  uniSyllables = reverse . (syll [] []) where
    syll sys sy is = case is of
      c:cs | isPreVowel c -> new [] is
      c:d:cs | isConsonant c && isConsonant d -> new [c] (d:cs) ---- no consonant clusters
      c:cs -> continue [c] cs ---- more rules to follow 
      _ -> sy:sys
     where
      new old = syll ((sy ++ old) : sys) []
      continue old = syll sys (sy ++ old)
  
  
  