-- |
-- Module      : Data.Unicode.Properties.Decompose
-- Copyright   : (c) 2016 Harendra Kumar
--
-- License     : BSD-style
-- Maintainer  : harendra.kumar@gmail.com
-- Stability   : experimental
--
module Data.Unicode.Properties.Decompose
    ( decomposeChar
    , decomposeCharHangul
    , DecomposeMode(..)
    , DecomposeResult(..)
    , isHangul
    , jamoLFirst
    , isDecomposable
    )
where

import           Data.BitArray                           (BitArray, lookupBit)
import           Data.Char                               (ord)

import qualified Data.Unicode.Properties.Decomposable    as D
import qualified Data.Unicode.Properties.DecomposableK   as K
import           Data.Unicode.Properties.DecomposeHangul ( decomposeCharHangul
                                                         , jamoLFirst
                                                         , isHangul)
import qualified Data.Unicode.Properties.Decompositions  as D
import qualified Data.Unicode.Properties.DecompositionsK as K

data DecomposeMode = DecomposeNFD | DecomposeNFKD

{-# INLINE decomposeChar #-}
decomposeChar :: DecomposeMode -> Char -> [Char]
decomposeChar :: DecomposeMode -> Char -> [Char]
decomposeChar DecomposeNFD  = Char -> [Char]
D.decomposeChar
decomposeChar DecomposeNFKD = Char -> [Char]
K.decomposeChar

{-# INLINE decomposeMin #-}
decomposeMin :: DecomposeMode -> Int
decomposeMin :: DecomposeMode -> Int
decomposeMin DecomposeNFD  = Int
D.decomposeMin
decomposeMin DecomposeNFKD = Int
K.decomposeMin

{-# INLINE decomposeMax #-}
decomposeMax :: DecomposeMode -> Int
decomposeMax :: DecomposeMode -> Int
decomposeMax DecomposeNFD  = Int
D.decomposeMax
decomposeMax DecomposeNFKD = Int
K.decomposeMax

{-# INLINE decomposeBitmap #-}
decomposeBitmap :: DecomposeMode -> BitArray
decomposeBitmap :: DecomposeMode -> BitArray
decomposeBitmap DecomposeNFD  = BitArray
D.decomposeBitmap
decomposeBitmap DecomposeNFKD = BitArray
K.decomposeBitmap

-- Hack Alert!
-- When we return just True and False GHC refactors the code to combine two
-- False or True results in a common function call and therefore not inlining
-- the code. To avoid that we return different results even though they
-- semantically mean the same thing.
--
data DecomposeResult = FalseA | FalseB | FalseC | TrueA

{-# INLINE isDecomposable #-}
isDecomposable :: DecomposeMode -> Char -> DecomposeResult
isDecomposable :: DecomposeMode -> Char -> DecomposeResult
isDecomposable mode :: DecomposeMode
mode c :: Char
c | (Char -> Int
ord Char
c) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<  DecomposeMode -> Int
decomposeMin DecomposeMode
mode = DecomposeResult
FalseA
isDecomposable mode :: DecomposeMode
mode c :: Char
c | (Char -> Int
ord Char
c) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= DecomposeMode -> Int
decomposeMax DecomposeMode
mode =
    case BitArray -> Int -> Bool
lookupBit (DecomposeMode -> BitArray
decomposeBitmap DecomposeMode
mode) (Char -> Int
ord Char
c) of
      True -> DecomposeResult
TrueA
      False -> DecomposeResult
FalseB
isDecomposable _ _ = DecomposeResult
FalseC