import wsgiref.handlers
import logging
from google.appengine.ext import db
import os
import datetime
import time

from orangescape.model.server.util.ServerUtil import _get_class
from orangescape.model.server.util.gfsutil import put
from orangescape.model.server.db.pickleUtil import unPickleStr, doPickle
import appconfig as config
import hashlib

def copyChange(d):
    changeDuplicate = dict()
    for modelId, data in d.iteritems():
        changeDuplicate[modelId] = dict(data)
    return changeDuplicate

def __create_dataobject__(entityClass, dictObject):
    dataObject = entityClass(key_name=dictObject['SheetId'])
    dataObject._dynamic_properties = dictObject
    dataObject.SheetId = dictObject['SheetId']
    dataObject.SheetMetadataId = dictObject['SheetMetadataId']
    dataObject.ApplicationId = dictObject['ApplicationId']
    return dataObject

class AppSetupService():

    def __init__(self, component):
        self.component = component
        self.session = component.getSession()
        self.dataObjects = None

        self.application = self.session.getApplication()
        self.directReplaceDict = {self.getSheetMetadata('Formula').getSheetId():[self.getSheetMetadata('Formula').getPublicCellMetadata('CellBelongingSheetId').getSheetId()],
                                  self.getSheetMetadata('Node').getSheetId():[self.getSheetMetadata('Node').getPublicCellMetadata('CellBelongingSheetId').getSheetId(), self.getSheetMetadata('Node').getPublicCellMetadata('ReferredSheetId').getSheetId()],
                                  self.getSheetMetadata('Branch').getSheetId():[self.getSheetMetadata('Branch').getPublicCellMetadata('EditorGridView').getSheetId(), self.getSheetMetadata('Branch').getPublicCellMetadata('InboxGridView').getSheetId(), self.getSheetMetadata('Branch').getPublicCellMetadata('Root').getSheetId()],
                                  self.getSheetMetadata('ActivityDefinition').getSheetId():[self.getSheetMetadata('ActivityDefinition').getPublicCellMetadata('Root').getSheetId(), 'CellMetadata_b0af5bb8_f3d3_4256_8000_41b728083eae', 'CellMetadata_d3befa88_1c14_4a6c_9ad5_75422c011cd2']
                            }

    def getSheetMetadata(self, sheetName):
        return self.application.getSheetMetadata(sheetName)

    def insertAppRecords(self, application, data):
        applicationId = application.getSheetId()
        logging.debug('Creating Application records for the application %s(%s) no.of records %d'%(application.getSheetName(), applicationId, len(data)))
        applicationUUId = self.__getAppUUID__(application)

        modifiedAt = time.time()
        dataObjects =  [self.__create_dataobject__(self.__update_ids__(data, data[key], applicationId, applicationUUId), modifiedAt) for key in data if data[key]['SheetMetadataId'] not in ('Sheet008', 'SheetMetadata_84a3daef_6a75_4e9a_8551_db5cfe288f12', 'SheetMetadata_300')]
        self.session.put_into_datastore(dataObjects)
        logging.debug('%s Application records created'%(len(dataObjects)))

    def __getAppUUID__(self, application):
        applicationId = application.getSheetId()
        return applicationId[applicationId.find('_'):] if applicationId.__contains__('_') else applicationId

    def copySheet_n_Attachments(self, application, templateApp):
        sheetMetadata = self.session.getApplication().getSheetMetadata('SheetMetadata')
        sheetAppRefCell = sheetMetadata.getPublicCellMetadata('Application')

        applicationId = application.getSheetId()
        applicationUUId = self.__getAppUUID__(application)

        modifiedAt = time.time()

        objList = []
        attachmentList = []

        for sheet in self.session.getList(templateApp, sheetAppRefCell):
            fileName, content = self.component.getAttachmentWithId(sheet)
            data = unPickleStr(content)
            newData = self.__update_sheet_record_ids__(applicationId, applicationUUId, data)

#            sheetRecord = newData[sheet.getSheetId()+applicationUUId]
            sheetRecord = newData[self.__generate_new_id__(sheet.getSheetId(), applicationUUId)]
            sheetRecord['CellMetadata_62331760_f14d_4902_a1b0_b7829653be10'] = sheetRecord['SheetId']+'.pri'
            dataObject = self.__create_dataobject__(sheetRecord, modifiedAt)
            attachment = self.__create_attachment__(sheetRecord, newData)

            objList.append(dataObject)
            attachmentList.append(attachment)

        self.session.put_into_datastore(objList)
        for attachment in attachmentList:
            attachment.put()
        logging.debug('%s sheet details and %s attachments copied from app %s'%(len(objList), len(attachmentList), templateApp.getSheetName()))

    def createSheet_n_Attachments(self, application):
        import pkgutil
        from orangescape.tests.functional.dev import primary
        package = primary
        applicationId = application.getSheetId()
        applicationUUId = self.__getAppUUID__(application)

        modifiedAt = time.time()

        objList = []
        attachmentList = []
        for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
            if modname != primary.appId:
                d = _get_class('orangescape.tests.functional.dev.primary.%s.%s'%(modname, modname))
                data = copyChange(d)
                newData = self.__update_sheet_record_ids__(applicationId, applicationUUId, data)

#                sheetRecord = newData[modname+applicationUUId]
                sheetRecord = newData[self.__generate_new_id__(modname, applicationUUId)]

                sheetRecord['CellMetadata_62331760_f14d_4902_a1b0_b7829653be10'] = sheetRecord['SheetId']+'.pri'
                sheetRecord[self.getSheetMetadata('SheetMetadata').getPublicCellMetadata('MetadataVersion').getSheetId()] = config.metadataVersion

                dataObject = self.__create_dataobject__(sheetRecord, modifiedAt)
                attachment = self.__create_attachment__(sheetRecord, newData)

                objList.append(dataObject)
                attachmentList.append(attachment)

        self.session.put_into_datastore(objList)
        for attachment in attachmentList:
            attachment.put()

    def __generate_new_id__(self, id, appUUId):
        new_id = id + appUUId
        hasher = hashlib.md5()
        hasher.update(new_id)
        hashed_id = hasher.hexdigest()
        return id[:2]+hashed_id

    def __update_ids__(self, dataDict, dictObject, applicationId, applicationUUId):
        metadata = self.session.getApplication().getSheetMetadataById(dictObject['SheetMetadataId'])

#        newSheetId = dictObject['SheetId']+applicationUUId
        newSheetId = self.__generate_new_id__(dictObject['SheetId'], applicationUUId)
        dictObject['SheetId'] = newSheetId
        dictObject['ApplicationId'] = applicationId
        dictObject[metadata.getPublicCellMetadata('SheetId').getSheetId()] = newSheetId

        if self.directReplaceDict.__contains__(dictObject['SheetMetadataId']):
            for cellId in self.directReplaceDict[dictObject['SheetMetadataId']]:
                if dictObject.__contains__(cellId):
                    if isinstance(dictObject[cellId], str) or isinstance(dictObject[cellId], unicode):
#                        dictObject[cellId]+= applicationUUId
                        dictObject[cellId] = self.__generate_new_id__(dictObject[cellId], applicationUUId)

        if (metadata.getSheetName()=='CellMetadata' or metadata.getSheetName()=='Node'):
            sheetNameCell = metadata.getPublicCellMetadata('SheetName')
            value = dictObject.get(sheetNameCell.getSheetId())
            if value and value.__contains__('-'):
#                print metadata.getSheetName(), 'SheetName', value, ':::', self.__generate_new_id__(value[:value.rfind('-')], applicationUUId)+value[value.rfind('-'):]
                dictObject[sheetNameCell.getSheetId()]=self.__generate_new_id__(value[:value.rfind('-')], applicationUUId)+value[value.rfind('-'):]

        elif metadata.getSheetName()=='InputportMetadata':
            paramNameCell = metadata.getPublicCellMetadata('ParamName')
            stringValueCell = metadata.getPublicCellMetadata('StringValue')
            paramName = dictObject.get(paramNameCell.getSheetId())
            if paramName and paramName in ('CallAction-Name', 'ParentAction-Name', 'CallAction-Name', 'SLA-Action', 'Action-Name', 'Model-Name', 'Context-CellName', 'Submit-From'):
                stringValue = dictObject.get(stringValueCell.getSheetId())
                if stringValue:
                    dictObject[stringValueCell.getSheetId()] = self.__generate_new_id__(dictObject[stringValueCell.getSheetId()], applicationUUId)
#                    dictObject[stringValueCell.getSheetId()]+= applicationUUId
            elif paramName and self.__generate_new_id__(paramName, applicationUUId) == dictObject['SheetId']:
                """Its a id so replace the ParamName also"""
                dictObject[paramNameCell.getSheetId()] = self.__generate_new_id__(dictObject[paramNameCell.getSheetId()], applicationUUId)
#                dictObject[paramNameCell.getSheetId()]+= applicationUUId

        elif metadata.getSheetName()=='OutputportMetadata':
            paramNameCell = metadata.getPublicCellMetadata('ParamName')
            paramName = dictObject.get(paramNameCell.getSheetId())
            if dataDict.has_key(paramName):
                """Its a id so replace the ParamName also"""
                dictObject[paramNameCell.getSheetId()] = self.__generate_new_id__(dictObject[paramNameCell.getSheetId()], applicationUUId)
#                dictObject[paramNameCell.getSheetId()]+= applicationUUId
        elif metadata.getSheetName()=='SheetMetadata':
            if dictObject.has_key('BelongingSheetId'):
                del dictObject['BelongingSheetId']

        sheetNameCell = metadata.getPublicCellMetadata('SheetName')
        sheetNameVal = dictObject.get(sheetNameCell.getSheetId())
        if sheetNameVal and self.__generate_new_id__(str(sheetNameVal), applicationUUId) == dictObject['SheetId']:
            dictObject[sheetNameCell.getSheetId()] = self.__generate_new_id__(dictObject[sheetNameCell.getSheetId()], applicationUUId)

        if metadata.getPublicCellMetadataDict().has_key('BelongingSheetId'):
            belongingSheetIdCell = metadata.getPublicCellMetadata('BelongingSheetId')
            if dictObject.has_key(belongingSheetIdCell.getSheetId()):
                dictObject[belongingSheetIdCell.getSheetId()] = self.__generate_new_id__(dictObject[belongingSheetIdCell.getSheetId()], applicationUUId)
                dictObject['BelongingSheetId'] = dictObject[belongingSheetIdCell.getSheetId()]

        for referenceCell in metadata.getManyToOneList():
            refCellValue = dictObject.get(referenceCell.getSheetId())
            if refCellValue is not None:
                if referenceCell.getReferredSheetMetadata().getSheetName()=='Application':
                    dictObject[referenceCell.getSheetId()] = applicationId
                elif referenceCell.getReferredSheetMetadata().getSheetName()=='User':
                    del dictObject[referenceCell.getSheetId()]
                else:
                    if isinstance(dictObject[referenceCell.getSheetId()], str) or isinstance(dictObject[referenceCell.getSheetId()], unicode):
                        dictObject[referenceCell.getSheetId()] = self.__generate_new_id__(dictObject[referenceCell.getSheetId()], applicationUUId)
                    else:
                        del dictObject[referenceCell.getSheetId()]
                        logging.error('Removing invalid reference cell value %s for the cell %s in the model %s'%(referenceCell, refCellValue, metadata.getSheetName()))

        if self.session.getUser() is not None:
            if metadata.getSheetName()=='SheetMetadata':
                dictObject[metadata.getPublicCellMetadata('ModifiedBy').getSheetId()] = None
            else:
                dictObject[metadata.getPublicCellMetadata('ModifiedBy').getSheetId()] = self.session.getUser().getSheetId()
            dictObject[metadata.getPublicCellMetadata('CreatedBy').getSheetId()] = self.session.getUser().getSheetId()
        else:
            dictObject[metadata.getPublicCellMetadata('CreatedBy').getSheetId()] = dictObject[metadata.getPublicCellMetadata('ModifiedBy').getSheetId()] = None

        return dictObject

    def __create_dataobject__(self, dictObject, modifiedAt):
        dataObject = self.session.createDataObject(None, dictObject['SheetId'])
        dataObject._dynamic_properties = dictObject
        dataObject.SheetId = dictObject['SheetId']
        dataObject.SheetMetadataId = dictObject['SheetMetadataId']
        dataObject.ApplicationId = dictObject['ApplicationId']
        dataObject.ModifiedAt = modifiedAt
        return dataObject

    def __update_sheet_record_ids__(self, applicationId, applicationUUId, data):
        newData = {}
        for id, record in data.iteritems():
            newRecord = self.__update_ids__(data, record, applicationId, applicationUUId)
            newData[newRecord['SheetId']] = newRecord
        return newData

    def __create_attachment__(self, sheetRecord, data):
        attachment = self.session.createAttachment(sheetRecord['SheetId'])
        attachment.content = self.session.__compress__(doPickle(data))
        return attachment
