VERSION="0.1"
SYSTEM_MODEL_NAME = 'system'
USER_MODEL_NAME = 'user'

#Depends on MySQLdb
#http://sourceforge.net/projects/mysql-python/
from MySQLContainer import MySQLContainer, FTSS_CONTAIMENT_TABLE
import urllib, types, sys
from Ft.Rdf import Model
from Ft.Xml import XPath
from string import join
from Ft.Server import FTSERVER_NAMESPACE
from Ft.Server.Common import ResourceTypes
import Escapec

def InitializeModule():
    """
    Post-import hook to initialize module's runtime variables that are not
    required at import time, but will be needed before the module-level
    functions are called.
    """
    global MySQLdb,MySQL4RDF

    # Load the required database interface module
    import MySQLdb

    # Incorporate the RDF driver module
    from Ft.Rdf.Drivers import MySQL as MySQL4RDF
    MySQL4RDF.InitializeModule()
    return


def Exists(properties):
    """See if this repo exists.  The return value for this is three state.
    1.  Everything is present
    0.  Some things are there
    -1  Nothing is there.
    """
    rdfConn = BuildRdfConnString(properties)
    #test_db = MySQLdb.connect(user=properties['User'],
    #                          passwd=properties['Passwd'],
    #                          db='test',
    #                          port=int(properties['Port']),
    #                          host=properties['Host']
    #                          )
    #c=test_db.cursor()
    #c.execute("""SET AUTOCOMMIT=0""")
    #c.execute("""SHOW DATABASES""")
    #rt = c.fetchall()
    db_name = properties['DbName']
    #test_db.rollback()
    #test_db.close()

    #if (db_name.encode('utf-8'),) in rt:
    #ASSUME DATABASE EXISTS!

    if True:
        if MySQL4RDF.ExistsDb(rdfConn,SYSTEM_MODEL_NAME) == -1 :return -1
        if MySQL4RDF.ExistsDb(rdfConn,USER_MODEL_NAME) != 1 :return 0

        msql_db = MySQLdb.connect(user=properties['User'],
                                  passwd=properties['Passwd'],
                                  db=db_name,
                                  port=int(properties['Port']),
                                  host=properties['Host']
                                  )        
        c=msql_db.cursor()
        c.execute("""SET AUTOCOMMIT=0""")

        for tn in ['ftss_strings',FTSS_CONTAIMENT_TABLE]:
            c.execute("""show tables like '%s'"""%(tn,))
            rt=c.fetchall()
            if not rt:
                msql_db.rollback()
                msql_db.close()
                return 0
        msql_db.rollback()
        msql_db.close()
        return 1
    return -1

def Initialize(properties):
    """Initialize a new copy of the repo.  This is not the same as a 4ss_manager init.  This
    is very raw.  The adapter will take care of calling our other interfaces
    (createContainer, createUser, etc) with all of the information
    about the rest of the 'init' stuff to do
    """
    rdfConn = BuildRdfConnString(properties)
    MySQL4RDF.CreateDb(rdfConn,SYSTEM_MODEL_NAME)
    MySQL4RDF.CreateDb(rdfConn,USER_MODEL_NAME)    

    db_name =  properties['DbName']
    msql_db = MySQLdb.connect(user=properties['User'],
                              passwd=properties['Passwd'],
                              db=db_name,
                              port=int(properties['Port']),
                              host=properties['Host']
                              )
    
    c=msql_db.cursor()
    c.execute("""SET AUTOCOMMIT=0""")
    c.execute('CREATE TABLE ftss_strings (path varchar(255), type int4, content LONGBLOB) TYPE=InnoDB')
    c.execute('CREATE UNIQUE INDEX ftss_strings_idx ON ftss_strings (path(255),type)')
    containerDrv = MySQLContainer(msql_db)
    containerDrv.initialize()
    msql_db.commit()
    msql_db.close()
    
def Destroy(properties,tryOnly=0):
    """Completly destroy the repo"""
    rdfConn = BuildRdfConnString(properties)
    MySQL4RDF.DestroyDb(rdfConn,SYSTEM_MODEL_NAME)
    MySQL4RDF.DestroyDb(rdfConn,USER_MODEL_NAME)    

    db_name = properties['DbName']
    msql_db = MySQLdb.connect(user=properties['User'],
                              passwd=properties['Passwd'],
                              db=db_name,
                              port=int(properties['Port']),
                              host=properties['Host']
                              )
    
    c=msql_db.cursor()
    c.execute("""SET AUTOCOMMIT=0""")
    for tn in ['ftss_strings',FTSS_CONTAIMENT_TABLE]:
        try:
            c.execute('DROP TABLE %s' % tn)
        except:
            sys.stderr.write("Unable to drop table %s\n" % tn);
            
    #c.execute("""DROP DATABASE %s"""%(db_name))
    msql_db.commit()
    msql_db.close()
    
def Maintain(properties):
    """
    Perform any maintenance on the db
    Necessary for MySQL??!
    """    
    pass
    
def BuildRdfConnString(properties):
    st = "rdf:"
    if properties['User']:
        if properties['Passwd']:
            st = st + properties['User'] + '/' + properties['Passwd'] + '@'
        else:
            st = st + properties['User'] + '@'
    if properties['Host']:
        st = st + properties['Host'] + ':'
    if properties['Port'] != -1:        
        st = st + str(properties['Port']) + ':'
    return st + properties['DbName']    

class MySQLDriver(MySQLContainer):
    """Store information in a MySQL (InnoDB) Database"""

    def __init__(self,
                 dbName,
                 host,
                 port,
                 user,
                 passwd):

        self._dbName = dbName
        self._host = host
        self._port = int(port)
        self._user = user
        self._passwd = passwd
        db_name = dbName
        msql_db = MySQLdb.connect(user=user,
                                  passwd=passwd,
                                  db=db_name,
                                  port=int(port),
                                  host=host
                                  )
            
        self._db = msql_db
        d = MySQL4RDF.DbAdapter('',SYSTEM_MODEL_NAME)
        d._db = self._db
        self._systemRdfModel = Model.Model(d)
        d = MySQL4RDF.DbAdapter('',USER_MODEL_NAME)
        d._db = self._db
        self._userRdfModel = Model.Model(d)

    def createFile(self,path,typ,content):
        """When creating a resource, store the content"""        
        #Verify that we were given a string object
        if not isinstance(content, types.StringType):
            type_name = type(content).__name__
            raise TypeError("Content must be a string, not %r" % type_name)        

        content = Escapec.escape(content)
        c=self._db.cursor()
        c.execute("""SET AUTOCOMMIT=0""")        
        c.execute("""INSERT INTO ftss_strings (path,type,content) VALUES ('%s', %d,'%s')"""%(str(path), typ, content))
        return
        
    def hasFile(self,path,typ):
        """See if we have any meta information about this resource"""        
        c=self._db.cursor()
        c.execute("""SELECT type FROM ftss_strings WHERE path = '%s' and type=%d"""%(str(path),typ))
        rt=c.fetchall()
        return not not rt

    def fetchFile(self, path, typ):        
        c=self._db.cursor()
        try:
            c.execute("""SELECT content FROM ftss_strings WHERE path = '%s' and type=%d"""%(str(path),typ))
            data = c.fetchall()
        except:
            return None
        if not data:
            return None
        return Escapec.unescape(data[0][0].tostring())
    
    def updateFile(self, path, typ, content):
        """Update only the content about this resource"""
        #Verify that we were given a string object
        if not isinstance(content, types.StringType):
            type_name = type(content).__name__
            raise TypeError("Content must be a string, not %r" % type_name)
        c=self._db.cursor()
        c.execute("""SET AUTOCOMMIT=0""")
        c.execute("""UPDATE ftss_strings SET content = '%s' WHERE path='%s' and type=%d"""%(Escapec.escape(content),str(path), typ))
        
    def deleteFile(self, path, typ):
        """Delete an object"""
        c=self._db.cursor()
        c.execute("""SET AUTOCOMMIT=0""") 
        c.execute("""DELETE FROM ftss_strings where path = '%s' and type = %d"""%(str(path),typ))
       
    def getSystemModel(self):
        return self._systemRdfModel

    def getUserModel(self):
        return self._userRdfModel
    
    def commit(self):
        self._db.commit()
        self._db.close()
        self._db = None
        self._systemRdfModel._db = None
        self._systemRdfModel = None
        self._userRdfModel._db = None
        self._userRdfModel = None
        
    def rollback(self):
        """Undo it"""
        self._db.rollback()
        self._db.close()
        self._db = None
        self._systemRdfModel._db = None
        self._systemRdfModel = None
        self._userRdfModel._db = None
        self._userRdfModel = None


def Begin(**properties):
    """Begin a new transaction.  Every driver must support this interface.
    The properties keyword arguments are passed from the config file
    (or where ever) to the driver.  The Begin file is responsible
    for doing what ever is needed to validate these arguements
    """
    return MySQLDriver(properties['DbName'],
                       properties['Host'],
                       properties['Port'],
                       properties['User'],
                       properties['Passwd'])


NAME='MySQL'
