########################################################################
#
# File Name:            Assert.py
#
# Documentation:        http://docs.4suite.org/4Rdf/Inference/Assert.py.html
#
"""

WWW: http://4suite.org/4RDF         e-mail: support@4suite.org

Copyright (c) 1999 Fourthought Inc, USA.   All Rights Reserved.
See  http://4suite.org/COPYRIGHT  for license and copyright information
"""

from Ft.Rdf.Statement import Statement

class Assert:
    def __init__(self, id_, negative,arguments):
        self.id = id_
        self.negative = negative
        self.arguments = arguments
        return

    def assert_(self,infEng,context):
        return self.execute(infEng,context)

    def chain(self,infEng,context):
        rules = infEng.narrowRules(self.id, self.arguments)
        for rule in rules:
            rule.fire(infEng,context)


    def _4rdf_dump(self,indent=0):
        n = ""
        if self.negative:
            n = "negate = '1' "
        iStr = "\t" * (indent)
        rt = iStr + "<ril:assert %sid='%s'>\n" % (n,self.id)
        for arg in self.arguments:
            rt = rt + arg._4rdf_dump(indent+1)
        rt = rt + iStr + '</ril:assert>\n'
        return rt

class SingleAssert(Assert):
    '''
    Stored in RDF Model as triple.  For instance
    hungry(X), if the hungry predicate is in the http://spam.com namespace
    and the UUID of the X resource is 132ad72a-f1e0-4482-82e3-e7d790d4f56
    is mapped to
    (http://spam.com#hungry, urn:uuid:132ad72a-f1e0-4482-82e3-e7d790d4f56, 1)
    '''

    def execute(self, infEng, context):
        arg = self.arguments[0]
        args = arg.execute(infEng,context) 
        if args is None:
            raise "Unresolved skolem variable %s" % arg.name
        new_assertion = 0
        for a in args:
            #FIXME negate fails if the core has this triple.  Remove from core???
            if (self.negative and
                infEng.workspace.contains(Statement(a, self.id, '1'))
                ):
                new_assertion = 1
                infEng.workspace.remove(Statement(a, self.id, '1'))
            elif not (self.negative or
                      infEng.workspace.contains(Statement(a, self.id, '1'))
                      ):
                new_assertion = 1
                infEng.workspace.add(Statement(a, self.id, '1'))
        if new_assertion and context.fireRules:
            self.chain(infEng,context)
        return

class DualAssert(Assert):
    '''
    Stored in RDF Model as triple.  For instance
    ate(X, Y), if the ate predicate is in the http://spam.com namespace
    and the UUID of the X resource is 132ad72a-f1e0-4482-82e3-e7d790d4f56
    and the UUID of the Y resource is 23bd4d35-afa1-4be1-8d80-e34bbed9db7d
    is mapped to
    (urn:uuid:132ad72a-f1e0-4482-82e3-e7d790d4f56, http://spam.com#ate, 23bd4d35-afa1-4be1-8d80-e34bbed9db7d)
    '''

    def execute(self, infEng, context):
        new_assertion = 0
        #FIXME: Can be optimized with recursive lambda trickery
        #Note that the multiple argument case will involve the cartesian product (ouch!)
        #Do the combanitorics belong here, or should they be left to the caller (in which case lists would not be permitted as arguments)?

        arg = self.arguments[0]
        args = arg.execute(infEng,context) 
        if args is None:
            raise "Unresolved skolem variable %s" % arg.name
        arg1 = self.arguments[1]
        args1 = arg1.execute(infEng,context) 
        if args1 is None:
            raise "Unresolved skolem variable %s" % arg1.name

        for a in args:
            for a1 in args1:
                #FIXME negate failes is the triple is in the core!
                if self.negative and infEng.workspace.contains(a, self.id, a1):
                    new_assertion = 1
                    infEng.workspace.remove(Statement(a, self.id, a1))
                elif not (self.negative or
                          infEng.workspace.contains(Statement(a, self.id, a1))
                          ):
                    new_assertion = 1
                    infEng.workspace.add(Statement(a, self.id, a1))
        if new_assertion and context.fireRules:
            self.chain(infEng,context)
        return

