import os
from Ft.Lib import Uri
from Ft.Xml.Domlette import NonvalidatingReader
from Ft.Rdf.Model import Model
from Ft.Rdf.RdfsHandler import RdfsHandler, RdfsConstraintViolation
from Ft.Rdf.Serializers.Dom import Serializer
from Ft.Rdf.Statement import Statement

DATABASE_NAME = os.environ.get('RDF_TEST_DB', 'test')

RDFS_XML = """<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
  xml:lang="en"
  xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
  xmlns:rdfs='http://www.w3.org/2000/01/rdf-schema#'
  xml:base="http://schema.spam.com/"
>

  <!--                     Class Person                     -->

  <rdfs:Class rdf:ID="Person">
    <rdfs:comment>The class of persons</rdfs:comment>
    <rdfs:subClassOf rdf:resource="http://www.w3.org/2000/01/rdf-schema#Resource"/>
  </rdfs:Class>

  <!--                     Class User                     -->

  <rdfs:Class rdf:ID="User">
    <rdfs:label>The class of users.</rdfs:label>
    <rdfs:subClassOf rdf:resource="#Person"/>
  </rdfs:Class>

  <rdf:Property rdf:ID="nickname">
    <rdfs:range rdf:resource="http://www.w3.org/2000/01/rdf-schema#Literal"/>
    <rdfs:domain rdf:resource="#User"/>
  </rdf:Property>

  <rdf:Property rdf:ID="email">
    <rdfs:range rdf:resource="http://www.w3.org/2000/01/rdf-schema#Literal"/>
    <rdfs:domain rdf:resource="#User"/>
  </rdf:Property>

  <!--                     Class Organization                     -->

  <rdfs:Class rdf:ID="Organization">
    <rdfs:comment>Educational institutions, insurance providers, practices, etc.</rdfs:comment>
    <rdfs:subClassOf rdf:resource="http://www.w3.org/2000/01/rdf-schema#Resource"/>
  </rdfs:Class>

  <rdf:Property rdf:ID="name">
    <rdfs:range rdf:resource="http://www.w3.org/2000/01/rdf-schema#Literal"/>
    <rdfs:domain rdf:resource="#Person"/>
    <rdfs:domain rdf:resource="#Organization"/>
  </rdf:Property>

  <rdf:Property rdf:ID="employs">
    <rdfs:range rdf:resource="#Person"/>
    <rdfs:domain rdf:resource="#Organization"/>
  </rdf:Property>

  <!--                     Class Moderator                     -->

  <rdfs:Class rdf:ID="Moderator">
    <rdfs:label>The class of moderators.</rdfs:label>
    <rdfs:subClassOf rdf:resource="#User"/>
  </rdfs:Class>

  <rdf:Property rdf:ID="represents">
    <rdfs:range rdf:resource="#Organization"/>
    <rdfs:domain rdf:resource="#Moderator"/>
  </rdf:Property>

</rdf:RDF>"""


RDF_XML = """<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns="http://schema.spam.com/#"
>

  <!-- explicit resource typing before use in constrained predicates required
       because 4RDF constraint checking is quite strict: likely too strict. -->
  <Organization rdf:about="http://rblrebels.com"/>

  <Person rdf:about="http://rblrebels.com/~robelee">
    <name>Gen. Robert E. Lee</name>
  </Person>
  <Moderator rdf:about="http://rblrebels.com/~spartacus">
    <name>Spartacus Fortissimus</name>
    <nickname>sparta-fort</nickname>
    <email>sparta-fort@rblrebels.com</email>
    <!-- OK because of above explicit typing of "http://rblrebels.com" -->
    <represents rdf:resource='http://rblrebels.com'/>
  </Moderator>
  <User rdf:about="http://rblrebels.com/~robespierre">
    <name>Le Brigand Robespierre</name>
    <nickname>guillot</nickname>
    <email>guillot@rblrebels.com</email>
  </User>
  <Organization rdf:about="http://rblrebels.com">
    <name>RBL Rebels</name>
    <employs rdf:resource='http://rblrebels.com/~robelee'/>
    <employs rdf:resource='http://rblrebels.com/~spartacus'/>
    <employs rdf:resource='http://rblrebels.com/~robespierre'/>
  </Organization>
</rdf:RDF>"""


def init(tester):
    tester.startTest("Prepare driver's database")
    driver = tester.test_data['driver']
    if driver.ExistsDb(DATABASE_NAME):
        driver.DestroyDb(DATABASE_NAME)
    driver.CreateDb(DATABASE_NAME)
    tester.testDone()


def test_schemahandler(tester):

    uri_base = Uri.OsPathToUri(__file__, attemptAbsolute=True)
    db = tester.test_data['driver'].GetDb(DATABASE_NAME)
    db.begin()

    try:
        tester.startTest("Create model with core RDFS statements")
        sh = RdfsHandler()
        m = Model(db, sh)
        total = len(m.statements())
        tester.compare(192, total)
        tester.testDone()

        tester.startTest("Add user RDFS statements")
        uri = uri_base + '-INTERNAL-RDFS-XML-STRING'
        schemadoc = NonvalidatingReader.parseString(RDFS_XML, uri)
        serializer = Serializer()
        m.suspendSchema()
        serializer.deserialize(m, schemadoc, scope='http://schema.spam.com/')
        m.resumeSchema()
        total = len(m.statements())
        tester.compare(220, total)
        tester.testDone()

        tester.startTest("Validate all statements")
        m.checkConsistency()
        tester.testDone()

        tester.startTest("Add & validate user RDF statements")
        uri = uri_base + '-INTERNAL-RDF-XML-STRING'
        datadoc = NonvalidatingReader.parseString(RDF_XML, uri)
        serializer.deserialize(m, datadoc, 'http://spam.com/data')
        total = len(m.statements())
        tester.compare(237, total)
        tester.testDone()

        tester.startTest("Misc validation tests")
        tester.compare(True, sh.isInstance('http://rblrebels.com/~robelee', 'http://schema.spam.com/#Person'))
        tester.compare(True, sh.isInstance('http://rblrebels.com/~spartacus', 'http://schema.spam.com/#Person'))
        tester.compare(True, sh.isSubClass('http://schema.spam.com/#Moderator', 'http://schema.spam.com/#Person'))
        tester.testDone()

        tester.startTest("Add invalid statement")
        s = Statement('http://rblrebels.com/~robelee', 'http://schema.spam.com/#represents', 'ILLEGAL')
        tester.testException(m.add, (s,), RdfsConstraintViolation)
        tester.testDone()

    except:
        db.rollback()
        raise

    db.rollback()
    tester.groupDone()


def Test(tester):
    tester.startGroup('RDF Schema Handler')
    init(tester)
    test_schemahandler(tester)
    return
