#Copyright (c) 2006-2007 SunMedia technology (Chengdu) co. Ltd. 
#All right reserved
#Author:jin.hu
#date:2009/09/15

import re
import os
import sys
import time
import string
import codecs

cFileHead = '''/********************************************************************
** File Name: %s
**
** File Description: %s default database
** This file is generated by DBTool %s.
** Do not edit this file manually.
**
** Copyright(c) 2009 Sunplus Technologies - All Rights Reserved
**
********************************************************************/

#if !defined(DEFAULT_DB_IN_BIN)

'''

#parser c struct, has keyword of typedef, group 1 is structure's alias, 2 is body, 3 is name
_DataStruct1 = re.compile(r"""
    (?: typedef\s+)        #typedef key word
    (?: struct)            #struct key word
    (\s+\b[\S]*?\b)?    #struct's name, have it or not
    \s*                    #zero or more blank
    [{]                
    ([^{}]*?)            #data structure body
    [}]
    \s*                    #zero or more blank
    (\w+?\b)            #structure's name
    \s*?                #one or more blank after name
    ;
""", re.VERBOSE | re.DOTALL).search

#parser c struct, group 1 is structure's name, group2 is structure's body
_DataStruct2 = re.compile(r"""
    (?: struct)            #struct key word
    (\s+\b[\S]*?\b)        #struct's name
    \s*                    #zero or more blank
    [{]                
    ([^{}]*?)            #data structure body
    [}]
    \s*?                #one or more blank
    ;
""", re.VERBOSE | re.DOTALL).search

#structure's member type, group 1 is keyword ,group 2 is member's type, group 3 is pointer sign, group 4 is group's name
_STVariable = re.compile(r"""
    (struct\s+?)?    #keyword, may be have
    \s*?
    (\w+)            #member's type
    \s*?
    (\w+)?           #member's type2
    ([*])?            #member may be pointer type
    \s*?
    (\S+);           #member's name
    \s*//\s*Byte:(\d*)\s*; #member's byte
    \s*Display:\s*(\w*)\s*; #member's display
    \s*Alias:\s*(.*)\s*; #member's alias
    \s*Fixed:\s*(\w*)\s*; #member's fixed
    \s*Struct:\s*(\w*)\s*; #member's struct
    \s*Bit:<\s*(.*)\s*>; #member's Bit
    \s*ValueDisplay:<\s*(.*)\s*>; #member's Display
""", re.VERBOSE).search

    #\s*ValueType:\s*(\d*)\s*; #member's value type
_STDisplayValue = re.compile(r"""
    \s*ValueType:\s*(\d*)\s*; #member's value type
    \s*ExtremumValue:\s*(.*)\s*; #member's Max and min Value
    \s*Custom:\((\s*(.*)\s*)\) #member's User Define Value
""", re.VERBOSE).search

_VariableByte = re.compile(r'\\\\\s*?d\s*?Byte')


class ParserStruct:
    def __init__(self, filePath):
        self.fp = open(filePath, 'r')
        #self.fp1 = open('E:\\DBTool111\\SystemTest\\fff.h','w')
        self.structData = None
        self.fileData = ''
        self.structValue = ''
        self.structMember = None


    def closeCFile(self):
        self.fp.close()

    def getFileData(self):
        self.fileData = self.fp.read()
        self.closeCFile()
    
    def getStructData(self):
        structData1 = _DataStruct1(self.fileData)
        structData2 = _DataStruct2(self.fileData)
        if structData1:
            self.structData = structData1
            self.fileData = self.fileData.replace(structData1.group(0), '', 1)
            self.structValue = structData1.group(2)
            return structData1
        elif structData2:
            self.structData = structData2
            self.fileData = self.fileData.replace(structData2.group(0), '', 1)
            self.structValue = structData2.group(0)
            return structData2
        else:
            return None 
    def getStructName(self):
        return self.formatString(self.structData.group(3))
    def getStructTypeDef(self):  
        return self.formatString(self.structData.group(1))
    
    def getStructValue(self):
        structMember = _STVariable(self.structValue)
        if structMember:
            self.structMember = structMember
            self.structValue = self.structValue.replace(structMember.group(0), '', 1)
            return structMember
        else:
            return None
    def getMemberType(self):
        memberType = ''
        if self.structMember.group(2) != None:
            memberType += self.structMember.group(2)
        if self.structMember.group(3) != None:
            memberType += ' ' + self.structMember.group(3)
        return memberType
    def getMemberName(self):
        return self.formatString(self.structMember.group(5))
    def getMemberByte(self):
        return int(self.structMember.group(6))
    def getMemberDisplay(self):
        if self.structMember.group(7) == 'TRUE':
            return 1
        else:
            return 0
    def getMemberAlias(self):
        return self.structMember.group(8)
    def getMemberFixed(self):
        if self.structMember.group(9) == 'TRUE':
            return 1
        else:
            return 0
    def getMemberStruct(self):
        if self.structMember.group(10) == 'TRUE':
            return 1
        else:
            return 0
    def getChildName(self, memberName):
        if memberName.find('[') != -1:
            memberName = memberName[:memberName.find('[')]
        if childNameDict.has_key(self.formatString(self.structData.group(3))):
            childDict = childNameDict[self.formatString(self.structData.group(3))]
            if childDict.has_key(memberName):
                return childDict[memberName]
            else:
                return None
        else:
            return None    
    
    def getMemberBit(self):
        bitDataList = []
        if self.structMember.group(11) != '':
            bitData = self.structMember.group(11).replace('[', '').replace(']','').split(',')
            for singleBit in bitData:
                singlebitDataDict = []
                for perporty in singleBit.split(';'):
                    perporty = perporty[perporty.find(':')+1:]
                    singlebitDataDict.append(perporty)
                bitDataList.append(singlebitDataDict)
        return bitDataList

    def getUserDefineDisplay(self):
        displayValue = []
        if self.structMember.group(12) != '':
            displayData = self.structMember.group(12).replace('[', '').replace(']','').split(',')
            for singleDisplay in displayData:
                singleDisplayDict = {}
                displayObj = _STDisplayValue(singleDisplay)
                if displayObj:
                    singleDisplayDict['ValueType'] = int(displayObj.group(1)) 
                    singleDisplayDict['MinValue'] = self.getMinValue(displayObj.group(2))
                    singleDisplayDict['MaxValue'] = self.getMaxValue(displayObj.group(2))
                    singleDisplayDict['UserDefine'] = self.getUserDefineValue(displayObj.group(3))
                displayValue.append(singleDisplayDict)
        return displayValue
    
    def getMinValue(self, extremumValue):
        return int(extremumValue[:extremumValue.find('-')])
    def getMaxValue(self, extremumValue):
        return int(extremumValue[extremumValue.find('-')+1:])
    def getUserDefineValue(self, customValue):
        customValueList = []
        if customValue == '' or customValue.find(';') == -1:
            return customValueList
        for singleCustom in customValue.split(';'):
            indexSplit = singleCustom.find('-')
            customValueDict = {}
            customValueDict['DisplayString'] = singleCustom[:indexSplit]
            customValueDict['BindValue'] = int(singleCustom[indexSplit+1:])
            customValueList.append(customValueDict)
        return customValueList
    
    def formatString(self, fotmatString):
        return fotmatString.replace(' ','').replace('   ','').replace('\n','')

class ExportHFile:
    def __init__(self, hFilePath):
        self.hFilePath = hFilePath
        self.fp = 0
        self.is1002Flag = 0
        self.struct1002Item = []
    
    def createFile(self):
        self.fp = open(self.hFilePath, 'w')
        #self.fp1 = open('E:\\DBTool111\\SystemTest\\fff.h', 'w')
    
    def writeStruct(self, strcutData):
        self.fp.write(self.formatStruct(strcutData))

    def formatStruct(self, structDataDict):
        structDataDict['StructTypedef'] = structDataDict['StructTypedef'].replace(' ','')
        structDataDict['StructTypedef'] = structDataDict['StructTypedef'].replace('\n','')
        structDataDict['StructTypedef'] = structDataDict['StructTypedef'].replace('\t','')
        structDataDict['StructName'] = structDataDict['StructName'].replace(' ','')
        structDataDict['StructName'] = structDataDict['StructName'].replace('\n','')
        structDataDict['StructName'] = structDataDict['StructName'].replace('\t','')
        if len(structDataDict.keys()) == 0:
            return ''
        structData = ''
        structData += 'typedef struct ' + structDataDict['StructTypedef']
        structData += '\n{\n'
        for item in structDataDict['StructItem']:
            structData += '\t'
            structData += item['ElementType'] + ' '
            structData += item['ElementName'] + ';'
            structData += '// ' + 'Byte:'+str(item['ElementByte']) + ';'
            if item['ElementDisplay'] == 1:
                structData += 'Display:TRUE;'
            else:
                structData += 'Display:FALSE;'
            structData += 'Alias:'+(item['ElementAlias'])+';'
            if item['ElementFixed'] == 1:
                structData += 'Fixed:TRUE;'
            else:
                structData += 'Fixed:FALSE;'
            if item['ElementStruct'] == 1:
                structData += 'Struct:TRUE;'
            else:
                structData += 'Struct:FALSE;'
            structData += self.formatBit(item['Bit'])
            structData += self.formatDislpayValue(item['ValueDisplay'])
        structData += '}' + structDataDict['StructName'] + ';\n'
        return structData

    def formatBit(self, bitData):
        bit = 'Bit:<'
        for singleBit in bitData:
            bit += '['
            bit += 'Name:' + singleBit['Name'] + ';'
            bit += 'BitNumber:' + str(singleBit['BitNumber']) + ';'
            if singleBit['Display'] == 1:
                bit += 'Display:TRUE;'
            else:
                bit += 'Display:FALSE;'
            if singleBit['Fixed'] == 1:
                bit += 'Fixed:TRUE'
            else:
                bit += 'Fixed:FALSE'
            bit += '],'
        if bit != 'Bit:<':
            bit = bit[:-1]
        bit += '>;'
        return bit

    def formatDislpayValue(self, displayValue):
        formatDisplay = 'ValueDisplay:<'
        for singleDisplay in displayValue:
            formatDisplay += '['
            formatDisplay += 'ValueType:' + str(singleDisplay['ValueType'])
            formatDisplay += ';ExtremumValue:' + str(singleDisplay['MinValue']) + '-'+ str(singleDisplay['MaxValue'])
            formatDisplay += ';Custom:('
            for singleCustom in singleDisplay['Custom']:
                formatDisplay += singleCustom['DisplayString'] + '-' + str(singleCustom['BindValue']) + ';'
            if len(singleDisplay['Custom']) != 0:
                formatDisplay = formatDisplay[:-1]
            formatDisplay += ')],'
        if formatDisplay != 'ValueDisplay:<':
            formatDisplay = formatDisplay[:-1]
        formatDisplay += '>;\n'
        return formatDisplay


class ExportCFile:
    def __init__(self, cFilePath):
        self.cFilePath = cFilePath
        self.fp = 0

        self.byteWidth = {}
        self.elementName = []
        self.elementType = {}
        self.elementStruct = {}

        self.bitName = {}
        self.bitNumber = {}
        self.DataDict = {}

        self.netPos = 0
        self.tpPos = 0
        self.servicePos = 0

        #self.fp1 = open('E:\\DBTool111\\s1\\new.h','w')

    def setByteWidth(self, byteWidth):
        self.byteWidth = byteWidth
    def setElementName(self, elementName):
        self.elementName = elementName
        self.fp.write('\n\t//')
        for element in self.elementName:
            self.fp.write(element + ' ')
        self.fp.write('\n')
    def setType(self, elementType):
        self.elementType = elementType
    def setBitName(self, bitName):
        self.bitName = bitName
    def setBitWidth(self, bitWidth):
        self.bitNumber = bitWidth
    def setStruct(self, elementStruct):
        self.elementStruct = elementStruct
    def resetData(self):
        self.byteWidth = {}
        self.elementName = []
        self.elementType = {}
        self.bitName = {}
        self.bitNumber = {}
        self.elementStruct = {}
        
    
    def setDictItem(self, key , value):
        self.DataDict[key] = value
    def resetValue(self):
        self.sdxDataDict = {}
    def createFile(self):
        self.fp = open(self.cFilePath, 'w')
    
    def writeFileHead(self, fileName, platForm, version):
        self.fp.write(cFileHead%(fileName, platForm, version))
    def writeEnd(self):
        self.fp.write('};\n')
    def writeNetName(self):
        self.netPos = self.fp.tell()
        self.fp.write('const DVB_NETWORK g_astDefNetInfo[MAX_NUM_DEF_NETWORK] = {\n')
    def writeTPName(self):
        self.tpPos = self.fp.tell()
        self.fp.write('const DVB_MULTIPLEX g_astDefTpInfo[MAX_NUM_DEF_TP] = {\n')
    def writeServiceName(self):
        self.servicePos = self.fp.tell()
        self.fp.write('const DVB_SERVICE g_astDefProgInfo[MAX_NUM_DEF_TV] = {\n')
    def writeData(self):
        self.fp.write('\t{')
        for element in self.elementName:
            if self.elementType[element].find('char') != -1 and self.byteWidth[element] != 1:
                stringValue = self.formatString(self.DataDict[element], self.byteWidth[element])
                if self.elementName[-1] == element:
                    self.fp.write('\"' + stringValue + '\"')
                else:
                    self.fp.write('\"' + stringValue + '\", ')
            else:
                if self.bitName.has_key(element):
                    self.writeBitValue(element)
                else:
                    dataValue = self.formatData(self.DataDict[element])
                    if element == 'stVideoPid' or element == 'stAudioPid[2]':
                        self.writeStruct(element, dataValue)
                    else:
                        if self.elementName[-1] == element:
                            self.fp.write(str(dataValue))
                        else:
                            self.fp.write(str(dataValue) + ', ')
        self.fp.write('},\n')
    def writeStruct(self, memberName, dataValue):
        if memberName == 'uiLNBFreq':
            itemValue = str('0x%02x'%(dataValue))
            if self.elementName[-1] == memberName:
                self.fp.write(str(itemValue))
            else:
                self.fp.write(str(itemValue) + ', ')
        elif memberName == 'stVideoPid':
            structValue = ''
            itemCount = self.byteWidth[memberName]/2
            for i in range(itemCount):
                #rightMoveNumber = 16*(itemCount-1-i)
                rightMoveNumber = 16*(i)
                structValue += str(dataValue>>rightMoveNumber&(pow(2, 16)-1)) + ','
            structValue = structValue[:-1]
            if self.elementName[-1] == memberName:
                self.fp.write('{' + str(structValue) + '}')
            else:
                self.fp.write('{' + str(structValue) + '}, ')
        elif memberName == 'stAudioPid[2]':
            audio2 = 0
            audio1 = 0
            bitWidth = 0
            bit1Width = 0
            bit2Width = 0
            for j in range(self.byteWidth[memberName]):
                baseValue = dataValue>>bitWidth&0xff
                if j < self.byteWidth[memberName]/2:
                    audio1 |= baseValue<<bit1Width
                    bit1Width += 8
                else:
                    audio2 |= baseValue<<bit2Width
                    bit2Width += 8
                bitWidth += 8
            self.fp.write('{')
            structValue = ''
            itemCount = self.byteWidth[memberName]/2/2
            for i in range(itemCount):
                #rightMoveNumber = 16*(itemCount-1-i)
                rightMoveNumber = 16*(i)
                structValue += str(audio1>>rightMoveNumber&(pow(2, 16)-1)) + ','
            structValue = structValue[:-1]
            self.fp.write('{'+str(structValue)+'}, ')
            structValue = ''
            itemCount = self.byteWidth[memberName]/2/2
            for i in range(itemCount):
                #rightMoveNumber = 16*(itemCount-1-i)
                rightMoveNumber = 16*(i)
                structValue += str(audio2>>rightMoveNumber&(pow(2, 16)-1)) + ','
            structValue = structValue[:-1]
            if self.elementName[-1] == memberName:
                self.fp.write('{'+str(structValue)+'}}')
            else:
                self.fp.write('{'+str(structValue)+'}}, ')

    def colseFile(self, netCount, tpCount, serviceCount):
        self.fp.write('\n#endif')
        '''
        self.fp.seek(self.netPos)
        self.fp.write('const DVB_NETWORK g_astDefNetInfo[MAX_NUM_DEF_NETWORK] = {\n')
        self.fp.seek(self.tpPos)
        self.fp.write('const DVB_MULTIPLEX g_astDefTpInfo[MAX_NUM_DEF_TP] = {\n')
        self.fp.seek(self.servicePos)
        self.fp.write('const DVB_SERVICE g_astDefProgInfo[MAX_NUM_DEF_TV ] = {\n')
        '''
        self.fp.close()
    def writeBitValue(self, memberName):
        bitName = self.bitName[memberName]
        bitNumber = self.bitNumber[memberName]
        dataValue = 0
        bitIndex = 0
        for singleBitName in bitName:
            moveNumber = 0
            for i in range(bitIndex):
                moveNumber += bitNumber[i]
            dataValue |= self.formatData(self.DataDict[singleBitName])<<moveNumber
            bitIndex += 1
        if memberName == 'stVideoPid' or memberName == 'stAudioPid[2]' or memberName == 'uiLNBFreq':
            self.writeStruct(memberName, dataValue)
        else:
            if self.elementName[-1] == memberName:
                self.fp.write(str(dataValue))
            else:
                self.fp.write(str(dataValue) + ',')
      
    def formatString(self, formatValue, formatBitWidth):
        formatValue = formatValue.replace('\n', '')
        charFlag = 0
        for i in range(len(formatValue)):
            if formatValue[i] != ' ':
                charFlag = i
        formatValue = formatValue[:charFlag+1]
        if len(formatValue) == formatBitWidth:
            formatValue = formatValue
        elif len(formatValue) > formatBitWidth:
            formatValue = formatValue[0:formatBitWidth]
        return formatValue

    def formatData(self, dataValue):
        if dataValue == 'NULL':
            return 0x00
        if dataValue == 'Unknown':
            return 0xff
        if dataValue == '':
            return 1
        try:
            base = 10
            if dataValue.find('0x') != -1:
                base = 16
            return int(dataValue, base)
        except Exception:
            return 1
def test1 ():
    c = ParserStruct('D:\\DB Tool\\DB Tool\\Bin\\config.h')
    c.getFileData()
    structData = c.getStructData()
    while structData:
        memberValue = c.getStructValue()
        while memberValue != None:
            print c.getUserDefineDisplay()
            #print c.getMemberDisplay()
            memberValue = c.getStructValue()
        structData = c.getStructData()

if __name__ == '__main__':
    test1()