import sys,os
from Ft.Server.Client.Commands import CommandUtil
from Ft.Server.Client import Core
from stat import ST_MTIME
from Ft.Server.Common import AclConstants, ResourceTypes

g_mimeMap = {'.html':'text/html',
             '.xml':'text/xml',
             '.gif': 'image/gif',
             '.png': 'image/png',
             '.jpg': 'image/jpeg',
             '.jpeg': 'image/jpeg',
             }


def Mirror(fsbase,
           ftssbase,
           repo,
           ftssReadAcl,
           ftssWriteAcl):

    """This is the function that does the mirroring.  It will connect to 4SS and see what has changed. and update accordingly.

    fsbase is the filesystem base directory
    ftssbase is the directory to root from in 4SS
    ftssUserName is the name of the 4SS user to use
    ftsspasswdhash is the password hash of the 4SS user
    ftssReadAcl is the acl read ident of new files (None means world access)
    ftssWriteAcl is the acl write ident of the new files (None means world access)
    """


    #Some validation
    if not os.path.exists(fsbase):
        raise Exception("No such file or directory %s" % fsbase)
    if not os.path.isdir(fsbase):
        raise Exception("%s is not a directory" % fsbase)

    if not repo.hasResource(ftssbase):
        print "Creating base container"
        root = repo.createContainer(ftssbase,createParents = 1)
    else:
        root = repo.fetchResource(ftssbase)

    MirrorFsContainer(root,fsbase,ftssReadAcl,ftssWriteAcl)
    #See if there is anything to update the other way
    Mirror4ssContainer(root,fsbase)



def MirrorFsContainer(ftRoot,fsDir,readAcl,writeAcl):
    """Mirror a fs container into 4SS"""


    for fileName in os.listdir(fsDir):
        fullPath = os.path.join(fsDir,fileName)
        if os.path.isdir(fullPath):
            if not ftRoot.hasResource(fileName):
                print "Creating Container %s" % fullPath
                nextCont = ftRoot.createContainer(fileName)
                nextCont.setAcl(AclConstants.READ_ACCESS,readAcl,AclConstants.ALLOWED)
                nextCont.setAcl(AclConstants.WRITE_ACCESS,writeAcl,AclConstants.ALLOWED)
            else:
                nextCont = ftRoot.fetchResource(fileName)
            MirrorFsContainer(nextCont,fullPath,readAcl,writeAcl)
        else:
            MirrorFsFile(ftRoot,fullPath,readAcl,writeAcl)

def MirrorFsFile(ftRoot,filePath,readAcl,writeAcl):
    fileName = os.path.split(filePath)[1]

    if ftRoot.hasResource(fileName):
        doc = ftRoot.fetchResource(fileName)
        mtime = os.stat(filePath)[ST_MTIME]
        modified = float(mtime) > float(doc.getLastModifiedDate())
        if modified:
            print "Mirroring %s --> 4SS/%s/%s" % (filePath,ftRoot.getAbsolutePath(),fileName)
            try:
                f = open(filePath)
                src = f.read()
                f.close()
            except IOError:
                sys.stderr.write("Unable to read file %s" % filePath)
            doc.setContent(src)
            
    else:
        print "Mirroring %s --> 4SS/%s/%s" % (filePath,ftRoot.getAbsolutePath(),fileName)
        try:
            f = open(filePath)
            src = f.read()
            f.close()
        except IOError:
            sys.stderr.write("Unable to read file %s" % filePath)
        else:
            doc = ftRoot.createRawFile(fileName,
                                       g_mimeMap.get(os.path.splitext(fileName)[1],'text/text'),
                                       src)
            doc.setAcl(AclConstants.READ_ACCESS,readAcl,AclConstants.ALLOWED)
            doc.setAcl(AclConstants.WRITE_ACCESS,writeAcl,AclConstants.ALLOWED)

def Mirror4ssContainer(root,baseDir):
    """Mirror a 4ss container into the file system"""


    for child in root:
        fullPath = os.path.join(baseDir,os.path.split(child.getAbsolutePath())[1])
        if child.isResourceType(ResourceTypes.ResourceType.CONTAINER):
            if not os.path.isdir(fullPath):
                print "Mirroring %s <-- 4SS%s" % (fullPath,child.getAbsolutePath())
                os.mkdir(fullPath)
            Mirror4ssContainer(root.fetchResource(child.getAbsolutePath()),
                               fullPath)
                               
        elif child.isResourceType(ResourceTypes.ResourceType.RAW_FILE):
            if not os.path.exists(fullPath):
                print "Mirroring %s <-- 4SS%s" % (fullPath,child.getAbsolutePath())
                doc = root.fetchResource(child.getAbsolutePath())
                f = open(fullPath,'w')
                f.write(doc.getContent())
                f.close()



if __name__ == '__main__':

    readAcl = AclConstants.WORLD_GROUP_NAME
    writeAcl = AclConstants.WORLD_GROUP_NAME
    fsbase = None
    ftssbase = None

    for a in sys.argv[1:]:
        if a[:7] == '--read=':
            readAcl = a[7:]
        elif a[:8] == '--write=':
            writeAcl = a[8:]
        elif fsbase is None:
            fsbase = a
        elif ftssbase is None:
            ftssbase = a
        else:
            raise Exception("Unknown Argument %s" % a)

    if fsbase is None or ftssbase is None:
        raise Exception("Invalid Command line, please see the READ file")

    repo = CommandUtil.GetRepository({},None)

    commit = 0
    try:
        Mirror(fsbase,
               ftssbase,
               repo,
               readAcl,
               writeAcl)
        commit = 1
    finally:
        if commit:
            repo.txCommit()
        else:
            repo.txRollback()
