module Database
   ( createDB
   , hasPredicate
   , getClauses
   , asserta
   , assertz
   , abolish
   , Signature(), signature
   )
where

import Data.Map (Map)
import qualified Data.Map.Strict as Map

import Syntax


data Signature = Signature Atom Int deriving (Ord, Eq)
instance Show Signature where
   show (Signature name arity) = name ++ "/" ++ show arity

signature :: Term -> Signature
signature (Struct name ts) = Signature name (length ts)


newtype Database = DB (Map Signature [Clause])

hasPredicate sig (DB index) = Map.member sig index

createDB clauses emptyPredicates = DB $
   foldr (\clause -> Map.insertWith (++) (signature (lhs clause)) [clause])
         (Map.fromList [ (signature (Struct name []), []) | name <- emptyPredicates ])
         clauses

getClauses term (DB index) = maybe [] id $ Map.lookup (signature term) index


asserta fact (DB index) = DB $ Map.insertWith (++)        (signature fact) [Clause fact []] index
assertz fact (DB index) = DB $ Map.insertWith (flip (++)) (signature fact) [Clause fact []] index
abolish fact (DB index) = DB $ Map.adjust deleteFact (signature fact) index
   where deleteFact (Clause t []:cs) | t == fact = cs
         deleteFact (_          :cs)             = cs
         deleteFact []                           = []