import logging
import time
import os
import re

from google.appengine.ext import webapp
from google.appengine.api import memcache
from google.appengine.ext.webapp import template
from google.appengine.api import mail

from orangescape.model.server.UserAuthentication import UserAuthentication
from orangescape.model.server.Cookies import Cookies
from CommandFactory import CommandFactory
from orangescape.model.server.util.basicutil import gzip_decompress

from orangescape.model.engine.exception.Error import InstanceNotFoundError
import appconfig as config
from orangescape.model.server.util.ServerUtil import _get_class
from orangescape.model.server.util.metadatautil import searchModelByName
from CommandUtil import dispatchCommand, getUrlParams
import build
from orangescape.model.server.util.basicutil import gzip_compress

log = logging.getLogger(__name__)

class GAECommandFactory(webapp.RequestHandler,CommandFactory):
#    def __init__(self):
#        from orangescape.model.server.GFSSession import PrimaryGFSSession as PrimarySession
#        self.setSession(PrimarySession(getApplication()))

    def logout(self,metadatatype,applicationid):
        cookies = Cookies(self)
        UserAuthentication(self.getSession()).logOutUser(self.userid)
        del cookies['sessionid']
        authInstance = _get_class(config.AUTHENTICATION)()
        self.redirect(authInstance.getLogoutUrl())

    def receiveMail(self, url=None, metadatatype=None, applicationid=None):
        message = mail.InboundEmailMessage(self.request.body)
        plaintext_bodies = message.bodies('text/plain')
        message_subject = message.subject
        message_body=u""
        message_sender = re.split('<|>',message.sender)[1]
        for body in plaintext_bodies:
            message_body+=body[1].decode()
        model_name=self.request.path.split('/')[len(self.request.path.split('/'))-1].split('%40')[0]
        if logging.getLogger().level == logging.DEBUG:
            logging.debug('mailing user: %s'%(message.sender))
            logging.debug('mailed message: %s'%(message))
            logging.debug('Saving in model: %s'%(model_name))
        userinitialization=UserAuthentication(self.session,message_sender)
        userSurrogateId=userinitialization.authenticateUser()
        metadata = searchModelByName(self.getSession().getApplication(),model_name)
        instance = dispatchCommand(self.getSession(),'new', metadata, {'Summary':message_subject,'Description':message_body})
        """Since its newly getting created submit from Start activity"""
        rootBranch = metadata.getWorkFlowRoot()
        if rootBranch:
            startActivity = rootBranch.getActivityDefinitionList()[0]
            dispatchCommand(self.getSession(),'submit', instance, startActivity)
        self.__commit__()

    def __getSubscriptionList__(self, application):
        metadataContext = self.getSession().getApplication()
        appSubscription = metadataContext.getSheetMetadata('ApplicationSubscription')
        refCell = appSubscription.getPublicCellMetadata('Application')
        return [appSub for appSub in self.getSession().getList(application, refCell) if appSub.getValue('Status') == 'ActivityDefinition_6a46e5d5_5951_4c25_9539_a3deaf9eeb28']

    def openModel(self):
        query_string=self.request.query_string
        params = self.getQueryStringParams(query_string)
        metadataContext = self.getSession().getApplication()

        appSubscriptionId = params.get('applicationsubscriptionid')
        if not appSubscriptionId:
            msg = 'Studio can\'t be loaded without applicationsubscriptionid'
            self.response.out.write(msg)
            return msg

        releaseId = params.get('releaseid')
        needsMigration = 0
        if params.get('migrate'):
            needsMigration = int(params.get('migrate'))
        initParams = {'ApplicationSubscriptionId':appSubscriptionId, 'url_scheme':self.request.environ.get('wsgi.url_scheme')}
        versionNumber = "trunk"

        appSubscriptionMetadata = metadataContext.getSheetMetadata('ApplicationSubscription')
        applicationMetadata = metadataContext.getSheetMetadata('Application')
        currentSubscription = self.getSession().get(appSubscriptionId, appSubscriptionMetadata)
        applicationId = currentSubscription.getValue('Application')
        application = self.getSession().get(applicationId, applicationMetadata)

        """Blocking ESIC apps to load the studio using trial. Needs to be removed once all the ESIC apps migrated to NEW Studio."""
        if applicationId in ('Application_3e33f614_dc1c_11de_b6ab_8d4e356e409e','Application_6a7f0985_c2c0_11de_af18_39d4b6a23447','Application_9d997480_b2f8_11de_9786_d7bab8d51d7c','Application_c66ef1f8_b6ee_11de_96dd_65dc25a820a3','Application_e6f5ca82_0a7a_11df_9716_af2651d75c85','Application_e9a76b33_da55_11de_b46b_83553b597d05'):
            oldAppspotUrl = 'http://recent.latest.os-dev.appspot.com/'
            self.response.out.write('Your application requires an older version of Studio. <br>Launch your application Using <a href="%s">Previous Version</a>'%(oldAppspotUrl))
            return 'Your application requires an older version of Studio. <br>Launch your application Using <a href="%s">Previous Version</a>'%(oldAppspotUrl)
        """********************************************************************************"""
        if (not(currentSubscription.getValue('Tenant') == self.getSession().getUser().getValue('Company') and currentSubscription.getValue('AssignedTo') == self.getSession().getUser().getValue('UserId').split('@')[0]) and  needsMigration != 1 and self.getSession().getUser().getValue('SheetId') != application.getValue('Owner')) or  currentSubscription.getValue('Status')!='ActivityDefinition_6a46e5d5_5951_4c25_9539_a3deaf9eeb28':
            msg = 'Your Application %s needs to be migrated, kindly contact your application owner %s'%(application.getSheetName(), application.getValue('ApplicationOwner'))
            self.response.out.write(msg)
            return msg
        elif (not(currentSubscription.getValue('Tenant') == self.getSession().getUser().getValue('Company') and currentSubscription.getValue('AssignedTo') == self.getSession().getUser().getValue('UserId').split('@')[0]) and  needsMigration != 1 and self.getSession().getUser().getValue('SheetId') == application.getValue('Owner')) or  currentSubscription.getValue('Status')!='ActivityDefinition_6a46e5d5_5951_4c25_9539_a3deaf9eeb28':
            msg = 'Your Application %s needs to be migrated, kindly use Migrate and Launch button to migrate.'%(application.getSheetName())
            self.response.out.write(msg)
            return msg
        elif ((not(currentSubscription.getValue('Tenant') == self.getSession().getUser().getValue('Company') and currentSubscription.getValue('AssignedTo') == self.getSession().getUser().getValue('UserId').split('@')[0])) and  needsMigration == 1 and self.getSession().getUser().getValue('SheetId') == application.getValue('Owner')) or  currentSubscription.getValue('Status')!='ActivityDefinition_6a46e5d5_5951_4c25_9539_a3deaf9eeb28':
            from orangescape.model.engine.Component import Component
            from orangescape.model.server.Repair import migrateApplication
            import appconfig
            component = Component(self.session)
            initParams['NeedsMigration'] = 1
            migrateApplication(component,applicationId)
            component.update(application, {'MetadataVersion':appconfig.metadataVersion})
            self.session.commit()
        elif self.getSession().getUser().getValue('SheetId') == application.getValue('Owner') and needsMigration == 1:
            import appconfig
            from orangescape.model.engine.Component import Component
            component = Component(self.session)
            initParams['NeedsMigration'] = 1
            component.update(application, {'MetadataVersion':appconfig.metadataVersion})
            self.session.commit()
        subScipList = self.__getSubscriptionList__(application)
        if len(subScipList)==1:
            initParams['IsSingleUser'] = 1
        if currentSubscription.getValue('ApplicationOwner') == self.getSession().getUser().getValue('SheetId'):
            initParams['AppOwner'] = 1

        if releaseId:
            releaseMetadata = metadataContext.getSheetMetadata('Release')
            parentSheet = self.getSession().get(releaseId, releaseMetadata)
            versionNumber = parentSheet.getValue('VersionNumber')
            referenceCell = metadataContext.getSheetMetadata('ModelRelease').getPublicCellMetadata('Release')
        else:
            releaseId = ''
            parentSheet = application
            referenceCell = metadataContext.getSheetMetadata('SheetMetadata').getPublicCellMetadata('Application')

        modelNames, sheetListStr = self.__getSheetsList__(parentSheet, referenceCell)
        version_appspot_url = ""
        if build.VersionAppspotUrl.get(versionNumber):
            version_appspot_url = build.VersionAppspotUrl.get(versionNumber)
        templatePath = os.path.dirname(__file__).split('model')[0]
        templatePath = os.path.join(templatePath,'studio.html')
        jsonstr = template.render(templatePath, {'applicationid':applicationId, 'sheetidlist':sheetListStr, 'userid':self.userid, 'sheetid':'', 'releaseid':releaseId, 'initParams':initParams, 'version_appspot_url':version_appspot_url})
        self.response.headers['Cache-Control'] = 'no-cache'
        self.response.out.write(jsonstr)

    def reloadModel(self):
        query_string=self.request.query_string

        params = self.getQueryStringParams(query_string)
        metadataContext = self.getSession().getApplication()

        workingSheetId = params.get('workingsheetid')
        applicationId = params.get('applicationid')
        sheetId = params.get('sheetid')
        releaseId = params.get('releaseid')
        modelReleaseId = params.get('modelreleaseid')
        forceUnlock = params.get('forceUnlock')
        lastModifiedAt = float(params.get('lastsyncat'))
        selectedSheetId = None
        sheet = None
        if releaseId:
            parentMetadata = metadataContext.getSheetMetadata('Release')
            metadata = metadataContext.getSheetMetadata('ModelRelease')
            referenceCell = metadata.getPublicCellMetadata('Release')

            parentSheet = self.getSession().get(releaseId, parentMetadata)
            applicationId = parentSheet.getValue('Application')
            if modelReleaseId:
                sheet = self.getSession().get(modelReleaseId, metadata)
                selectedSheetId = sheet.getValue('Attachment')[:-4]
        else:
            parentMetadata = metadataContext.getSheetMetadata('Application')
            metadata = metadataContext.getSheetMetadata('SheetMetadata')
            referenceCell = metadata.getPublicCellMetadata('Application')

            parentSheet = self.getSession().get(applicationId, parentMetadata)
            if sheetId:
                sheet = self.getSession().get(sheetId, metadata)
                selectedSheetId = sheetId
            releaseId = ''
        try:
            if sheet:
                if forceUnlock is None and not (sheet.getValue('ModifiedBy') is None or sheet.getValue('ModifiedBy') == self.userid):
                    lockedBy = self.getSession().get(sheet.getValue('ModifiedBy'), metadataContext.getSheetMetadata('User'))
                    self.response.headers['Cache-Control'] = 'no-cache'
                    self.response.out.write("{'locked': 'Model %s is locked by %s'}"%(sheet.getSheetName(), lockedBy.getSheetName()))
                    return
                if sheet.getValue('ModifiedBy') is None or forceUnlock is not None:
                    logging.info('Locking the sheet %s '%(sheet.getSheetId()))
                    dispatchCommand(self.getSession(), 'update', sheet, {'ModifiedAt':sheet.getValue('ModifiedAt')})

            if workingSheetId and selectedSheetId != workingSheetId:
                workingSheet = self.getSession().get(workingSheetId, metadata)
                logging.info('Releasing the sheet %s '%(workingSheet.getSheetId()))
                dispatchCommand(self.getSession(), 'update', workingSheet, {'ModifiedBy':None, 'ModifiedAt':workingSheet.getValue('ModifiedAt')})

            includes = params.get('includes')
            if includes:
                includes = eval(includes)
            modelNames, sheetListStr = self.__getSheetsList__(parentSheet, referenceCell, lastModifiedAt, includes)
            logging.debug('Reload model response %s'%(sheetListStr))
            self.getSession().commit()
            self.response.headers['Cache-Control'] = 'no-cache'
            self.response.out.write(sheetListStr)
        except Exception, e:
            raise

    def createModel(self):
        """NEED TO REMOVE THIS METHOD"""
        query_string=self.request.query_string
        url_scheme = self.request.environ.get('wsgi.url_scheme')

        params = self.getQueryStringParams(query_string)
        applicationId = params.get('applicationid')
        releaseId = params.get('releaseid')
        metadataContext = self.getSession().getApplication()

        initParams = {}
        if releaseId:
            parentMetadata = metadataContext.getSheetMetadata('Release')
            metadata = metadataContext.getSheetMetadata('ModelRelease')
            referenceCell = metadata.getPublicCellMetadata('Release')
            parentSheet = self.getSession().get(releaseId, parentMetadata)
            applicationId = parentSheet.getValue('Application')
            application = self.getSession().get(applicationId, metadataContext.getSheetMetadata('Application'))
        else:
            parentMetadata = metadataContext.getSheetMetadata('Application')
            metadata = metadataContext.getSheetMetadata('SheetMetadata')
            referenceCell = metadata.getPublicCellMetadata('Application')
            parentSheet = self.getSession().get(applicationId, parentMetadata)
            application = parentSheet
            releaseId = ''

        subScipList = self.__getSubscriptionList__(application)
        currentUserSubscription = [sub for sub in subScipList if sub.getValue('AssignedTo') == self.userid]
        if not currentUserSubscription:
            msg = 'You don\'t have access to this application :%s'%(application.getSheetName())
            self.response.out.write(msg)
            return msg
        if len(subScipList)==1:
            initParams['IsSingleUser'] = 1
        if currentUserSubscription:
            initParams['ApplicationSubscriptionId'] = str(currentUserSubscription[0].getSheetId())

        sheetMetadata = metadataContext.getSheetMetadata('SheetMetadata')
        modelNames, sheetListStr = self.__getSheetsList__(parentSheet, referenceCell)

        newSheetParams = eval(params.get('newsheetparams') or '{}')
        newSheetParams['action'] = 'invoke'
        newSheetParams['invoke'] = 'modeldesign.invoke'
        newSheetParams['method'] = 'createSheet'
        newModelName = newSheetParams.get('SheetName')
        if not newModelName:
            newModelName = 'Untitled_1'
            i=2
            while modelNames.has_key(newModelName.upper()):
                newModelName = 'Untitled_%s'%(i)
                i+=1
            newSheetParams['SheetName'] = newModelName

        elif modelNames.has_key(newModelName.upper()):
            return ("Model with name %s is already exists"%(newModelName))

        if not newSheetParams.has_key('styleId'):
            normalStyle = None
            styleAppRefCell = metadataContext.getSheetMetadata('Style').getPublicCellMetadata('Application')
            for style in self.getSession().getList(application, styleAppRefCell):
                if style.getSheetName()=='Normal':
                    normalStyle = style
                    break
            if normalStyle:
                newSheetParams['styleId'] = normalStyle.getSheetId()
            else:
                logging.warn('Normal style is deleted. New model %s is creating without default style'%(newModelName))
        newSheetQs = '&'.join(['%s=%s'%(k, v) for k, v in newSheetParams.iteritems()])
        initParams['url_scheme'] = url_scheme
        templatePath = os.path.dirname(__file__).split('model')[0]
        templatePath = os.path.join(templatePath,'studio.html')
        jsonstr =  template.render(templatePath, {'applicationid':applicationId,'sheetidlist':sheetListStr, 'userid':self.userid, 'newsheetqs':newSheetQs, 'releaseid':releaseId, 'initParams':initParams})
        self.response.out.write(jsonstr)

    def __getSheetsList__(self, parent, refCell, lastModifiedAt=None, includes=None, excludes=None):
        from cStringIO import StringIO

        allSheetList = self.getSession().getList(parent, refCell)
        if lastModifiedAt:
            sheetList = [sheet for sheet in allSheetList if sheet.getValue('ModifiedAt') > lastModifiedAt or (includes and includes.__contains__(sheet.getSheetId()))]
            logging.debug('Last modified details %s'%([(sheet.getValue('Attachment')[:-4], sheet.getValue('ModifiedAt')) for sheet in allSheetList if (includes and includes.__contains__(sheet.getValue('Attachment')[:-4]))]))
        else:
            sheetList = allSheetList

        buff = StringIO()
        buff.write("{'lockinfo' :{")
        for sheet in allSheetList:
            if sheet.getValue('ModifiedBy'):
                buff.write("'%s':'%s', "%(sheet.getValue('Attachment')[:-4], sheet.getValue('ModifiedBy')))
            else:
                buff.write("'%s':None, "%(sheet.getValue('Attachment')[:-4]))

        buff.write("},'sheetinfo' :{")
        modelNames = {}
        for sheet in sheetList:
            if (not excludes or not excludes.__contains__(sheet.getSheetId())):
                self.__write_sheet_info__(parent, refCell, sheet, buff)
                modelNames[sheet.getSheetName().upper()] = sheet.getValue('Attachment')[:-4]
        buff.write("}}")
        sheetListStr = buff.getvalue()
        return modelNames, sheetListStr

    def __write_sheet_info__(self, parent, refCell, sheet, buff):
        id = sheet.getValue('Attachment')[:-4]
        buff.write("'%s':{"%(id))
        from cStringIO import StringIO
        details = StringIO()

        details.write("'ModifiedAt':%.7f, "%(sheet.getValue('ModifiedAt')+0.0000001))
        if parent.getSheetMetadata().getSheetName()=='Release':
            details.write("'ModelReleaseId':'%s', "%(sheet.getSheetId()))
        buff.write('%s}, '%(details.getvalue()))

    def clearCache(self):
        logging.info('Clearing memcache')
        query_string=self.request.query_string
        queryStringDict = self.getQueryStringParams(query_string)
        cachekey = queryStringDict.get('cachekey')
        if cachekey:
            memcache.delete(cachekey)

    def checkout(self, metadatatype, applicationid, parentsheetmetadataid,taskid,sheetmetadataid,url):
        expirationTime = time.ctime(time.time()+(60*60*24*365))
        try:
            url=getUrlParams(self.request.path)
            url.pop()
            #Application001/1/54321.123/Sheet008/ActivityDefinition_2/Sheet008/Application_2/Cell_001_002_006/Sheet001/SheetMetadata_154.pri/checkout
            metadataType=url.pop(0)
            modifiedIn = url[2]

            fileName=url.pop()
            sheetMetadataId=url.pop()
            referenceCellId=url.pop()
            parentSheetId = url.pop()
            parentSheetMetadataId=url.pop()

            applicationObj = self.getSession().getApplication()
            self.getSession().setModifiedIn(modifiedIn)

            sheetMetadata=applicationObj.getSheetMetadataById(sheetMetadataId)
            parentSheetMetadata=applicationObj.getSheetMetadataById(parentSheetMetadataId)
            parentSheet=self.getSession().get(parentSheetId, parentSheetMetadata)
            referenceCell = sheetMetadata.getCellMetadataById(referenceCellId)

            fileContent = dispatchCommand(self.getSession(),'getAttachment', parentSheet, referenceCell, fileName)

            self.response.headers['Content-Type'] = 'text/plain'
            self.response.headers['Cache-Control'] = 'public'
            self.response.headers['Expires'] = expirationTime
            self.response.headers['Content-Disposition'] = 'attachment; filename="%s"' % fileName
            self.response.out.write(fileContent)
        except InstanceNotFoundError, e:
#                self.response.set_status(404, 'Instance not found %s'%(e))
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.headers['Expires'] = expirationTime
            self.response.headers['Content-Disposition'] = 'attachment; filename="%s"' % fileName
            import pickle
            self.response.out.write(pickle.dumps({}, 0))
        except Exception, e:
            logging.error('Error during checkout %s'%(e))
            self.response.set_status(500)

    def commit(self, applicationid, metadatatype, parentsheetmetadataid, taskid, sheetmetadataid, url):
        content = self.request.body
        fileContent = gzip_decompress(content)
        query_string = self.request.query_string
        url=getUrlParams(self.request.path)
        url.pop()
        metadataType=url.pop(0)
        modifiedIn = url[2]
        params = self.getQueryStringParams(query_string)
        applicationObj = self.getSession().getApplication()
        self.getSession().setModifiedIn(modifiedIn)
        forceUnlock = params.get('forceUnlock')

        fileName = url.pop()
        sheetMetadataId = url.pop()
        referenceCellId = url.pop()
        parentSheetId = url.pop()
        parentMetadataId = url.pop()

        sheetMetadata = applicationObj.getSheetMetadataById(sheetMetadataId)
        parentMetadata = applicationObj.getSheetMetadataById(parentMetadataId)
        referenceCell = sheetMetadata.getCellMetadataById(referenceCellId)
        parentSheet = self.getSession().get(parentSheetId, parentMetadata)

        if fileName.endswith('.pri'):
            sheetParams = {}
            for k, v in params.iteritems():
                if k != 'ModifiedAt' and k!= 'ModifiedBy' and sheetMetadata.getPublicCellMetadataDict().has_key(k):
                    sheetParams[k] = v

            sheetId = fileName[:-4]
            sheet = dispatchCommand(self.getSession(), 'getAttachmentInstance', parentSheet, referenceCell, fileName)
            lastModifiedAt = params.get('ModifiedAt')
            lastSyncAt = params.get('lastsyncat')
#            logging.debug('LastModifiedAt %s lastSyncAt %s'%(lastModifiedAt, lastSyncAt))
            if forceUnlock is None and sheet and sheet.getValue('ModifiedBy') and sheet.getValue('ModifiedBy') != self.userid:
                lockedUser = self.session.get(sheet.getValue('ModifiedBy'), applicationObj.getSheetMetadata('User'))
                errMsg = "{'Error':%s }"%(['Save failed! This model is Locked by the user %s. He might unlock the model and loaded '%(lockedUser.getSheetName())])
                self.response.out.write(errMsg)
                return

            if lastModifiedAt and sheet:
                logging.debug('Save %s %s %s'%(float(lastModifiedAt) > sheet.getValue('ModifiedAt'), (lastModifiedAt), sheet.getValue('ModifiedAt')))
            if forceUnlock is None and sheet and lastModifiedAt and float(lastModifiedAt) < sheet.getValue('ModifiedAt'):
                errMsg = "{'Error':%s}"%(['Save failed! You have older version of the model. Which might be loaded from the cache data.', 'Please clear the cache and reload the model from \"Server\" and Save the changes.'])
                self.response.out.write(errMsg)
                return

            if not sheet:
                newSheetName = sheetParams.get('SheetName')
                sheetNames = [existingSheet.getSheetName().upper() for existingSheet in self.getSession().getList(parentSheet, referenceCell)]
                if sheetNames.__contains__(newSheetName.upper()):
                    return 'Model with name "%s" already exists. Please Rename & save.'%(newSheetName)

#                logging.debug('Creating new sheet with the id %s'%(sheetId))
                if sheetMetadataId=='Sheet001':
                    sheet = dispatchCommand(self.getSession(),'create', parentSheet, referenceCell, sheetParams, sheetId)
                else:
                    sheet = dispatchCommand(self.getSession(),'create', parentSheet, referenceCell, sheetParams)
#                logging.debug('New Sheet created %s'%(sheet.getSheetName()))
            elif len(sheetParams)>0:
                """Updating sheet info"""
#                logging.debug('Updating sheet info %s'%(sheetParams))
                sheet = dispatchCommand(self.getSession(), 'update', sheet, sheetParams)
            else:
                sheet = dispatchCommand(self.getSession(), 'update', sheet, {})
            dispatchCommand(self.getSession(),'updateAttachmentWithId', sheet, fileName, fileContent, params.get('tag'))
        else:
#            logging.debug('Updating attachment %s %s %s'%(parentSheet.getSheetName(), referenceCell, fileName))
            dispatchCommand(self.getSession(),'updateAttachment', parentSheet, referenceCell, fileName, fileContent, params.get('tag'))

        if params.get('release'):
            logging.debug('Releasing sheet %s'%(sheet.getSheetName()))
            dispatchCommand(self.getSession(),'update', sheet, {'ModifiedBy':None, 'ModifiedAt':sheet.getValue('ModifiedAt')})

        responseStr = ['{']
        callback = params.get('slcallback')
        if callback:
            responseStr.append("'slcallback':'%s', "%(callback))
        if fileName.endswith('.pri'):
            selectedSheetId = params.get('selectedsheetid')
            if selectedSheetId:
                selectedSheet = self.getSession().get(selectedSheetId, sheetMetadata)
                if forceUnlock is not None or selectedSheet.getValue('ModifiedBy') is None or selectedSheet.getValue('ModifiedBy') == self.userid:
                    modelNames, sheetListStr = self.__getSheetsList__(parentSheet, referenceCell, lastSyncAt, [selectedSheetId], [sheet.getSheetId()])
                    responseStr.append("'syncresponse' : {'ModifiedAt':%.7f}, 'reloadresponse' : %s"%(sheet.getValue('ModifiedAt')+0.0000001, sheetListStr))
                    if (forceUnlock is not None and selectedSheet.getValue('ModifiedBy') != self.userid) or selectedSheet.getValue('ModifiedBy') is None:
                        logging.debug('Locking the sheet %s '%(selectedSheet.getSheetId()))
                        dispatchCommand(self.getSession(), 'update', selectedSheet, {'ModifiedAt':selectedSheet.getValue('ModifiedAt')})
                    dispatchCommand(self.getSession(), 'update', sheet, {'ModifiedBy':None, 'ModifiedAt':sheet.getValue('ModifiedAt')})
                else:
                    lockedBy = self.getSession().get(selectedSheet.getValue('ModifiedBy'), applicationObj.getSheetMetadata('User'))
                    responseStr.append("'syncresponse' : {'ModifiedAt':%.7f}, 'reloadresponse' : {'locked': 'Model %s is locked by %s'}"%(sheet.getValue('ModifiedAt')+0.0000001, selectedSheet.getSheetName(), lockedBy.getSheetName()))
            else:
#                responseStr = "{'syncresponse' : {'ModifiedAt':%.7f}}"%(sheet.getValue('ModifiedAt')+0.0000001)
                responseStr.append("'syncresponse' : {'ModifiedAt':%.7f}"%(sheet.getValue('ModifiedAt')+0.0000001))
        self.getSession().commit()
        responseStr.append('}')
        self.response.out.write(''.join(responseStr))

    def serializeApplication(self,metadatatype,applicationid,parentsheetmetadataid,taskid,sheetmetadataid,url):
        """GET /Instances/id: Show a specific item."""
        url=getUrlParams(self.request.path)
        #Application001/1/Sheet008/ActivityDefinition_2/Sheet008/Application_2/application
        url.pop()
        url.pop(0)
        modifiedIn = url[2]

        sheetId=url.pop()
        sheetMetadataId=url.pop()

        applicationObj = self.getSession().getApplication()
        self.getSession().setModifiedIn(modifiedIn)
        sheetMetadata=applicationObj.getSheetMetadataById(sheetMetadataId)
        sheet=self.getSession().get(sheetId, sheetMetadata)
        from orangescape.model.server.util.privateserializer import SheetSerializer

        appData = SheetSerializer(self.getSession(), sheet, {'Sheet008' : ['CellMetadata_99dcc7f8_f829_4da1_8d4f_a00c57684e45', 'Cell_001_002_006', 'Cell_016_002_006']}, True).serializeSubscription()
        import cPickle as pickle
        appPck = pickle.dumps(appData, 0)
        self.response.out.write(appPck)

    def serializeFormData(self, metadatatype, applicationid, parentsheetmetadataid, taskid, sheetmetadataid, url):
        """GET /Instances/id: Show a specific item."""
        url=getUrlParams(self.request.path)
        url.pop()
        url.pop(0)
        modifiedIn = url[2]

        sheetId=url.pop()
        sheetMetadataId=url.pop()

        applicationObj = self.getSession().getApplication()
        self.getSession().setModifiedIn(modifiedIn)
        sheetMetadata=applicationObj.getSheetMetadataById(sheetMetadataId)
        sheet=self.getSession().get(sheetId, sheetMetadata)
        from orangescape.model.server.util.privateserializer import SheetSerializer

        formMetadata = self.getSession().getApplication().getSheetMetadata('Form')
        excludeList  = {'Sheet001' : [refCell.getSheetId() for refCell in sheetMetadata.getOneToManyList() if refCell.getSheetMetadata().getSheetName()!='Form'],
                        formMetadata.getSheetId() : [refCell.getSheetId() for refCell in formMetadata.getOneToManyList() if refCell.getSheetMetadata().getSheetName()!='Form']
                        }
        formData = SheetSerializer(self.getSession(), sheet, excludeList, True).serializeSheet()
        import cPickle as pickle
        formPck = pickle.dumps(formData, 0)
        self.response.out.write(formPck)

    def modelversions(self, applicationid, metadatatype, parentsheetmetadataid, taskid, sheetmetadataid, url):
        urlParamList=getUrlParams(self.request.path)
        query_string = self.request.query_string
        url=getUrlParams(self.request.path)
        url.pop()
        downloadUrl = '/'.join(url)
        url.pop(0)

        sheetId=url.pop()
        sheetMetadataId=url.pop()
        applicationObj = self.getSession().getApplication()

        sheetMetadata=applicationObj.getSheetMetadataById(sheetMetadataId)
        sheet=self.getSession().get(sheetId, sheetMetadata)

        baseQuery = {}
        params = self.getQueryStringParams(query_string)
        orderBy = params.get('orderby') or 'versionedAt'
        limit = params.get('limit')
        limit=int(limit) if limit else 50

        isDescending = params.get('descending')
        if isDescending:
            isDescending = eval(isDescending)
        else:
            isDescending = True

        versionList = self.getSession().getAttachmentVersionList(sheetId, {}, orderBy=orderBy, isDescending = isDescending, limit=limit)
        template_values = {
            'modelName': sheet.getSheetName(),
            'versionList': versionList,
            'downloadurl':downloadUrl+'/downloadversion',
            'replaceurl':downloadUrl+'/replaceattachment'
            }
        templatePath = os.path.dirname(__file__).split('model')[0]
        templatePath = os.path.join(templatePath,'templates','viewversions.html')
        response  = template.render(templatePath, template_values)
        self.response.out.write(response)

    def downloadversion(self, applicationid, metadatatype, parentsheetmetadataid, taskid, sheetmetadataid, url):
        urlParamList=getUrlParams(self.request.path)
        query_string = self.request.query_string
        url=getUrlParams(self.request.path)
        url.pop()
        url.pop(0)

        sheetId=url.pop()
        sheetMetadataId=url.pop()
        applicationObj = self.getSession().getApplication()

        params = self.getQueryStringParams(query_string)
        versionId = params.get('versionid')
        version = self.getSession().getVersion(versionId)
        fileName = sheetId+'.pri',
        response = gzip_compress(version)
        self.response.headers['Content-Disposition'] = 'attachment; filename="%s"' % fileName
        self.response.out.write(response)

    def replaceAttachment(self, applicationid, metadatatype, parentsheetmetadataid, taskid, sheetmetadataid, url):
        url=getUrlParams(self.request.path)
        query_string = self.request.query_string
        url.pop()
        url.pop(0)

        sheetId=url.pop()
        sheetMetadataId=url.pop()
        applicationObj = self.getSession().getApplication()

        sheetMetadata=applicationObj.getSheetMetadataById(sheetMetadataId)
        sheet=self.getSession().get(sheetId, sheetMetadata)

        if sheet.getValue('ModifiedBy') is None:
            dispatchCommand(self.getSession(), 'update', sheet, {'ModifiedBy':None})
            self.getSession().commit()
        elif sheet.getValue('ModifiedBy') != self.userid:
            lockedBy = self.getSession().get(sheet.getValue('ModifiedBy'), applicationObj.getSheetMetadata('User'))
            return ("Model %s is locked by %s"%(sheet.getSheetName(), lockedBy.getSheetName()))
        else:
            dispatchCommand(self.getSession(), 'update', sheet, {})
            self.getSession().commit()


        params = self.getQueryStringParams(query_string)
        versionId = params.get('versionid')
        self.getSession().replaceAttachment(sheetId, versionId)
        self.response.out.write('Version Replaced')

    def schemaSync(self, metadatatype=None, applicationid=None):
        from orangescape.model.server.sql import engine
        from orangescape.model.server.sql.classes import Base
        Base.metadata.create_all(engine)
        logging.info('Tables created successfully')

    def dropTables(self, metadatatype=None, applicationid=None):

        from sqlalchemy.engine import create_engine
        from sqlalchemy.engine.url import URL

        from orangescape.model.server.sql.SchemaGenerator import SchemaGen
        from orangescape.model.server.Context import getApplication

        DATABASE_NAME = config.SQL_SCHEMA
        engine = create_engine(URL('mysql+googledialect', database=DATABASE_NAME, username='root', password='root'),instance=config.SQL_INSTANCE, paramstyle='format')
        logging.info('SQL Engine created successfully')
        schemaGenerator = SchemaGen(getApplication(), DATABASE_NAME, True)

        schemaGenerator.generate()
        logging.info('SQL Metadata generated')
        schemaGenerator.drop_tables(engine)
        logging.info('Tables dropped successfully')

    def backendStart(self):
        logging.info('Backend instance is getting started')