{-# LANGUAGE OverloadedStrings #-}

--------------------------------------------------------------------------------
--  See end of this file for licence information.
--------------------------------------------------------------------------------
-- |
--  Module      :  VarBinding
--  Copyright   :  (c) 2003, Graham Klyne, 2009 Vasili I Galchin, 2011, 2012 Douglas Burke
--  License     :  GPL V2
--
--  Maintainer  :  Douglas Burke
--  Stability   :  experimental
--  Portability :  OverloadedStrings
--
--  This module instantiates the `VarBinding` types and methods for use
--  with RDF graph labels.
--
--------------------------------------------------------------------------------

--  See module RDFQueryTest for test cases.

module Swish.RDF.VarBinding
    ( RDFVarBinding
    , RDFVarBindingModify, RDFOpenVarBindingModify, RDFOpenVarBindingModifyMap
    , RDFVarBindingFilter
    , nullRDFVarBinding
    , rdfVarBindingUriRef, rdfVarBindingBlank
    , rdfVarBindingLiteral
    , rdfVarBindingUntypedLiteral, rdfVarBindingTypedLiteral
    , rdfVarBindingXMLLiteral, rdfVarBindingDatatyped
    , rdfVarBindingMemberProp
    )
where

import Swish.Namespace (ScopedName)
import Swish.VarBinding (VarBinding(..), VarBindingModify(..), OpenVarBindingModify, VarBindingFilter(..))
import Swish.VarBinding (nullVarBinding, applyVarBinding, makeVarTestFilter)

import Swish.RDF.Graph
    ( RDFLabel(..)
    , isLiteral, isUntypedLiteral, isTypedLiteral, isXMLLiteral
    , isDatatyped, isMemberProp, isUri, isBlank
    )
import Swish.RDF.Vocabulary (swishName)

import qualified Data.Map as M

------------------------------------------------------------
--  Types for RDF query variable bindings and modifiers
------------------------------------------------------------

-- |@RDFVarBinding@ is the specific type type of a variable
--  binding value used with RDF graph queries. 
type RDFVarBinding  = VarBinding RDFLabel RDFLabel

-- | maps no query variables.
nullRDFVarBinding :: RDFVarBinding
nullRDFVarBinding :: RDFVarBinding
nullRDFVarBinding = RDFVarBinding
forall a b. VarBinding a b
nullVarBinding

-- |Define type of query binding modifier for RDF graph inference
type RDFVarBindingModify = VarBindingModify RDFLabel RDFLabel

-- |Open variable binding modifier that operates on RDFLabel values
--
type RDFOpenVarBindingModify = OpenVarBindingModify RDFLabel RDFLabel

-- |Define type for lookup map of open query binding modifiers
type RDFOpenVarBindingModifyMap = M.Map ScopedName RDFOpenVarBindingModify

-- |@RDFVarBindingFilter@ is a function type that tests to see if
--  a query binding satisfies some criterion, and is used to
--  create a variable binding modifier that simply filers
--  given variable bindings.
--
--  Queries often want to apply some kind of filter or condition
--  to the variable bindings that are processed.  In inference rules,
--  it sometimes seems desirable to stipulate additional conditions on
--  the things that are matched.
--
--  This function type is used to perform such tests.
--  A number of simple implementations are included.
--
type RDFVarBindingFilter = VarBindingFilter RDFLabel RDFLabel

------------------------------------------------------------
--  Declare some query binding filters
------------------------------------------------------------

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to a URI reference.
rdfVarBindingUriRef :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingUriRef :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingUriRef =
    ScopedName -> (RDFLabel -> Bool) -> RDFLabel -> RDFVarBindingFilter
forall b a. ScopedName -> (b -> Bool) -> a -> VarBindingFilter a b
makeVarTestFilter (LName -> ScopedName
swishName LName
"rdfVarBindingUriRef") RDFLabel -> Bool
isUri

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to a blank node.
rdfVarBindingBlank :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingBlank :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingBlank =
    ScopedName -> (RDFLabel -> Bool) -> RDFLabel -> RDFVarBindingFilter
forall b a. ScopedName -> (b -> Bool) -> a -> VarBindingFilter a b
makeVarTestFilter (LName -> ScopedName
swishName LName
"rdfVarBindingBlank") RDFLabel -> Bool
isBlank

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to a literal value.
rdfVarBindingLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingLiteral =
    ScopedName -> (RDFLabel -> Bool) -> RDFLabel -> RDFVarBindingFilter
forall b a. ScopedName -> (b -> Bool) -> a -> VarBindingFilter a b
makeVarTestFilter (LName -> ScopedName
swishName LName
"rdfVarBindingLiteral") RDFLabel -> Bool
isLiteral

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to an untyped literal value.
rdfVarBindingUntypedLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingUntypedLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingUntypedLiteral =
    ScopedName -> (RDFLabel -> Bool) -> RDFLabel -> RDFVarBindingFilter
forall b a. ScopedName -> (b -> Bool) -> a -> VarBindingFilter a b
makeVarTestFilter (LName -> ScopedName
swishName LName
"rdfVarBindingUntypedLiteral") RDFLabel -> Bool
isUntypedLiteral

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to a typed literal value.
rdfVarBindingTypedLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingTypedLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingTypedLiteral =
    ScopedName -> (RDFLabel -> Bool) -> RDFLabel -> RDFVarBindingFilter
forall b a. ScopedName -> (b -> Bool) -> a -> VarBindingFilter a b
makeVarTestFilter (LName -> ScopedName
swishName LName
"rdfVarBindingTypedLiteral") RDFLabel -> Bool
isTypedLiteral

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to an XML literal value.
rdfVarBindingXMLLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingXMLLiteral :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingXMLLiteral =
    ScopedName -> (RDFLabel -> Bool) -> RDFLabel -> RDFVarBindingFilter
forall b a. ScopedName -> (b -> Bool) -> a -> VarBindingFilter a b
makeVarTestFilter (LName -> ScopedName
swishName LName
"rdfVarBindingXMLLiteral") RDFLabel -> Bool
isXMLLiteral

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to container membership property.
rdfVarBindingMemberProp :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingMemberProp :: RDFLabel -> RDFVarBindingFilter
rdfVarBindingMemberProp =
    ScopedName -> (RDFLabel -> Bool) -> RDFLabel -> RDFVarBindingFilter
forall b a. ScopedName -> (b -> Bool) -> a -> VarBindingFilter a b
makeVarTestFilter (LName -> ScopedName
swishName LName
"rdfVarBindingMemberProp") RDFLabel -> Bool
isMemberProp

-- |This function generates a query binding filter that ensures
--  an indicated variable is bound to a literal value with a
--  datatype whose URI is bound to another node
--
rdfVarBindingDatatyped ::
  RDFLabel    -- ^ variable bound to the required datatype. 
  -> RDFLabel -- ^ variable bound to the literal node to be tested.
  -> RDFVarBindingFilter
rdfVarBindingDatatyped :: RDFLabel -> RDFLabel -> RDFVarBindingFilter
rdfVarBindingDatatyped RDFLabel
dvar RDFLabel
lvar = VarBindingFilter
    { vbfName :: ScopedName
vbfName   = LName -> ScopedName
swishName LName
"rdfVarBindingDatatyped"
    , vbfVocab :: [RDFLabel]
vbfVocab  = [RDFLabel
dvar,RDFLabel
lvar]
    , vbfTest :: RDFVarBinding -> Bool
vbfTest   = \RDFVarBinding
vb -> RDFVarBinding -> RDFLabel -> RDFLabel -> Bool
testDatatyped RDFVarBinding
vb RDFLabel
dvar RDFLabel
lvar
    }

testDatatyped :: RDFVarBinding -> RDFLabel -> RDFLabel -> Bool
testDatatyped :: RDFVarBinding -> RDFLabel -> RDFLabel -> Bool
testDatatyped RDFVarBinding
vb RDFLabel
dvar RDFLabel
lvar = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and
        [ RDFLabel -> Bool
isUri RDFLabel
dtype
        , ScopedName -> RDFLabel -> Bool
isDatatyped ScopedName
dqnam (RDFLabel -> Bool) -> RDFLabel -> Bool
forall a b. (a -> b) -> a -> b
$ RDFVarBinding -> RDFLabel -> RDFLabel
forall a. VarBinding a a -> a -> a
applyVarBinding RDFVarBinding
vb RDFLabel
lvar
        ]
        where
            dtype :: RDFLabel
dtype = RDFVarBinding -> RDFLabel -> RDFLabel
forall a. VarBinding a a -> a -> a
applyVarBinding RDFVarBinding
vb RDFLabel
dvar
            -- NOTE: dqnam is not evaluated unless (isUri dtype)
            --       but add in a _ handler to appease -Wall
            -- dqnam = case dtype of { (Res x) -> x }
            dqnam :: ScopedName
dqnam = case RDFLabel
dtype of
              Res ScopedName
x -> ScopedName
x
              RDFLabel
_ -> [Char] -> ScopedName
forall a. HasCallStack => [Char] -> a
error ([Char] -> ScopedName) -> [Char] -> ScopedName
forall a b. (a -> b) -> a -> b
$ [Char]
"dqnam should not be evaluated with " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ RDFLabel -> [Char]
forall a. Show a => a -> [Char]
show RDFLabel
dtype

--------------------------------------------------------------------------------
--
--  Copyright (c) 2003, Graham Klyne, 2009 Vasili I Galchin,
--    2011, 2012 Douglas Burke  
--  All rights reserved.
--
--  This file is part of Swish.
--
--  Swish is free software; you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation; either version 2 of the License, or
--  (at your option) any later version.
--
--  Swish is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with Swish; if not, write to:
--    The Free Software Foundation, Inc.,
--    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
--
--------------------------------------------------------------------------------