{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module      : Git.Stale.Types.Branch
-- License     : BSD3
-- Maintainer  : tbidne@gmail.com
-- Provides types for holding branch information.
module Git.Stale.Types.Branch
  ( AnyBranch (..),
    BranchStatus (..),
    Branch (..),
    branchesToName,
    mkAnyBranch,
  )
where

import qualified Data.Text as T
import qualified Data.Time.Calendar as C
import Git.Types.GitTypes

-- | Promoted data type used for adding type-safe merge status
-- to branches.
data BranchStatus where
  Merged :: BranchStatus
  UnMerged :: BranchStatus

-- | Holds branch information with phantom `BranchStatus`.
data Branch (a :: BranchStatus) where
  MkBranch :: Name -> Author -> C.Day -> Branch a
  deriving (Int -> Branch a -> ShowS
[Branch a] -> ShowS
Branch a -> String
(Int -> Branch a -> ShowS)
-> (Branch a -> String) -> ([Branch a] -> ShowS) -> Show (Branch a)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (a :: BranchStatus). Int -> Branch a -> ShowS
forall (a :: BranchStatus). [Branch a] -> ShowS
forall (a :: BranchStatus). Branch a -> String
showList :: [Branch a] -> ShowS
$cshowList :: forall (a :: BranchStatus). [Branch a] -> ShowS
show :: Branch a -> String
$cshow :: forall (a :: BranchStatus). Branch a -> String
showsPrec :: Int -> Branch a -> ShowS
$cshowsPrec :: forall (a :: BranchStatus). Int -> Branch a -> ShowS
Show)

-- | Maps each @[`Branch` a]@ to its `T.Text` `Name` and concatenates results.
-- Attempts to strip out an irrelevant prefix it may have (i.e. `Types.Env.remoteName`).
branchesToName :: T.Text -> [Branch a] -> T.Text
branchesToName :: Text -> [Branch a] -> Text
branchesToName prefix :: Text
prefix branches :: [Branch a]
branches = "[" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate " " [Text]
names Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "]"
  where
    names :: [Text]
names = Text -> Branch a -> Text
forall (a :: BranchStatus). Text -> Branch a -> Text
branchToName Text
prefix (Branch a -> Text) -> [Branch a] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Branch a]
branches

branchToName :: T.Text -> Branch a -> T.Text
branchToName :: Text -> Branch a -> Text
branchToName prefix :: Text
prefix (MkBranch (Name n :: Text
n) _ _) =
  case Text
prefix of
    "" -> Text
n
    p :: Text
p ->
      case Text -> Text -> [Text]
T.splitOn Text
p (Text -> Text
T.strip Text
n) of
        [_, nm :: Text
nm] -> Text
nm
        [nm :: Text
nm] -> Text
nm
        _ -> "Err splitting " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
n Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> " on " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
p

-- | Hides `BranchStatus` type parameter, used for processing
-- @'Branch' a@ in heterogeneous collections.
data AnyBranch where
  MergedBranch :: Branch 'Merged -> AnyBranch
  UnMergedBranch :: Branch 'UnMerged -> AnyBranch
  deriving (Int -> AnyBranch -> ShowS
[AnyBranch] -> ShowS
AnyBranch -> String
(Int -> AnyBranch -> ShowS)
-> (AnyBranch -> String)
-> ([AnyBranch] -> ShowS)
-> Show AnyBranch
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AnyBranch] -> ShowS
$cshowList :: [AnyBranch] -> ShowS
show :: AnyBranch -> String
$cshow :: AnyBranch -> String
showsPrec :: Int -> AnyBranch -> ShowS
$cshowsPrec :: Int -> AnyBranch -> ShowS
Show)

-- | Constructs an `AnyBranch` wrapper around a @`Branch` a@
-- where @a@ is `Merged` if passed `True`, `UnMerged` otherwise.
mkAnyBranch :: Name -> Author -> C.Day -> Bool -> AnyBranch
mkAnyBranch :: Name -> Author -> Day -> Bool -> AnyBranch
mkAnyBranch n :: Name
n a :: Author
a d :: Day
d b :: Bool
b
  | Bool
b = Branch 'Merged -> AnyBranch
MergedBranch (Branch 'Merged -> AnyBranch) -> Branch 'Merged -> AnyBranch
forall a b. (a -> b) -> a -> b
$ Name -> Author -> Day -> Branch 'Merged
forall (a :: BranchStatus). Name -> Author -> Day -> Branch a
MkBranch Name
n Author
a Day
d
  | Bool
otherwise = Branch 'UnMerged -> AnyBranch
UnMergedBranch (Branch 'UnMerged -> AnyBranch) -> Branch 'UnMerged -> AnyBranch
forall a b. (a -> b) -> a -> b
$ Name -> Author -> Day -> Branch 'UnMerged
forall (a :: BranchStatus). Name -> Author -> Day -> Branch a
MkBranch Name
n Author
a Day
d