-- | Module to generate the config file
module Transformer (
  generateConfigFile
) where

import PhoneNumberMetadata
import Text.XML.HXT.Core hiding (removeWhiteSpace)
import Data.Text ( pack
                 , unpack
                 , toLower)

-- * Pickler-Unpicklers for Phone number types defined in 'Phone'

instance XmlPickler PhoneNumberMetadata where
  xpickle  = xpPhoneNumberMetadata

instance XmlPickler Territory where
  xpickle  = xpTerritory

instance XmlPickler NumberFormat where
  xpickle = xpNumberFormat

xpPhoneNumberMetadata :: PU PhoneNumberMetadata
xpPhoneNumberMetadata =
  xpElem "phoneNumberMetadata" $
  xpWrap (\ts -> PhoneNumberMetadata ts,
          \p  -> territories p)
  (xpElem "territories" (xpList xpTerritory))

xpTerritory :: PU Territory
xpTerritory =
  xpElem "territory" $
  xpWrap (territoryPickler, territoryUnpickler) $
  xpTerritoryTuples

xpNumberFormat :: PU NumberFormat
xpNumberFormat =
  xpElem   "numberFormat" $
  xpWrap   (numberFormatPickler, numberFormatUnPickler) $
  xp8Tuple (xpOption (xpAttr         "nationalPrefixFormattingRule"         xpText))
           (xpOption (xpAttr         "nationalPrefixOptionalWhenFormatting" xpText))
           (xpOption (xpAttr         "carrierCodeFormattingRule"            xpText))
           (xpAttr                   "pattern"                              xpText)
           (xpOption (xpAttr         "leadingZeroPossible"                  xpText))
           (xpOption (xpList (xpElem "leadingDigits"                        xpText)))
           (xpElem                   "format"                               xpText)
           (xpOption (xpList (xpElem "intlFormat"                           xpText)))

xpPhoneNumberPatterns patternType =
  xpElem patternType $
  xpWrap (\(ptype, np, pp, e) -> PhoneNumberPatterns ptype (removeWhiteSpace <$> np) (removeWhiteSpace <$> pp) e,
         \pnp -> ( phoneNumberType pnp
                 , nationalNumberPattern pnp
                 , possibleNumberPattern pnp
                 , exampleNumber pnp
                 )) $
  xp4Tuple (xpDefault patternType xpText)
           (xpOption (xpElem "nationalNumberPattern" xpText))
           (xpOption (xpElem "possibleNumberPattern" xpText))
           (xpOption (xpElem "exampleNumber"         xpText))

numberFormatPickler (npfr,         npowf, ccfr, p,         lzp, ld, f, intlf) =
  NumberFormat       npfr  (toBool npowf) ccfr  p  (toBool lzp) ((fmap removeWhiteSpace) <$> ld)  f  intlf

numberFormatUnPickler nf =
  (
  nfNationalPrefixFormattingRule                    nf,
  fromBool $ nfNationalPrefixOptionalWhenFormatting nf,
  nfCarrierCodeFormattingRule                       nf,
  nfPattern                                         nf,
  fromBool $ nfLeadingZeroPossible                  nf,
  nfLeadingDigits                                   nf,
  nfFormat                                          nf,
  nfInternationalFormat                             nf
  )


xpTerritoryTuples =
  xp30Tuple(         xpAttr                "id"                                         xpText )
           (         xpAttr                "countryCode"                                xpText )
           (xpOption(xpAttr                "mainCountryForCode"                         xpText ))
           (xpOption(xpAttr                "leadingDigits"                              xpText ))
           (xpOption(xpAttr                "preferredInternationalPrefix"               xpText ))
           (xpOption(xpAttr                "internationalPrefix"                        xpText ))
           (xpOption(xpAttr                "nationalPrefix"                             xpText ))
           (xpOption(xpAttr                "nationalPrefixForParsing"                   xpText ))
           (xpOption(xpAttr                "nationalPrefixTransformRule"                xpText ))
           (xpOption(xpAttr                "preferredExtnPrefix"                        xpText ))
           (xpOption(xpAttr                "nationalPrefixFormattingRule"               xpText ))
           (xpOption(xpAttr                "nationalPrefixOptionalWhenFormatting"       xpText ))
           (xpOption(xpAttr                "leadingZeroPossible"                        xpText ))
           (xpOption(xpAttr                "carrierCodeFormattingRule"                  xpText ))
           (xpOption(xpAttr                "mobileNumberPortableRegion"                 xpText ))
           (xpElem                         "references" (xpList (xpElem "sourceUrl"     xpText )))
           (xpOption(xpElem                "availableFormats" (xpList xpNumberFormat)))
           (xpOption(xpPhoneNumberPatterns "generalDesc"))
           (xpOption(xpPhoneNumberPatterns "noInternationalDialling"))
           (xpOption(xpPhoneNumberPatterns "areaCodeOptional"))
           (xpOption(xpPhoneNumberPatterns "fixedLine"))
           (xpOption(xpPhoneNumberPatterns "mobile"))
           (xpOption(xpPhoneNumberPatterns "pager"))
           (xpOption(xpPhoneNumberPatterns "tollFree"))
           (xpOption(xpPhoneNumberPatterns "premiumRate"))
           (xpOption(xpPhoneNumberPatterns "sharedCost"))
           (xpOption(xpPhoneNumberPatterns "personalNumber"))
           (xpOption(xpPhoneNumberPatterns "voip"))
           (xpOption(xpPhoneNumberPatterns "uan"))
           (xpOption(xpPhoneNumberPatterns "voicemail"))

territoryPickler
  ( abbreviation
  , countryCode
  , mainCountryForCode
  , leadingDigits
  , preferredInternationalPrefix
  , internationalPrefix
  , nationalPrefix
  , nationalPrefixForParsing
  , nationalPrefixTransformRule
  , preferredExtensionPrefix
  , nationalPrefixFormattingRule
  , nationalPrefixOptionalWhenFormatting
  , leadingZeroPossible
  , carrierCodeFormattingRule
  , mobileNumberPortableRegion
  , references
  , availableFormats
  , generalDescription
  , noInternationalDialling
  , areaCodeOptional
  , fixedLine
  , mobile
  , pager
  , tollFree
  , premiumRate
  , sharedCost
  , personalNumber
  , voip
  , uan
  , voicemail
  )  = Territory
  abbreviation
  countryCode
  ( toBool mainCountryForCode )
  leadingDigits
  preferredInternationalPrefix
  internationalPrefix
  nationalPrefix
  nationalPrefixForParsing
  nationalPrefixTransformRule
  preferredExtensionPrefix
  nationalPrefixFormattingRule
  ( toBool nationalPrefixOptionalWhenFormatting )
  ( toBool leadingZeroPossible )
  carrierCodeFormattingRule
  ( toBool mobileNumberPortableRegion )
  references
  availableFormats
  generalDescription
  noInternationalDialling
  areaCodeOptional
  fixedLine
  mobile
  pager
  tollFree
  premiumRate
  sharedCost
  personalNumber
  voip
  uan
  voicemail

territoryUnpickler t =
  ( abbreviation t
  , countryCode t
  , fromBool $ mainCountryForCode t
  , leadingDigits t
  , preferredInternationalPrefix t
  , internationalPrefix t
  , nationalPrefix t
  , nationalPrefixForParsing t
  , nationalPrefixTransformRule t
  , preferredExtensionPrefix t
  , nationalPrefixFormattingRule t
  , fromBool $ nationalPrefixOptionalWhenFormatting t
  , fromBool $ leadingZeroPossible t
  , carrierCodeFormattingRule t
  , fromBool $ mobileNumberPortableRegion t
  , references t
  , availableFormats t
  , generalDescription t
  , noInternationalDialling t
  , areaCodeOptional t
  , fixedLine t
  , mobile t
  , pager t
  , tollFree t
  , premiumRate t
  , sharedCost t
  , personalNumber t
  , voip t
  , uan t
  , voicemail t
  )

toBool :: Maybe String -> Maybe Bool
toBool ( Just "true" ) = Just True
toBool ( Just "false" ) = Just False
toBool _ = Nothing

fromBool :: Maybe Bool -> Maybe String
fromBool ( Just x )  = Just ((unpack . toLower . pack . show) x)
fromBool Nothing = Nothing

removeWhiteSpace :: String -> String
removeWhiteSpace = concat . words

generateConfigFile = do
  runX (xunpickleDocument xpPhoneNumberMetadata
      [ withValidate no
      , withTrace 1
      , withRemoveWS yes
      , withPreserveComment no
      ] "config/phoneNumberMetadata.xml"
    >>>
      processXML
     )
  return ()

processXML :: IOSArrow PhoneNumberMetadata PhoneNumberMetadata
processXML =  arrIO (\x -> do {
 writeFile "config/phoneNumberMetadata.hs" $ show x;
 return x;
})

-- | HXT defines tuples upto 24 elements ('xp24Tuple').
-- We need a 30-tuple to handle all our attributes & elements of 'Territory'
xp30Tuple :: PU a  -> PU b -> PU c -> PU d -> PU e ->
             PU f  -> PU g -> PU h -> PU i -> PU j ->
             PU k  -> PU l -> PU m -> PU n -> PU o ->
             PU p  -> PU q -> PU r -> PU s -> PU t ->
             PU u  -> PU v -> PU w -> PU x -> PU aa ->
             PU bb -> PU cc -> PU dd -> PU ee -> PU ff ->
             PU ( a, b, c, d, e, f
                , g, h, i, j, k, l
                , m, n, o, p, q, r
                , s, t, u, v, w, x
                , aa, bb, cc, dd, ee, ff)
xp30Tuple a b c d e f g h i j k l m n o p q r s t u v w x aa bb cc dd ee ff =
  xpWrap (\( (a, b, c, d, e, f)
   , (g, h, i, j, k, l)
   , (m, n, o, p, q, r)
   , (s, t, u, v, w, x)
   , (aa, bb, cc, dd, ee, ff)) ->
   (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, aa, bb, cc, dd, ee, ff),
   \(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, aa, bb, cc, dd, ee, ff) ->
      ( (a, b, c, d, e, f)
      , (g, h, i, j, k, l)
      , (m, n, o, p, q, r)
      , (s, t, u, v, w, x)
      , (aa, bb, cc, dd, ee, ff))
   ) $
  (xp5Tuple
   (xp6Tuple a b c d e f)
   (xp6Tuple g h i j k l)
   (xp6Tuple m n o p q r)
   (xp6Tuple s t u v w x)
   (xp6Tuple aa bb cc dd ee ff))