module Grakn.Pattern
  ( Pattern
  , var_
  , isa
  , (<:)
  , has
  ) where

import           Grakn.Property (Label, Property (Has, Isa, Rel), RolePlayer,
                                 Value, Var, VarOrLabel)
import           Grakn.Util     (Convert (convert), spaces, with)

-- |A pattern to find in the knowledge base
data Pattern =
  Pattern (Maybe VarOrLabel)
          [Property]

-- |Create an anonymous variable
var_ :: Pattern
var_ = Pattern Nothing []

-- |Specify a property has a particular type
isa :: (Convert p Pattern, Convert a VarOrLabel) => p -> a -> Pattern
patt `isa` x = addProperty patt (Isa $ convert x)

-- |Specify a property is a relation between other variables
(<:) :: (Convert p Pattern, Convert a RolePlayer) => p -> [a] -> Pattern
patt <: cs = addProperty patt (Rel $ map convert cs)

-- |Specify a property has a resource
has ::
     (Convert p Pattern, Convert a (Either Value Var))
  => p
  -> Label
  -> a
  -> Pattern
has patt rt v = addProperty patt (Has rt $ convert v)

showProps :: Show a => [a] -> String
showProps = spaces . reverse

addPropToPattern :: Pattern -> Property -> Pattern
addPropToPattern (Pattern n props) prop = Pattern n (prop : props)

addProperty :: Convert a Pattern => a -> Property -> Pattern
addProperty = addPropToPattern . convert

instance Show Pattern where
  show (Pattern v [])    = v `with` "" ++ ";"
  show (Pattern v props) = v `with` " " ++ showProps props ++ ";"

instance Convert Var Pattern where
  convert = convert . (convert :: Var -> VarOrLabel)

instance Convert Label Pattern where
  convert = convert . (convert :: Label -> VarOrLabel)

instance Convert VarOrLabel Pattern where
  convert v = Pattern (Just v) []