module Distribution.Types.ForeignLib(
    ForeignLib(..),
    emptyForeignLib,
    foreignLibModules,
    foreignLibIsShared,
    foreignLibVersion,
    LibVersionInfo,
    mkLibVersionInfo,
    libVersionInfoCRA,
    libVersionNumber,
    libVersionNumberShow,
    libVersionMajor
) where
import Prelude ()
import Distribution.Compat.Prelude
import Distribution.ModuleName
import Distribution.Version
import Distribution.System
import Distribution.Text
import qualified Distribution.Compat.ReadP as Parse
import Distribution.Types.BuildInfo
import Distribution.Types.ForeignLibType
import Distribution.Types.ForeignLibOption
import Distribution.Types.UnqualComponentName
import qualified Text.PrettyPrint as Disp
import qualified Text.Read as Read
data ForeignLib = ForeignLib {
      
      foreignLibName       :: UnqualComponentName
      
    , foreignLibType       :: ForeignLibType
      
      
    , foreignLibOptions    :: [ForeignLibOption]
      
    , foreignLibBuildInfo  :: BuildInfo
      
      
      
    , foreignLibVersionInfo :: Maybe LibVersionInfo
      
    , foreignLibVersionLinux :: Maybe Version
      
      
      
      
    , foreignLibModDefFile :: [FilePath]
    }
    deriving (Generic, Show, Read, Eq, Typeable, Data)
data LibVersionInfo = LibVersionInfo Int Int Int deriving (Data, Eq, Generic, Typeable)
instance Ord LibVersionInfo where
    LibVersionInfo c r _ `compare` LibVersionInfo c' r' _ =
        case c `compare` c' of
            EQ -> r `compare` r'
            e  -> e
instance Show LibVersionInfo where
    showsPrec d (LibVersionInfo c r a) = showParen (d > 10)
        $ showString "mkLibVersionInfo "
        . showsPrec 11 (c,r,a)
instance Read LibVersionInfo where
    readPrec = Read.parens $ do
        Read.Ident "mkLibVersionInfo" <- Read.lexP
        t <- Read.step Read.readPrec
        return (mkLibVersionInfo t)
instance Binary LibVersionInfo
instance Text LibVersionInfo where
    disp (LibVersionInfo c r a)
      = Disp.hcat $ Disp.punctuate (Disp.char ':') $ map Disp.int [c,r,a]
    parse = do
        c <- parseNat
        (r, a) <- Parse.option (0,0) $ do
            _ <- Parse.char ':'
            r <- parseNat
            a <- Parse.option 0 (Parse.char ':' >> parseNat)
            return (r, a)
        return $ mkLibVersionInfo (c,r,a)
      where
        parseNat = read `fmap` Parse.munch1 isDigit
mkLibVersionInfo :: (Int, Int, Int) -> LibVersionInfo
mkLibVersionInfo (c,r,a) = LibVersionInfo c r a
libVersionInfoCRA :: LibVersionInfo -> (Int, Int, Int)
libVersionInfoCRA (LibVersionInfo c r a) = (c,r,a)
libVersionNumber :: LibVersionInfo -> (Int, Int, Int)
libVersionNumber (LibVersionInfo c r a) = (ca , a , r)
libVersionNumberShow :: LibVersionInfo -> String
libVersionNumberShow v =
    let (major, minor, build) = libVersionNumber v
    in show major ++ "." ++ show minor ++ "." ++ show build
libVersionMajor :: LibVersionInfo -> Int
libVersionMajor (LibVersionInfo c _ a) = ca
instance Binary ForeignLib
instance Semigroup ForeignLib where
  a <> b = ForeignLib {
      foreignLibName         = combine'  foreignLibName
    , foreignLibType         = combine   foreignLibType
    , foreignLibOptions      = combine   foreignLibOptions
    , foreignLibBuildInfo    = combine   foreignLibBuildInfo
    , foreignLibVersionInfo  = combine'' foreignLibVersionInfo
    , foreignLibVersionLinux = combine'' foreignLibVersionLinux
    , foreignLibModDefFile   = combine   foreignLibModDefFile
    }
    where combine field = field a `mappend` field b
          combine' field = case ( unUnqualComponentName $ field a
                                , unUnqualComponentName $ field b) of
            ("", _) -> field b
            (_, "") -> field a
            (x, y) -> error $ "Ambiguous values for executable field: '"
                                  ++ x ++ "' and '" ++ y ++ "'"
          combine'' field = field b
instance Monoid ForeignLib where
  mempty = ForeignLib {
      foreignLibName         = mempty
    , foreignLibType         = ForeignLibTypeUnknown
    , foreignLibOptions      = []
    , foreignLibBuildInfo    = mempty
    , foreignLibVersionInfo  = Nothing
    , foreignLibVersionLinux = Nothing
    , foreignLibModDefFile   = []
    }
  mappend = (<>)
emptyForeignLib :: ForeignLib
emptyForeignLib = mempty
foreignLibModules :: ForeignLib -> [ModuleName]
foreignLibModules = otherModules . foreignLibBuildInfo
foreignLibIsShared :: ForeignLib -> Bool
foreignLibIsShared = foreignLibTypeIsShared . foreignLibType
foreignLibVersion :: ForeignLib -> OS -> [Int]
foreignLibVersion flib Linux =
  case foreignLibVersionLinux flib of
    Just v  -> versionNumbers v
    Nothing ->
      case foreignLibVersionInfo flib of
        Just v' ->
          let (major, minor, build) = libVersionNumber v'
          in [major, minor, build]
        Nothing -> []
foreignLibVersion _ _ = []