{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE CPP #-}
module Graphics.Text.TrueType.LanguageIds
    ( PlatformId( .. )
    , UnicodePlatformSpecific( .. )
    , MacPlatformId( .. )
    , MacLanguage( .. )
    , platformToWord
    , unicodePlatformSpecificToId
    ) where

#if !MIN_VERSION_base(4,8,0)
import Control.Applicative( (<$>) )
#endif

import Data.Binary( Binary( .. ) )
import Data.Binary.Get( getWord16be )
import Data.Binary.Put( putWord16be )
import Data.Word( Word16 )
import qualified Data.Map.Strict as M

-- Note [PlatformID sorting]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- Unicode and Windows are the two preferred encodings according to Apple's
-- documentation. Indeed some fonts (e.g., Bitstream Vera Mono) return the wrong
-- glyphs if we use Macintosh encoding instead of Windows one.
--
-- To fix this, the Ord instance for PlatformId ensures that:
--    Unicode < Windows < Macintosh
-- 

data PlatformId
    = PlatformUnicode   -- ^ 0 Don't change the ordering (see Note [PlatformID sorting])
    | PlatformWindows   -- ^ 3 
    | PlatformMacintosh -- ^ 1
    | PlatformISO       -- ^ 2
    | PlatformCustom    -- ^ 4
    | PlatformId Word16
    deriving (Eq, Ord, Show)

instance Binary PlatformId where
    put = putWord16be . platformToWord
    get = do
      val <- getWord16be
      return $ case val of
        0 -> PlatformUnicode
        1 -> PlatformMacintosh
        2 -> PlatformISO
        3 -> PlatformWindows
        4 -> PlatformCustom
        n -> PlatformId n

platformToWord :: PlatformId -> Word16
platformToWord = p where
  p PlatformUnicode = 0
  p PlatformMacintosh = 1
  p PlatformISO = 2
  p PlatformWindows = 3
  p PlatformCustom = 4
  p (PlatformId v) = v

data UnicodePlatformSpecific
    = UnicodePlatform1_0
    | UnicodePlatform1_1
    | UnicodeISO10645
    | UnicodeBMPOnly2_0
    | UnicodeFull2_0
    | UnicodeVariation
    | UnicodeFull
    deriving (Eq, Show)

unicodePlatformSpecificToId :: UnicodePlatformSpecific -> Word16
unicodePlatformSpecificToId = go
  where
    go UnicodePlatform1_0 = 0
    go UnicodePlatform1_1 = 1
    go UnicodeISO10645    = 2
    go UnicodeBMPOnly2_0  = 3
    go UnicodeFull2_0     = 4
    go UnicodeVariation   = 5
    go UnicodeFull        = 6

instance Binary UnicodePlatformSpecific where
    put = putWord16be . unicodePlatformSpecificToId

    get = do
       v <- getWord16be
       return $ case v of
          0 -> UnicodePlatform1_0
          1 -> UnicodePlatform1_1
          2 -> UnicodeISO10645
          3 -> UnicodeBMPOnly2_0
          4 -> UnicodeFull2_0
          5 -> UnicodeVariation
          6 -> UnicodeFull
          _ -> UnicodeFull

data MacPlatformId
   = MacSpecificRoman
   | MacSpecificJapanese
   | MacSpecificChineseTraditional
   | MacSpecificKorean
   | MacSpecificArabic
   | MacSpecificHebrew
   | MacSpecificGreek
   | MacSpecificRussian
   | MacSpecificRSymbol
   | MacSpecificDevanagari
   | MacSpecificGurmukhi
   | MacSpecificGujarati
   | MacSpecificOriya
   | MacSpecificBengali
   | MacSpecificTamil
   | MacSpecificTelugu
   | MacSpecificKannada
   | MacSpecificMalayalam
   | MacSpecificSinhalese
   | MacSpecificBurmese
   | MacSpecificKhmer
   | MacSpecificThai
   | MacSpecificLaotian
   | MacSpecificGeorgian
   | MacSpecificArmenian
   | MacSpecificChineseSimplified
   | MacSpecificTibetan
   | MacSpecificMongolian
   | MacSpecificGeez
   | MacSpecificSlavic
   | MacSpecificVietnamese
   | MacSpecificSindhi
   | MacSpecificUninterpreted
   deriving (Eq, Ord, Show)

macSpecifcIdList :: [MacPlatformId]
macSpecifcIdList =
    [ MacSpecificRoman, MacSpecificJapanese, MacSpecificChineseTraditional
    , MacSpecificKorean, MacSpecificArabic, MacSpecificHebrew
    , MacSpecificGreek, MacSpecificRussian, MacSpecificRSymbol
    , MacSpecificDevanagari, MacSpecificGurmukhi, MacSpecificGujarati
    , MacSpecificOriya, MacSpecificBengali, MacSpecificTamil
    , MacSpecificTelugu, MacSpecificKannada, MacSpecificMalayalam
    , MacSpecificSinhalese, MacSpecificBurmese, MacSpecificKhmer
    , MacSpecificThai, MacSpecificLaotian, MacSpecificGeorgian
    , MacSpecificArmenian, MacSpecificChineseSimplified, MacSpecificTibetan
    , MacSpecificMongolian, MacSpecificGeez, MacSpecificSlavic
    , MacSpecificVietnamese, MacSpecificSindhi, MacSpecificUninterpreted
    ]


prepareSpecificMaps :: Ord a => [a] -> (M.Map a Word16, M.Map Word16 a)
prepareSpecificMaps lst = (toWord, toPlatform)
  where
    toWord = M.fromList $ zip lst [0 ..]
    toPlatform = M.fromList $ zip [0 ..] lst

mapSpecifcIdMaps :: ( M.Map MacPlatformId Word16
                    , M.Map Word16 MacPlatformId )
mapSpecifcIdMaps = prepareSpecificMaps macSpecifcIdList

instance Binary MacPlatformId where
    get = finder <$> getWord16be
      where
        (_, to) = mapSpecifcIdMaps
        finder v = M.findWithDefault MacSpecificUninterpreted v to

    put v = putWord16be val
      where
        (from, _) = mapSpecifcIdMaps
        val = M.findWithDefault 32 v from

data MacLanguage
    = MacLangEnglish
    | MacLangFrench
    | MacLangGerman
    | MacLangItalian
    | MacLangDutch
    | MacLangSwedish
    | MacLangSpanish
    | MacLangDanish
    | MacLangPortuguese
    | MacLangNorwegian
    | MacLangHebrew
    | MacLangJapanese
    | MacLangArabic
    | MacLangFinnish
    | MacLangGreek
    | MacLangInuktitut
    | MacLangIcelandic
    | MacLangMaltese
    | MacLangTurkish
    | MacLangCroatian
    | MacLangChineseTraditional
    | MacLangUrdu
    | MacLangHindi
    | MacLangThai
    | MacLangKorean
    | MacLangLithuanian
    | MacLangPolish
    | MacLangHungarian
    | MacLangEstonian
    | MacLangLatvian
    | MacLangSami
    | MacLangFaroese
    | MacLangFarsiPersian
    | MacLangRussian
    | MacLangChineseSimplified
    | MacLangFlemish
    | MacLangIrishGaelic
    | MacLangAlbanian
    | MacLangRomanian
    | MacLangCzech
    | MacLangSlovak
    | MacLangSlovenian
    | MacLangYiddish
    | MacLangSerbian
    | MacLangMacedonian
    | MacLangBulgarian
    | MacLangUkrainian
    | MacLangByelorussian
    | MacLangUzbek
    | MacLangKazakh
    | MacLangAzerbaijaniCyrillic
    | MacLangAzerbaijaniArabic
    | MacLangArmenian
    | MacLangGeorgian
    | MacLangMoldavian
    | MacLangKirghiz
    | MacLangTajiki
    | MacLangTurkmen
    | MacLangMongolian
    | MacLangMongolianCyrillic
    | MacLangPashto
    | MacLangKurdish
    | MacLangKashmiri
    | MacLangSindhi
    | MacLangTibetan
    | MacLangNepali
    | MacLangSanskrit
    | MacLangMarathi
    | MacLangBengali
    | MacLangAssamese
    | MacLangGujarati
    | MacLangPunjabi
    | MacLangOriya
    | MacLangMalayalam
    | MacLangKannada
    | MacLangTamil
    | MacLangTelugu
    | MacLangSinhalese
    | MacLangBurmese
    | MacLangKhmer
    | MacLangLao
    | MacLangVietnamese
    | MacLangIndonesian
    | MacLangTagalong
    | MacLangMalayRoman
    | MacLangMalayArabic
    | MacLangAmharic
    | MacLangTigrinya
    | MacLangGalla
    | MacLangSomali
    | MacLangSwahili
    | MacLangKinyarwandaRuanda
    | MacLangRundi
    | MacLangNyanjaChewa
    | MacLangMalagasy
    | MacLangEsperanto
    | MacLangWelsh
    | MacLangBasque
    | MacLangCatalan
    | MacLangLatin
    | MacLangQuenchua
    | MacLangGuarani
    | MacLangAymara
    | MacLangTatar
    | MacLangUighur
    | MacLangDzongkha
    | MacLangJavanese
    | MacLangSundanese
    | MacLangGalician
    | MacLangAfrikaans
    | MacLangBreton
    | MacLangScottishGaelic
    | MacLangManxGaelic
    | MacLangIrishGaelicWithDot
    | MacLangTongan
    | MacLangGreekPolytonic
    | MacLangGreenlandic
    | MacLangAzerbaijani
    deriving (Eq, Ord, Show)

macLangList :: [MacLanguage]
macLangList =
    [ MacLangEnglish , MacLangFrench , MacLangGerman , MacLangItalian
    , MacLangDutch , MacLangSwedish , MacLangSpanish , MacLangDanish
    , MacLangPortuguese , MacLangNorwegian , MacLangHebrew , MacLangJapanese
    , MacLangArabic , MacLangFinnish , MacLangGreek , MacLangInuktitut
    , MacLangIcelandic , MacLangMaltese , MacLangTurkish , MacLangCroatian
    , MacLangChineseTraditional , MacLangUrdu , MacLangHindi , MacLangThai
    , MacLangKorean , MacLangLithuanian , MacLangPolish , MacLangHungarian
    , MacLangEstonian , MacLangLatvian , MacLangSami , MacLangFaroese
    , MacLangFarsiPersian , MacLangRussian , MacLangChineseSimplified
    , MacLangFlemish
    , MacLangIrishGaelic , MacLangAlbanian , MacLangRomanian , MacLangCzech
    , MacLangSlovak , MacLangSlovenian , MacLangYiddish , MacLangSerbian
    , MacLangMacedonian , MacLangBulgarian , MacLangUkrainian , MacLangByelorussian
    , MacLangUzbek , MacLangKazakh , MacLangAzerbaijaniCyrillic
    , MacLangAzerbaijaniArabic
    , MacLangArmenian , MacLangGeorgian , MacLangMoldavian , MacLangKirghiz
    , MacLangTajiki , MacLangTurkmen , MacLangMongolian , MacLangMongolianCyrillic
    , MacLangPashto , MacLangKurdish , MacLangKashmiri , MacLangSindhi
    , MacLangTibetan , MacLangNepali , MacLangSanskrit , MacLangMarathi
    , MacLangBengali , MacLangAssamese , MacLangGujarati , MacLangPunjabi
    , MacLangOriya , MacLangMalayalam , MacLangKannada , MacLangTamil
    , MacLangTelugu , MacLangSinhalese , MacLangBurmese , MacLangKhmer
    , MacLangLao , MacLangVietnamese , MacLangIndonesian , MacLangTagalong
    , MacLangMalayRoman , MacLangMalayArabic , MacLangAmharic , MacLangTigrinya
    , MacLangGalla , MacLangSomali , MacLangSwahili , MacLangKinyarwandaRuanda
    , MacLangRundi , MacLangNyanjaChewa , MacLangMalagasy , MacLangEsperanto
    , MacLangWelsh , MacLangBasque , MacLangCatalan , MacLangLatin
    , MacLangQuenchua , MacLangGuarani , MacLangAymara , MacLangTatar
    , MacLangUighur , MacLangDzongkha , MacLangJavanese , MacLangSundanese
    , MacLangGalician , MacLangAfrikaans , MacLangBreton , MacLangScottishGaelic
    , MacLangManxGaelic , MacLangIrishGaelicWithDot , MacLangTongan
    , MacLangGreekPolytonic , MacLangGreenlandic , MacLangAzerbaijani
    ]

mapLangIdMaps :: (M.Map MacLanguage Word16, M.Map Word16 MacLanguage)
mapLangIdMaps = prepareSpecificMaps macLangList

instance Binary MacLanguage where
    get = finder <$> getWord16be
      where
        (_, to) = mapLangIdMaps
        finder v = M.findWithDefault MacLangEnglish v to

    put v = putWord16be val
      where
        (from, _) = mapLangIdMaps
        val = M.findWithDefault 0 v from