{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}

module Continent
  ( Continent
  , pattern Africa
  , pattern Asia
  , pattern Antarctica
  , pattern Europe
  , pattern NorthAmerica
  , pattern Oceania
  , pattern SouthAmerica
  -- * Continent Mapping
  , continent
  -- * Name
  , encodeEnglish
  , decodeEnglish
  -- * Two-letter Codes
  , alphaUpper
  , alphaLower
  , decodeAlpha
  ) where

import Continent.Unsafe

import Control.Monad (forM_)
import Control.Monad.ST (runST)
import Country.Unexposed.Continents (continentAList)
import Country.Unexposed.Util (mapTextArray,charToWord8,word16ToInt,timesTwo)
import Country.Unsafe (Country(Country))
import Data.Char (toLower)
import Data.Text (Text)
import Data.Word (Word8)

import qualified Data.Primitive as Prim
import qualified Data.Text as T
import qualified Data.Text.Array as TA
import qualified Data.Text.Internal as TI


numberOfContinents :: Int
numberOfContinents :: Int
numberOfContinents = forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Word8, Text, (Char, Char))]
continentNameDb
{-# NOINLINE numberOfContinents #-}


alphaUpper :: Continent -> Text
alphaUpper :: Continent -> Text
alphaUpper (Continent Word8
n) = Array -> Int -> Int -> Text
TI.text Array
allAlphaUpper (Int -> Int
timesTwo (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
n)) Int
2

allAlphaUpper :: TA.Array
allAlphaUpper :: Array
allAlphaUpper = (forall s. ST s (MArray s)) -> Array
TA.run forall a b. (a -> b) -> a -> b
$ do
  MArray s
m <- forall s. Int -> ST s (MArray s)
TA.new (Int -> Int
timesTwo Int
numberOfContinents)
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(Word8, Text, (Char, Char))]
continentNameDb forall a b. (a -> b) -> a -> b
$ \(Word8
n,Text
_,(Char
a1,Char
a2)) -> do
    let ix :: Int
ix = Int -> Int
timesTwo (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
n)
    forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
m Int
ix (Char -> Word8
charToWord8 Char
a1)
    forall s. MArray s -> Int -> Word8 -> ST s ()
TA.unsafeWrite MArray s
m (Int
ix forall a. Num a => a -> a -> a
+ Int
1) (Char -> Word8
charToWord8 Char
a2)
  forall (m :: * -> *) a. Monad m => a -> m a
return MArray s
m
{-# NOINLINE allAlphaUpper #-}

alphaLower :: Continent -> Text
alphaLower :: Continent -> Text
alphaLower (Continent Word8
n) = Array -> Int -> Int -> Text
TI.text Array
allAlphaLower (Int -> Int
timesTwo (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
n)) Int
2

allAlphaLower :: TA.Array
allAlphaLower :: Array
allAlphaLower = (Char -> Char) -> Array -> Array
mapTextArray Char -> Char
toLower Array
allAlphaUpper
{-# NOINLINE allAlphaLower #-}

decodeAlpha :: Text -> Maybe Continent
decodeAlpha :: Text -> Maybe Continent
decodeAlpha = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Word8 -> Continent
Continent forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [(Text, Word8)]
tbl forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.toUpper
  where tbl :: [(Text, Word8)]
tbl = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. (a -> b) -> [a] -> [b]
map [(Word8, Text, (Char, Char))]
continentNameDb forall a b. (a -> b) -> a -> b
$ \(Word8
n,Text
_,(Char
a,Char
b)) -> ((Text -> Text
T.toUpper forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack) [Char
a,Char
b], Word8
n)

encodeEnglish :: Continent -> Text
encodeEnglish :: Continent -> Text
encodeEnglish (Continent Word8
n) = forall a. Array a -> Int -> a
Prim.indexArray Array Text
englishContinentNamesText (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
n)

englishContinentNamesText :: Prim.Array Text
englishContinentNamesText :: Array Text
englishContinentNamesText = forall a. (forall s. ST s a) -> a
runST forall a b. (a -> b) -> a -> b
$ do
  MutableArray s Text
m <- forall (m :: * -> *) a.
PrimMonad m =>
Int -> a -> m (MutableArray (PrimState m) a)
Prim.newArray Int
numberOfContinents Text
unnamed
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\(Word8
ix,Text
name,(Char, Char)
_) -> forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
Prim.writeArray MutableArray s Text
m (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
ix) Text
name) [(Word8, Text, (Char, Char))]
continentNameDb
  forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> m (Array a)
Prim.unsafeFreezeArray MutableArray s Text
m
{-# NOINLINE englishContinentNamesText #-}

decodeEnglish :: Text -> Maybe Continent
decodeEnglish :: Text -> Maybe Continent
decodeEnglish = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Word8 -> Continent
Continent forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [(Text, Word8)]
tbl
  where tbl :: [(Text, Word8)]
tbl = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. (a -> b) -> [a] -> [b]
map [(Word8, Text, (Char, Char))]
continentNameDb forall a b. (a -> b) -> a -> b
$ \(Word8
n,Text
name,(Char, Char)
_) -> (Text
name, Word8
n)

continent :: Country -> Continent
continent :: Country -> Continent
continent (Country Word16
n) = Word8 -> Continent
Continent forall a b. (a -> b) -> a -> b
$ forall a. Array a -> Int -> a
Prim.indexArray Array Word8
allContinents (Word16 -> Int
word16ToInt Word16
n)

allContinents :: Prim.Array Word8
allContinents :: Array Word8
allContinents = forall a. (forall s. ST s a) -> a
runST forall a b. (a -> b) -> a -> b
$ do
  MutableArray s Word8
m <- forall (m :: * -> *) a.
PrimMonad m =>
Int -> a -> m (MutableArray (PrimState m) a)
Prim.newArray Int
numberOfPossibleCodes Word8
255
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(Word16, Continent)]
continentAList forall a b. (a -> b) -> a -> b
$ \(Word16
ix,Continent Word8
n) ->
    forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> Int -> a -> m ()
Prim.writeArray MutableArray s Word8
m (Word16 -> Int
word16ToInt Word16
ix) Word8
n
  forall (m :: * -> *) a.
PrimMonad m =>
MutableArray (PrimState m) a -> m (Array a)
Prim.unsafeFreezeArray MutableArray s Word8
m
{-# NOINLINE allContinents #-}

unnamed :: Text
unnamed :: Text
unnamed = Text
"Invalid Continent"
{-# NOINLINE unnamed #-}

numberOfPossibleCodes :: Int
numberOfPossibleCodes :: Int
numberOfPossibleCodes = Int
1000