#!/usr/bin/env python
# As of Python 2.3, there is a built-in module for Berkeley DB,
# called bsddb.  The next uncommented line assumes that module is being used.
# If you are using your own bsddb3 module, use this line:
#      from bsddb3.db import *
from bsddb.db import *
from dbxml import *

book_content = r"<book><title>Knowledge Discovery in Databases.</title></book>"
book_content_ns = r"<book xmlns:books='http://foo.bar.com/books.dtd'><books:title>Knowledge Discovery in Databases.</books:title></book>"

def remove_database():
    """Removes the databases so we can start with a fresh environment for
    each test."""
    import os, glob
    databases = ["test", "test1", "test2"]
    for database in databases:
        files = glob.glob(database + "*.dbxml")
        files += glob.glob("__db*")
        files += glob.glob("log.*")
        for file in files:
            os.remove(file)

def example01():
    """Create an XMLContainer, add a document, get the document,
    display the content of the document.

    >>> remove_database()
    >>> example01()
    1 = <book><title>Knowledge Discovery in Databases.</title></book>
    """
    
    container = XmlContainer(None, "test.dbxml")
    container.open(None, DB_CREATE)
    document = XmlDocument()
    document.setContent(book_content)
    id = container.putDocument(None, document)
    document = container.getDocument(None, id)
    s = document.getContent()
    print id, "=", s
    container.close()

def example02():
    """Create an XMLContainer, add a document, query the container
    for the document, iterate over the result set displaying the
    values returned.

    >>> remove_database()
    >>> example02()
    1 = <book><title>Knowledge Discovery in Databases.</title></book>
    """
    
    container = XmlContainer(None, "test.dbxml")
    container.open(None, DB_CREATE)
    document = XmlDocument()
    document.setContent(book_content)
    container.putDocument(None, document)
    results = container.queryWithXPath(None, "/book")
    results.reset()
    for value in results:
        document = value.asDocument()
        print document.getID(), "=", value.asString()
    container.close()

def example03():
    """Create an XML Container, add a document that includes a
    namespace definition, create a query context, define a
    namespace prefix to URI mapping, query the container
    for the document within a context, iterate over the
    result set displaying the values returned.

    >>> remove_database()
    >>> example03()
    1 = <book xmlns:books='http://foo.bar.com/books.dtd'><books:title>Knowledge Discovery in Databases.</books:title></book>
    """

    container = XmlContainer(None, "test.dbxml")
    container.open(None, DB_CREATE)
    document = XmlDocument()
    document.setContent(book_content_ns)
    container.putDocument(None, document)
    context = XmlQueryContext()
    context.setNamespace("books2", "http://foo.bar.com/books.dtd")
    results = container.queryWithXPath(None, "/*[books2:title='Knowledge Discovery in Databases.']", context)
    for value in results:
        document = value.asDocument()
        print document.getID(), "=", value.asString()
    container.close()

def example04():
    """Create an XML Container, define an equality string index
    for booktitle elements, add a document, query the container
    for the document, iterate over the result set displaying
    the values returned.

    Note that this example assumes that the 'test' container
    does not already exist. If it does exist then the
    addIndex method will throw an exception to complain
    that the container isn't empty.

    Python note: This exception is not passed on to Python, which
    will abort the interpreter.

    >>> remove_database()
    >>> example04()
    1 = <book><title>Knowledge Discovery in Databases.</title></book>
    """

    container = XmlContainer(None, "test.dbxml")
    container.open(None, DB_CREATE)
    container.addIndex(None, "", "title", "node-element-equality-string")
    document = XmlDocument()
    document.setContent(book_content)
    container.putDocument(None, document)
    results = container.queryWithXPath(None, "//*[title='Knowledge Discovery in Databases.']")
    for value in results:
        document = value.asDocument()
        print document.getID(), "=", value.asString()
    container.close()

def example05():
    """
    Create an XML Container, define an equality string index
    for booktitle elements, add a document, create a query
    context, define a variable binding, query the container
    for the document within a context referencing the variable
    defined, iterate over the result set displaying the values
    returned.

    Note that this example assumes that the 'test' container
    does not already exist. If it does exist then the
    addIndex method will throw an exception to complain
    that the container isn't empty.

    Python note: This exception is not passed on to Python, which
    will abort the interpreter.

    >>> remove_database()
    >>> example05()
    1 = <book><title>Knowledge Discovery in Databases.</title></book>
    """

    container = XmlContainer(None, "test.dbxml")
    container.open(None, DB_CREATE)
    container.addIndex(None, "", "title", "node-element-equality-string")
    document = XmlDocument()
    document.setContent(book_content)
    container.putDocument(None, document)
    context = XmlQueryContext()
    context.setVariableValue("title", XmlValue("Knowledge Discovery in Databases."))
    results = container.queryWithXPath(None, "//*[title=$title]", context)
    for value in results:
        document = value.asDocument()
        print document.getID(), "=", value.asString()
    container.close()

def example06():
    """Create an XML Container, rename that container, delete the
    container, and repeat.

    >>> remove_database()
    >>> example06()
    """

    for i in range(2):
        container = XmlContainer(None, "test1.dbxml")
        container.open(None, DB_CREATE)
        container.close()
        container.rename(None, "test2.dbxml")
        container.setName("test2.dbxml")
        container.open(None, 0)
        container.close()
        container.remove(None)

def example07():
    """Create an XML Container within a Berkeley DB environment,
    add a document, get the document, display the content of
    the document.

    >>> remove_database()
    >>> example07()
    1 = <book><title>Knowledge Discovery in Databases.</title></book>
    """

    environment = DBEnv()
    environment.open(None, DB_CREATE|DB_INIT_MPOOL, 0)
    container = XmlContainer(environment, "test.dbxml")
    container.open(None, DB_CREATE)
    document = XmlDocument()
    document.setContent(book_content)
    id = container.putDocument(None, document)
    s = document.getContent()
    print id, "=", s
    container.close()
    environment.close()

def example08():
    """Create an XML Container within a Berkeley DB environment,
    then within a Berkeley DB transaction, add a document,
    get the document, display the content of the document.

    >>> remove_database()
    >>> example08()
    1 = <book><title>Knowledge Discovery in Databases.</title></book>
    """

    environment = DBEnv()
    environment.open(None, DB_CREATE|DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN, 0)
    txn = environment.txn_begin()
    container = XmlContainer(environment, "test.dbxml")
    container.open(txn, DB_CREATE)
    document = XmlDocument()
    document.setContent(book_content)
    id = container.putDocument(txn, document)
    document = container.getDocument(txn, id)
    s = document.getContent()
    print id, "=", s
    txn.commit(0)
    container.close()
    environment.close(0)

def example09():
    """ Create two XML Containers within a Berkeley DB environment,
    then within a Berkeley DB transaction add a document to
    each container.

    >>> remove_database()
    >>> example09()
    """

    environment = DBEnv()
    environment.open(None, DB_CREATE|DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN, 0)
    txn = environment.txn_begin()
    container1 = XmlContainer(environment, "test1.dbxml")
    container2 = XmlContainer(environment, "test2.dbxml")
    container1.open(txn, DB_CREATE)
    container2.open(txn, DB_CREATE)
    document = XmlDocument()
    document.setContent(book_content)
    container1.putDocument(txn, document)
    container2.putDocument(txn, document)
    txn.commit(0)
    container1.close()
    container2.close()
    environment.close(0)

def example10():
    """Create two XML Containers within a Berkeley DB environment,
    configure default deadlock detection, then within a Berkeley
    DB transaction add a document to each container. If a
    deadlock occurs then retry the transaction.

    >>> remove_database()
    >>> example10()
    """

    environment = DBEnv()
    environment.set_lk_detect(DB_LOCK_DEFAULT)
    environment.open(None, DB_CREATE|DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN, 0)
    txn = environment.txn_begin()
    container1 = XmlContainer(environment, "test1.dbxml")
    container2 = XmlContainer(environment, "test2.dbxml")
    container1.open(txn, DB_CREATE)
    container2.open(txn, DB_CREATE)
    document = XmlDocument()
    document.setContent(book_content)
    container1.putDocument(txn, document)
    container2.putDocument(txn, document)
    txn.commit(0)
    container1.close()
    container2.close()
    environment.close(0)
    
def example11():
    """Create a Berkeley DB environment with default deadlock detection.
    Create a checkpointing thread to checkpoint the environment every
    minute. Open the environment with transaction support, and recover
    the environment. Create two XML Containers, then within a Berkeley
    DB transaction add a document to each container. If a deadlock
    occurs then retry the transaction.

    >>> remove_database()
    >>> example11()
    """

    # TODO: C++ version is Windows-specific
    pass

def example12():
    """Demonstrate the definition of an index, and the iteration over set set
    of indexes specified

    >>> remove_database()
    >>> example12()
    :title node-element-equality-string edge-element-equality-string
    """

    container = XmlContainer(None, "test.dbxml")
    container.open(None, DB_CREATE)
    container.addIndex(None, "", "title", "node-element-equality-string, edge-element-equality-string")
    n = 0
    for index in container.getIndexSpecification(None):
      print "%s:%s %s" % (index.get_uri(), index.get_name(), index.get_index())
    container.close()

NUMBER_OF_EXAMPLES = 12

def do_example(number):
    print "Running example %d." % number
    globals()["example%02d" % number]()
    
if __name__ == "__main__":
    import sys
    number = sys.argv[-1]
    if number == "test":
        import doctest, examples
        doctest.testmod(examples)
        sys.exit()
        
    try:
        number = int(number)
    except ValueError:
        print "Usage: ./examples.py <example_number>|test"
        sys.exit()

    if number < 1 or number > NUMBER_OF_EXAMPLES:
        print "Usage: ./examples.py <example_number>|test"
        print "Example number out of range (1-%d)" % NUMBER_OF_EXAMPLES
        sys.exit()

    remove_database()
    do_example(number)
