{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Patch.PatchOrReplacement
  ( PatchOrReplacement (..)
  , _PatchOrReplacement_Patch
  , _PatchOrReplacement_Replacement
  , traversePatchOrReplacement
  ) where
import Control.Lens.TH (makePrisms)
import Data.Patch
#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup (Semigroup (..))
#endif
import GHC.Generics
data PatchOrReplacement p
  = PatchOrReplacement_Patch p
  | PatchOrReplacement_Replacement (PatchTarget p)
  deriving (Generic)
deriving instance (Eq p, Eq (PatchTarget p)) => Eq (PatchOrReplacement p)
deriving instance (Ord p, Ord (PatchTarget p)) => Ord (PatchOrReplacement p)
deriving instance (Show p, Show (PatchTarget p)) => Show (PatchOrReplacement p)
deriving instance (Read p, Read (PatchTarget p)) => Read (PatchOrReplacement p)
traversePatchOrReplacement
  :: Functor f
  => (a -> f b)
  -> (PatchTarget a -> f (PatchTarget b))
  -> PatchOrReplacement a -> f (PatchOrReplacement b)
traversePatchOrReplacement f g = \case
  PatchOrReplacement_Patch p -> PatchOrReplacement_Patch <$> f p
  PatchOrReplacement_Replacement p -> PatchOrReplacement_Replacement <$> g p
instance Patch p => Patch (PatchOrReplacement p) where
  type PatchTarget (PatchOrReplacement p) = PatchTarget p
  apply = \case
    PatchOrReplacement_Patch p -> apply p
    PatchOrReplacement_Replacement v -> \_ -> Just v
instance ( Monoid p
#if !MIN_VERSION_base(4,11,0)
         , Semigroup p
#endif
         , Patch p
         ) => Monoid (PatchOrReplacement p) where
  mempty = PatchOrReplacement_Patch mempty
  mappend = (<>)
instance (Semigroup p, Patch p) => Semigroup (PatchOrReplacement p) where
  (<>) = curry $ \case
    (PatchOrReplacement_Patch a, PatchOrReplacement_Patch b) -> PatchOrReplacement_Patch $ a <> b
    (PatchOrReplacement_Patch a, PatchOrReplacement_Replacement b) -> PatchOrReplacement_Replacement $ applyAlways a b
    (PatchOrReplacement_Replacement a, _) -> PatchOrReplacement_Replacement a
makePrisms ''PatchOrReplacement