{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric      #-}
module Distribution.Types.LegacyExeDependency
  ( LegacyExeDependency(..)
  ) where

import Distribution.Compat.Prelude
import Prelude ()

import Distribution.Parsec.Class
import Distribution.ParseUtils   (parseMaybeQuoted)
import Distribution.Pretty
import Distribution.Text
import Distribution.Version      (VersionRange, anyVersion)

import qualified Distribution.Compat.CharParsing as P
import           Distribution.Compat.ReadP  ((<++))
import qualified Distribution.Compat.ReadP  as Parse
import           Text.PrettyPrint           (text, (<+>))

-- | Describes a legacy `build-tools`-style dependency on an executable
--
-- It is "legacy" because we do not know what the build-tool referred to. It
-- could refer to a pkg-config executable (PkgconfigName), or an internal
-- executable (UnqualComponentName). Thus the name is stringly typed.
--
-- @since 2.0.0.2
data LegacyExeDependency = LegacyExeDependency
                           String
                           VersionRange
                         deriving (Generic, Read, Show, Eq, Typeable, Data)

instance Binary LegacyExeDependency
instance NFData LegacyExeDependency where rnf = genericRnf

instance Pretty LegacyExeDependency where
  pretty (LegacyExeDependency name ver) =
    text name <+> pretty ver

instance Parsec LegacyExeDependency where
    parsec = do
        name <- parsecMaybeQuoted nameP
        P.spaces
        verRange <- parsecMaybeQuoted parsec <|> pure anyVersion
        pure $ LegacyExeDependency name verRange
      where
        nameP = intercalate "-" <$> P.sepBy1 component (P.char '-')
        component = do
            cs <- P.munch1 (\c -> isAlphaNum c || c == '+' || c == '_')
            if all isDigit cs then fail "invalid component" else return cs

instance Text LegacyExeDependency where
  parse = do name <- parseMaybeQuoted parseBuildToolName
             Parse.skipSpaces
             ver <- parse <++ return anyVersion
             Parse.skipSpaces
             return $ LegacyExeDependency name ver
    where
      -- like parsePackageName but accepts symbols in components
      parseBuildToolName :: Parse.ReadP r String
      parseBuildToolName = do ns <- Parse.sepBy1 component (Parse.char '-')
                              return (intercalate "-" ns)
        where component = do
                cs <- Parse.munch1 (\c -> isAlphaNum c || c == '+' || c == '_')
                if all isDigit cs then Parse.pfail else return cs
