from cStringIO import StringIO
from orangescape.model.server.util.ConversionUtil import getCellCategory
from orangescape.model.server.util.SerializeUtil import getDisplayCellName
from orangescape.model.server.util.json import write_object_key_value, write
from orangescape.model.server.commands.CommandUtil import getUrlParams

import logging
import sys

includeSysCells = ('SheetId', 'SheetName', 'SheetMetadataName', 'CreatedAt', 'ModifiedAt', 'CreatedBy', 'ModifiedBy', 'Caption', 'AssignedTo', 'Status')
filterList = ('User Input', 'Master Lookup')

def serializeCells(metadata, buff, referenceCell=None):
    refCells = []
    for cell in metadata.getCellMetadataList():
        if cell.getRowNumber()>0 or cell.getCellName() in includeSysCells:
            buff.append('"')
            if referenceCell:
                buff.append('%s.%s'%(referenceCell.getCellName(), cell.getCellName()))
            else:
                buff.append(cell.getCellName())
            buff.append('":"')
            if cell.isReferenceCell():
                buff.append(cell.getReferredSheetMetadata().getSheetName())
                refCells.append(cell)
            else:
                buff.append(getCellCategory(cell))
            buff.append('"')
            buff.append(',')
    return refCells
#            if not referenceCell and cell.isReferenceCell():
#                serializeCells(cell.getReferredSheetMetadata(), buff, cell)

def serializeCondition(condition, buff, path, configfilter=None):
    if condition.getLHSCellMetadata() and condition.getRHSParamType() and condition.getRHSValue() and condition.getRHSParamType() in filterList:
        if len(buff)> 0:
            buff.append(',')
        buff.append(write(condition.getRHSValue()))
        buff.append(':{')
        buff.append(write("Datatype"))
        buff.append(':')
        buff.append(write(getCellCategory(condition.getLHSCellMetadata())))
        buff.append(',')

        buff.append(write("Format"))
        buff.append(':')
        buff.append(write(condition.getLHSCellMetadata().getFinalFormat()))
        buff.append(',')

        buff.append(write("FilterType"))
        buff.append(':')
        buff.append(write(condition.getRHSParamType()))
        buff.append(',')

        buff.append(write("FilterName"))
        buff.append(':')
        buff.append(write(condition.getRHSValue()))
        buff.append(',')

        if configfilter and condition.getRHSValue() in configfilter.keys() and 'hide' in configfilter[condition.getRHSValue()]:
            logging.info(configfilter[condition.getRHSValue()])
            buff.append(write("Hide"))
            buff.append(':')
            buff.append(write(configfilter[condition.getRHSValue()]['hide']))
            buff.append(',')

        if configfilter and condition.getRHSValue() in configfilter.keys():
            buff.append(write("DisplayValue"))
            buff.append(':')
            buff.append(write(configfilter[condition.getRHSValue()]['display']))
        else:
            buff.append(write("DisplayValue"))
            buff.append(':')
            buff.append(write(condition.getRHSValue()))

        if condition.getSearchDefinitionList():
            buff.append(',')
            buff.append(write("URL"))
            buff.append(':"')
            buff.append(path+"/")
            buff.append(condition.getSearchDefinitionList()[0].getSheetId()+'"')

        buff.append('}')
        return ''.join(buff)

def serializeMetaInfo(metadata):
    buff = ['"table":"']
    buff.append(metadata.getSheetName())
    buff.append('",\n"columns":{')
    for refCell in serializeCells(metadata, buff):
        serializeCells(refCell.getReferredSheetMetadata(), buff, refCell)
    buff.pop()
    buff.append('}')
    return ''.join(buff)

def serializeMetaInfoWithFilter(metadata,searchDef,path):
    buff = ['"table":"']
    buff.append(metadata.getSheetName())
    buff.append('",\n"columns":{')
    for refCell in serializeCells(metadata, buff):
        serializeCells(refCell.getReferredSheetMetadata(), buff, refCell)
    buff.pop()
    buff.append('},"filter":{')
    buff.append(serializeFilterInfo(searchDef,path))
    buff.append('}')
    return ''.join(buff)

def serializeFilterInfo(searchDef,path,configfilter=None):
    buff = []
    if searchDef.getCriteriaList().__len__()>0 :
        criteria=searchDef.getCriteriaList().pop()
        serializeCriteria(criteria, buff, path, configfilter)
        return ''.join(buff)

def serializeCriteria(criteria, buff, path, configfilter):
    if criteria.getConditionList().__len__()>0:
        conditionList = criteria.getConditionList()
        conditionList.sort(lambda x, y: cmp(x.getValue('CreatedAt'), y.getValue('CreatedAt')))
        for condition in conditionList:
            serializeCondition(condition, buff, path, configfilter)
    for childCriteria in criteria.getCriteriaList():
        serializeCriteria(childCriteria, buff, path, configfilter)

class ReportKeysSerializer:
    def __init__(self, session):
        self.session = session
        self.file_str = StringIO()

    def write(self, val):
        self.file_str.write(val)

    def serializeKeys(self, metadata, keys):
        self.write('{')
        self.write(serializeMetaInfo(metadata))
        self.write(',\n"keys":')
        if len(keys)>0:
            self.write('["'+'","'.join(keys)+'"]')
        else:
            self.write('[]')
        self.write('}')
        return self.getValue()

    def getValue(self):
        return self.file_str.getvalue()

class ReportSyncSerializer:
    def __init__(self, session):
        self.session = session
        self.file_str = StringIO()

    def write(self, val):
        self.file_str.write(val)

    def writeEntity(self, entity, columns, manyToOneDispCell, getMultiIds, manyToOneReferenceMap):
        self.write('\n"')
        self.write(entity.getSheetId())
        self.write('":{')
        recordBuff = list()
        write_object_key_value(recordBuff, '__key__', str(entity.getKey()))
        for cellName in columns:
            value = entity.getValue(cellName)
            if value:
                cell = entity.getCellMetadata(cellName)
                if cell.isReferenceCell():
                    getMultiIds[value] = cell.getReferredSheetMetadata().getSheetId()
                    manyToOneReferenceMap.setdefault(cell.getCellName(), {})[value] = manyToOneDispCell[cellName]
                write_object_key_value(recordBuff, cellName, value)
        self.write(','.join(recordBuff))
        self.write('},')

    def serializeManyToOneReferences(self, getMultiIds, manyToOneReferenceMap):
        manyToOneEntities = self.session.getMulti(getMultiIds)
        for colName, dispMap in manyToOneReferenceMap.iteritems():
            if dispMap:
                self.write('"')
                self.write(colName)
                self.write('":{')
                recordBuff = list()
                for id, dispCellName in dispMap.iteritems():
                    parentRecord = manyToOneEntities.get(id)
                    if parentRecord and parentRecord.getValue(dispCellName) is not None:
                        write_object_key_value(recordBuff, id, parentRecord.getValue(dispCellName))
                self.write(','.join(recordBuff))
                self.write('},')

    def serializeWithKeys(self, metadata, entities, columns):
        manyToOneDispCell = {}
        manyToOneReferenceMap = {}
        for cellName in columns:
            cell = metadata.getPublicCellMetadata(cellName)
            if cell.isReferenceCell():
                manyToOneDispCell[cell.getCellName()] = getDisplayCellName(cell)
        getMultiIds = {}
        self.write('{"entities":{')
        for entity in entities:
            self.writeEntity(entity, columns, manyToOneDispCell, getMultiIds, manyToOneReferenceMap)

        self.write('\n},\n')
        self.write('"references":{\n')
        self.serializeManyToOneReferences(getMultiIds, manyToOneReferenceMap)
        self.write('\n}}')
        return self.getValue()

    def getValue(self):
        return self.file_str.getvalue()

def serializeAggregatedData(aggData):
    return '{"data":%s}'%(write(aggData))
