module Distribution.Types.Component (
    Component(..),
    foldComponent,
    componentBuildInfo,
    componentBuildable,
    componentName,
    partitionComponents,
) where
import Prelude ()
import Distribution.Compat.Prelude
import Distribution.Types.Library
import Distribution.Types.ForeignLib
import Distribution.Types.Executable
import Distribution.Types.TestSuite
import Distribution.Types.Benchmark
import Distribution.Types.ComponentName
import Distribution.Types.BuildInfo
import qualified Distribution.Types.BuildInfo.Lens as L
data Component = CLib   Library
               | CFLib  ForeignLib
               | CExe   Executable
               | CTest  TestSuite
               | CBench Benchmark
               deriving (Show, Eq, Read)
instance Semigroup Component where
    CLib   l <> CLib   l' = CLib   (l <> l')
    CFLib  l <> CFLib  l' = CFLib  (l <> l')
    CExe   e <> CExe   e' = CExe   (e <> e')
    CTest  t <> CTest  t' = CTest  (t <> t')
    CBench b <> CBench b' = CBench (b <> b')
    _        <> _         = error "Cannot merge Component"
instance L.HasBuildInfo Component where
    buildInfo f (CLib l)   = CLib <$> L.buildInfo f l
    buildInfo f (CFLib l)  = CFLib <$> L.buildInfo f l
    buildInfo f (CExe e)   = CExe <$> L.buildInfo f e
    buildInfo f (CTest t)  = CTest <$> L.buildInfo f t
    buildInfo f (CBench b) = CBench <$> L.buildInfo f b
foldComponent :: (Library -> a)
              -> (ForeignLib -> a)
              -> (Executable -> a)
              -> (TestSuite -> a)
              -> (Benchmark -> a)
              -> Component
              -> a
foldComponent f _ _ _ _ (CLib   lib) = f lib
foldComponent _ f _ _ _ (CFLib  flib)= f flib
foldComponent _ _ f _ _ (CExe   exe) = f exe
foldComponent _ _ _ f _ (CTest  tst) = f tst
foldComponent _ _ _ _ f (CBench bch) = f bch
componentBuildInfo :: Component -> BuildInfo
componentBuildInfo =
  foldComponent libBuildInfo foreignLibBuildInfo buildInfo testBuildInfo benchmarkBuildInfo
componentBuildable :: Component -> Bool
componentBuildable = buildable . componentBuildInfo
componentName :: Component -> ComponentName
componentName =
  foldComponent (libraryComponentName . libName)
                (CFLibName  . foreignLibName)
                (CExeName   . exeName)
                (CTestName  . testName)
                (CBenchName . benchmarkName)
partitionComponents
    :: [Component]
    -> ([Library], [ForeignLib], [Executable], [TestSuite], [Benchmark])
partitionComponents = foldr (foldComponent fa fb fc fd fe) ([],[],[],[],[])
  where
    fa x ~(a,b,c,d,e) = (x:a,b,c,d,e)
    fb x ~(a,b,c,d,e) = (a,x:b,c,d,e)
    fc x ~(a,b,c,d,e) = (a,b,x:c,d,e)
    fd x ~(a,b,c,d,e) = (a,b,c,x:d,e)
    fe x ~(a,b,c,d,e) = (a,b,c,d,x:e)