#!/usr/bin/python3
import collections
from bitarray import bitarray
from datetime import datetime, timedelta


__DEBUG__ = "N"


class FruException(Exception):
    def __init__(self, message='fruerror', code=-100):
        err = 'errcode: {0} message:{1}'.format(code, message)
        Exception.__init__(self, err)
        self.code = code
        self.message = message


def e_print(err):
    print("ERROR: " + err)


def d_print(debug_info):
    if(__DEBUG__ == "Y"):
        print(debug_info)


class FruUtil():
    @staticmethod
    def decodeLength(value):
        a = bitarray(8)
        a.setall(True)
        a[0:1] = 0
        a[1:2] = 0
        x = ord(a.tobytes())
        return x & ord(value)

    @staticmethod
    def minToData():
        starttime = datetime(1996, 1, 1, 0, 0, 0)
        endtime = datetime.now()
        seconds = (endtime - starttime).total_seconds()
        mins = seconds // 60
        m = int(round(mins))
        return m

    @staticmethod
    def getTimeFormat():
        return datetime.now().strftime('%Y-%m-%d')

    @staticmethod
    def getTypeLength(value):
        if value is None or len(value) == 0:
            return 0
        a = bitarray(8)
        a.setall(False)
        a[0:1] = 1
        a[1:2] = 1
        x = ord(a.tobytes())
        return x | len(value)

    @staticmethod
    def checksum(b):
        result = 0
        for i in range(len(b)):
            result += ord(b[i])
        return (0x100 - (result & 0xff)) & 0xff


class BaseArea(object):
    SUGGESTED_SIZE_COMMON_HEADER = 8
    SUGGESTED_SIZE_INTERNAL_USE_AREA = 72
    SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32
    SUGGESTED_SIZE_BOARD_INFO_AREA = 80
    SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80

    INITVALUE = b'\x00'
    resultvalue = INITVALUE * 256
    COMMON_HEAD_VERSION = b'\x01'
    __childList = None

    def __init__(self, name="", size=0, offset=0):
        self.__childList = []
        self._offset = offset
        self.name = name
        self._size = size
        self._isPresent = False
        self._data = b'\x00' * size
        self.__dataoffset = 0

    @property
    def childList(self):
        return self.__childList

    @childList.setter
    def childList(self, value):
        self.__childList = value

    @property
    def offset(self):
        return self._offset

    @offset.setter
    def offset(self, value):
        self._offset = value

    @property
    def size(self):
        return self._size

    @size.setter
    def size(self, value):
        self._size = value

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, value):
        self._data = value

    @property
    def isPresent(self):
        return self._isPresent

    @isPresent.setter
    def isPresent(self, value):
        self._isPresent = value


class InternalUseArea(BaseArea):
    pass


class ChassisInfoArea(BaseArea):
    pass


class BoardInfoArea(BaseArea):
    _boardTime = None
    _fields = None
    _mfg_date = None

    def __str__(self):
        formatstr = "version             : %x\n" \
                    "length              : %d \n" \
                    "language            : %x \n" \
                    "mfg_date            : %s \n" \
                    "boardManufacturer   : %s \n" \
                    "boardProductName    : %s \n" \
                    "boardSerialNumber   : %s \n" \
                    "boardPartNumber     : %s \n" \
                    "fruFileId           : %s \n"

        tmpstr = formatstr % (ord(self.boardversion), self.size,
                              self.language, self.getMfgRealData(),
                              self.boardManufacturer, self.boardProductName,
                              self.boardSerialNumber, self.boardPartNumber,
                              self.fruFileId)
        for i in range(1, 11):
            valtmp = "boardextra%d" % i
            if hasattr(self, valtmp):
                valtmpval = getattr(self, valtmp)
                tmpstr += "boardextra%d         : %s \n" % (i, valtmpval)
            else:
                break

        return tmpstr

    def todict(self):
        dic = collections.OrderedDict()
        dic["boardversion"] = ord(self.boardversion)
        dic["boardlength"] = self.size
        dic["boardlanguage"] = self.language
        dic["boardmfg_date"] = self.getMfgRealData()
        dic["boardManufacturer"] = self.boardManufacturer
        dic["boardProductName"] = self.boardProductName
        dic["boardSerialNumber"] = self.boardSerialNumber
        dic["boardPartNumber"] = self.boardPartNumber
        dic["boardfruFileId"] = self.fruFileId
        for i in range(1, 11):
            valtmp = "boardextra%d" % i
            if hasattr(self, valtmp):
                valtmpval = getattr(self, valtmp)
                dic[valtmp] = valtmpval
            else:
                break
        return dic

    def decodedata(self):
        index = 0
        self.areaversion = self.data[index]
        index += 1
        d_print("decode length :%d class size:%d" %
                ((ord(self.data[index]) * 8), self.size))
        index += 2

        timetmp = self.data[index: index + 3]
        self.mfg_date = ord(timetmp[0]) | (
            ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16)
        d_print("decode getMfgRealData :%s" % self.getMfgRealData())
        index += 3

        templen = FruUtil.decodeLength(self.data[index])
        self.boardManufacturer = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode boardManufacturer:%s" % self.boardManufacturer)

        templen = FruUtil.decodeLength(self.data[index])
        self.boardProductName = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode boardProductName:%s" % self.boardProductName)

        templen = FruUtil.decodeLength(self.data[index])
        self.boardSerialNumber = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode boardSerialNumber:%s" % self.boardSerialNumber)

        templen = FruUtil.decodeLength(self.data[index])
        self.boardPartNumber = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode boardPartNumber:%s" % self.boardPartNumber)

        templen = FruUtil.decodeLength(self.data[index])
        self.fruFileId = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode fruFileId:%s" % self.fruFileId)

        for i in range(1, 11):
            valtmp = "boardextra%d" % i
            if self.data[index] != chr(0xc1):
                templen = FruUtil.decodeLength(self.data[index])
                tmpval = self.data[index + 1: index + templen + 1]
                setattr(self, valtmp, tmpval)
                index += templen + 1
                d_print("decode boardextra%d:%s" % (i, tmpval))
            else:
                break
        return

    def recalcute(self):
        d_print("boardInfoArea version:%x" % ord(self.boardversion))
        d_print("boardInfoArea length:%d" % self.size)
        d_print("boardInfoArea language:%x" % self.language)
        self.mfg_date = FruUtil.minToData()
        d_print("boardInfoArea mfg_date:%x" % self.mfg_date)

        self.data = chr(ord(self.boardversion)) + \
            chr(self.size // 8) + chr(self.language)

        self.data += chr(self.mfg_date & 0xFF)
        self.data += chr((self.mfg_date >> 8) & 0xFF)
        self.data += chr((self.mfg_date >> 16) & 0xFF)

        d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer)
        typelength = FruUtil.getTypeLength(self.boardManufacturer)
        self.data += chr(typelength)
        self.data += self.boardManufacturer

        d_print("boardInfoArea boardProductName:%s" % self.boardProductName)
        self.data += chr(FruUtil.getTypeLength(self.boardProductName))
        self.data += self.boardProductName

        d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber)
        self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber))
        self.data += self.boardSerialNumber

        d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber)
        self.data += chr(FruUtil.getTypeLength(self.boardPartNumber))
        self.data += self.boardPartNumber

        d_print("boardInfoArea fruFileId:%s" % self.fruFileId)
        self.data += chr(FruUtil.getTypeLength(self.fruFileId))
        self.data += self.fruFileId

        for i in range(1, 11):
            valtmp = "boardextra%d" % i
            if hasattr(self, valtmp):
                valtmpval = getattr(self, valtmp)
                d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval))
                self.data += chr(FruUtil.getTypeLength(valtmpval))
                if valtmpval is None:
                    pass
                else:
                    self.data += valtmpval
            else:
                break

        self.data += chr(0xc1)

        if len(self.data) > (self.size - 1):
            incr = (len(self.data) - self.size) // 8 + 1
            self.size += incr * 8

        self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:]
        d_print("self data:%d" % len(self.data))
        d_print("self size:%d" % self.size)
        d_print("adjust size:%d" % (self.size - len(self.data) - 1))
        self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0]))

        # checksum
        checksum = FruUtil.checksum(self.data)
        d_print("board info checksum:%x" % checksum)
        self.data += chr(checksum)

    def getMfgRealData(self):
        starttime = datetime(1996, 1, 1, 0, 0, 0)
        mactime = starttime + timedelta(minutes=self.mfg_date)
        return mactime

    @property
    def language(self):
        self._language = 25
        return self._language

    @property
    def mfg_date(self):
        return self._mfg_date

    @mfg_date.setter
    def mfg_date(self, val):
        self._mfg_date = val

    @property
    def boardversion(self):
        self._boardversion = self.COMMON_HEAD_VERSION
        return self._boardversion

    @property
    def fruFileId(self):
        return self._FRUFileID

    @fruFileId.setter
    def fruFileId(self, val):
        self._FRUFileID = val

    @property
    def boardPartNumber(self):
        return self._boardPartNumber

    @boardPartNumber.setter
    def boardPartNumber(self, val):
        self._boardPartNumber = val

    @property
    def boardSerialNumber(self):
        return self._boardSerialNumber

    @boardSerialNumber.setter
    def boardSerialNumber(self, val):
        self._boardSerialNumber = val

    @property
    def boardProductName(self):
        return self._boradProductName

    @boardProductName.setter
    def boardProductName(self, val):
        self._boradProductName = val

    @property
    def boardManufacturer(self):
        return self._boardManufacturer

    @boardManufacturer.setter
    def boardManufacturer(self, val):
        self._boardManufacturer = val

    @property
    def boardTime(self):
        return self._boardTime

    @boardTime.setter
    def boardTime(self, val):
        self._boardTime = val

    @property
    def fields(self):
        return self._fields

    @fields.setter
    def fields(self, val):
        self._fields = val


class ProductInfoArea(BaseArea):
    _productManufacturer = None
    _productAssetTag = None
    _FRUFileID = None

    def __str__(self):
        formatstr = "version             : %x\n" \
                    "length              : %d \n" \
                    "language            : %x \n" \
                    "productManufacturer : %s \n" \
                    "productName         : %s \n" \
                    "productPartModelName: %s \n" \
                    "productVersion      : %s \n" \
                    "productSerialNumber : %s \n" \
                    "productAssetTag     : %s \n" \
                    "fruFileId           : %s \n"

        tmpstr = formatstr % (ord(self.areaversion), self.size,
                              self.language, self.productManufacturer,
                              self.productName, self.productPartModelName,
                              self.productVersion, self.productSerialNumber,
                              self.productAssetTag, self.fruFileId)

        for i in range(1, 11):
            valtmp = "productextra%d" % i
            if hasattr(self, valtmp):
                valtmpval = getattr(self, valtmp)
                tmpstr += "productextra%d       : %s \n" % (i, valtmpval)
            else:
                break

        return tmpstr

    def todict(self):
        dic = collections.OrderedDict()
        dic["productversion"] = ord(self.areaversion)
        dic["productlength"] = self.size
        dic["productlanguage"] = self.language
        dic["productManufacturer"] = self.productManufacturer
        dic["productName"] = self.productName
        dic["productPartModelName"] = self.productPartModelName
        dic["productVersion"] = int(self.productVersion, 16)
        dic["productSerialNumber"] = self.productSerialNumber
        dic["productAssetTag"] = self.productAssetTag
        dic["productfruFileId"] = self.fruFileId
        for i in range(1, 11):
            valtmp = "productextra%d" % i
            if hasattr(self, valtmp):
                valtmpval = getattr(self, valtmp)
                dic[valtmp] = valtmpval
            else:
                break
        return dic

    def decodedata(self):
        index = 0
        self.areaversion = self.data[index]  # 0
        index += 1
        d_print("decode length %d" % (ord(self.data[index]) * 8))
        d_print("class size %d" % self.size)
        index += 2

        templen = FruUtil.decodeLength(self.data[index])
        self.productManufacturer = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode productManufacturer:%s" % self.productManufacturer)

        templen = FruUtil.decodeLength(self.data[index])
        self.productName = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode productName:%s" % self.productName)

        templen = FruUtil.decodeLength(self.data[index])
        self.productPartModelName = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode productPartModelName:%s" % self.productPartModelName)

        templen = FruUtil.decodeLength(self.data[index])
        self.productVersion = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode productVersion:%s" % self.productVersion)

        templen = FruUtil.decodeLength(self.data[index])
        self.productSerialNumber = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode productSerialNumber:%s" % self.productSerialNumber)

        templen = FruUtil.decodeLength(self.data[index])
        self.productAssetTag = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode productAssetTag:%s" % self.productAssetTag)

        templen = FruUtil.decodeLength(self.data[index])
        self.fruFileId = self.data[index + 1: index + templen + 1]
        index += templen + 1
        d_print("decode fruFileId:%s" % self.fruFileId)

        for i in range(1, 11):
            valtmp = "productextra%d" % i
            if self.data[index] != chr(0xc1) and index < self.size - 1:
                templen = FruUtil.decodeLength(self.data[index])
                if templen == 0:
                    break
                tmpval = self.data[index + 1: index + templen + 1]
                d_print("decode boardextra%d:%s" % (i, tmpval))
                setattr(self, valtmp, tmpval)
                index += templen + 1
            else:
                break

    @property
    def productVersion(self):
        return self._productVersion

    @productVersion.setter
    def productVersion(self, name):
        self._productVersion = name

    @property
    def areaversion(self):
        self._areaversion = self.COMMON_HEAD_VERSION
        return self._areaversion

    @areaversion.setter
    def areaversion(self, name):
        self._areaversion = name

    @property
    def language(self):
        self._language = 25
        return self._language

    @property
    def productManufacturer(self):
        return self._productManufacturer

    @productManufacturer.setter
    def productManufacturer(self, name):
        self._productManufacturer = name

    @property
    def productName(self):
        return self._productName

    @productName.setter
    def productName(self, name):
        self._productName = name

    @property
    def productPartModelName(self):
        return self._productPartModelName

    @productPartModelName.setter
    def productPartModelName(self, name):
        self._productPartModelName = name

    @property
    def productSerialNumber(self):
        return self._productSerialNumber

    @productSerialNumber.setter
    def productSerialNumber(self, name):
        self._productSerialNumber = name

    @property
    def productAssetTag(self):
        return self._productAssetTag

    @productAssetTag.setter
    def productAssetTag(self, name):
        self._productAssetTag = name

    @property
    def fruFileId(self):
        return self._FRUFileID

    @fruFileId.setter
    def fruFileId(self, name):
        self._FRUFileID = name

    def recalcute(self):
        d_print("product version:%x" % ord(self.areaversion))
        d_print("product length:%d" % self.size)
        d_print("product language:%x" % self.language)
        self.data = chr(ord(self.areaversion)) + \
            chr(self.size // 8) + chr(self.language)

        typelength = FruUtil.getTypeLength(self.productManufacturer)
        self.data += chr(typelength)
        self.data += self.productManufacturer

        self.data += chr(FruUtil.getTypeLength(self.productName))
        self.data += self.productName

        self.data += chr(FruUtil.getTypeLength(self.productPartModelName))
        self.data += self.productPartModelName

        self.data += chr(FruUtil.getTypeLength(self.productVersion))
        self.data += self.productVersion

        self.data += chr(FruUtil.getTypeLength(self.productSerialNumber))
        self.data += self.productSerialNumber

        self.data += chr(FruUtil.getTypeLength(self.productAssetTag))
        if self.productAssetTag is not None:
            self.data += self.productAssetTag

        self.data += chr(FruUtil.getTypeLength(self.fruFileId))
        self.data += self.fruFileId

        for i in range(1, 11):
            valtmp = "productextra%d" % i
            if hasattr(self, valtmp):
                valtmpval = getattr(self, valtmp)
                d_print("boardInfoArea productextra%d:%s" % (i, valtmpval))
                self.data += chr(FruUtil.getTypeLength(valtmpval))
                if valtmpval is None:
                    pass
                else:
                    self.data += valtmpval
            else:
                break

        self.data += chr(0xc1)
        if len(self.data) > (self.size - 1):
            incr = (len(self.data) - self.size) // 8 + 1
            self.size += incr * 8
        d_print("self.data:%d" % len(self.data))
        d_print("self.size:%d" % self.size)

        self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:]
        self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0]))
        checksum = FruUtil.checksum(self.data)
        d_print("board info checksum:%x" % checksum)
        self.data += chr(checksum)


class MultiRecordArea(BaseArea):
    pass


class Field(object):

    def __init__(self, fieldType="ASCII", fieldData=""):
        self.fieldData = fieldData
        self.fieldType = fieldType

    @property
    def data(self):
        return self._data

    @property
    def fieldType(self):
        return self._fieldType

    @property
    def fieldData(self):
        return self._fieldData


class ipmifru(BaseArea):
    _BoardInfoArea = None
    _ProductInfoArea = None
    _InternalUseArea = None
    _ChassisInfoArea = None
    _multiRecordArea = None
    _productinfoAreaOffset = BaseArea.INITVALUE
    _boardInfoAreaOffset = BaseArea.INITVALUE
    _internalUserAreaOffset = BaseArea.INITVALUE
    _chassicInfoAreaOffset = BaseArea.INITVALUE
    _multiRecordAreaOffset = BaseArea.INITVALUE
    _bindata = None
    _bodybin = None
    _version = BaseArea.COMMON_HEAD_VERSION
    _zeroCheckSum = None
    _frusize = 256

    def __str__(self):
        tmpstr = ""
        if self.boardInfoArea.isPresent:
            tmpstr += "\nboardinfoarea: \n"
            tmpstr += self.boardInfoArea.__str__()
        if self.productInfoArea.isPresent:
            tmpstr += "\nproductinfoarea: \n"
            tmpstr += self.productInfoArea.__str__()
        return tmpstr

    def decodeBin(self, eeprom):
        commonHead = eeprom[0:8]
        d_print("decode version %x" % ord(commonHead[0]))
        if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]):
            raise FruException("HEAD VERSION error,not Fru format!", -10)
        if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]):
            strtemp = "check header checksum error [cal:%02x data:%02x]" % (
                FruUtil.checksum(commonHead[0:7]), ord(commonHead[7]))
            raise FruException(strtemp, -3)
        if ord(commonHead[1]) != ord(self.INITVALUE):
            d_print("Internal Use Area is present")
            self.internalUseArea = InternalUseArea(
                name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA)
            self.internalUseArea.isPresent = True
            self.internalUserAreaOffset = ord(commonHead[1])
            self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: (
                self.internalUserAreaOffset * 8 + self.internalUseArea.size)]
        if ord(commonHead[2]) != ord(self.INITVALUE):
            d_print("Chassis Info Area is present")
            self.chassisInfoArea = ChassisInfoArea(
                name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA)
            self.chassisInfoArea.isPresent = True
            self.chassicInfoAreaOffset = ord(commonHead[2])
            self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: (
                self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)]
        if ord(commonHead[3]) != ord(self.INITVALUE):
            self.boardInfoArea = BoardInfoArea(
                name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA)
            self.boardInfoArea.isPresent = True
            self.boardInfoAreaOffset = ord(commonHead[3])
            self.boardInfoArea.size = ord(
                eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8
            d_print("Board Info Area is present size:%d" %
                    (self.boardInfoArea.size))
            self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: (
                self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)]
            if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]):
                strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" %  \
                    (FruUtil.checksum(
                        self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:]))
                raise FruException(strtmp, -3)
            self.boardInfoArea.decodedata()
        if ord(commonHead[4]) != ord(self.INITVALUE):
            d_print("Product Info Area is present")
            self.productInfoArea = ProductInfoArea(
                name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA)
            self.productInfoArea.isPresent = True
            self.productinfoAreaOffset = ord(commonHead[4])
            d_print("length offset value: %02x" %
                    ord(eeprom[self.productinfoAreaOffset * 8 + 1]))
            self.productInfoArea.size = ord(
                eeprom[self.productinfoAreaOffset * 8 + 1]) * 8
            d_print("Product Info Area is present size:%d" %
                    (self.productInfoArea.size))

            self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: (
                self.productinfoAreaOffset * 8 + self.productInfoArea.size)]
            if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]):
                strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % (
                    FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:]))
                raise FruException(strtmp, -3)
            self.productInfoArea.decodedata()
        if ord(commonHead[5]) != ord(self.INITVALUE):
            self.multiRecordArea = MultiRecordArea(
                name="MultiRecord record Area ")
            d_print("MultiRecord record present")
            self.multiRecordArea.isPresent = True
            self.multiRecordAreaOffset = ord(commonHead[5])
            self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: (
                self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)]

    def initDefault(self):
        self.version = self.COMMON_HEAD_VERSION
        self.internalUserAreaOffset = self.INITVALUE
        self.chassicInfoAreaOffset = self.INITVALUE
        self.boardInfoAreaOffset = self.INITVALUE
        self.productinfoAreaOffset = self.INITVALUE
        self.multiRecordAreaOffset = self.INITVALUE
        self.PAD = self.INITVALUE
        self.zeroCheckSum = self.INITVALUE
        self.offset = self.SUGGESTED_SIZE_COMMON_HEADER
        self.productInfoArea = None
        self.internalUseArea = None
        self.boardInfoArea = None
        self.chassisInfoArea = None
        self.multiRecordArea = None
        # self.recalcute()

    @property
    def version(self):
        return self._version

    @version.setter
    def version(self, name):
        self._version = name

    @property
    def internalUserAreaOffset(self):
        return self._internalUserAreaOffset

    @internalUserAreaOffset.setter
    def internalUserAreaOffset(self, obj):
        self._internalUserAreaOffset = obj

    @property
    def chassicInfoAreaOffset(self):
        return self._chassicInfoAreaOffset

    @chassicInfoAreaOffset.setter
    def chassicInfoAreaOffset(self, obj):
        self._chassicInfoAreaOffset = obj

    @property
    def productinfoAreaOffset(self):
        return self._productinfoAreaOffset

    @productinfoAreaOffset.setter
    def productinfoAreaOffset(self, obj):
        self._productinfoAreaOffset = obj

    @property
    def boardInfoAreaOffset(self):
        return self._boardInfoAreaOffset

    @boardInfoAreaOffset.setter
    def boardInfoAreaOffset(self, obj):
        self._boardInfoAreaOffset = obj

    @property
    def multiRecordAreaOffset(self):
        return self._multiRecordAreaOffset

    @multiRecordAreaOffset.setter
    def multiRecordAreaOffset(self, obj):
        self._multiRecordAreaOffset = obj

    @property
    def zeroCheckSum(self):
        return self._zeroCheckSum

    @zeroCheckSum.setter
    def zeroCheckSum(self, obj):
        self._zeroCheckSum = obj

    @property
    def productInfoArea(self):
        return self._ProductInfoArea

    @productInfoArea.setter
    def productInfoArea(self, obj):
        self._ProductInfoArea = obj

    @property
    def internalUseArea(self):
        return self._InternalUseArea

    @internalUseArea.setter
    def internalUseArea(self, obj):
        self.internalUseArea = obj

    @property
    def boardInfoArea(self):
        return self._BoardInfoArea

    @boardInfoArea.setter
    def boardInfoArea(self, obj):
        self._BoardInfoArea = obj

    @property
    def chassisInfoArea(self):
        return self._ChassisInfoArea

    @chassisInfoArea.setter
    def chassisInfoArea(self, obj):
        self._ChassisInfoArea = obj

    @property
    def multiRecordArea(self):
        return self._multiRecordArea

    @multiRecordArea.setter
    def multiRecordArea(self, obj):
        self._multiRecordArea = obj

    @property
    def bindata(self):
        return self._bindata

    @bindata.setter
    def bindata(self, obj):
        self._bindata = obj

    @property
    def bodybin(self):
        return self._bodybin

    @bodybin.setter
    def bodybin(self, obj):
        self._bodybin = obj

    def recalcuteCommonHead(self):
        self.bindata = ""
        self.offset = self.SUGGESTED_SIZE_COMMON_HEADER
        d_print("common Header %d" % self.offset)
        d_print("fru eeprom size  %d" % self._frusize)
        if self.internalUseArea is not None and self.internalUseArea.isPresent:
            self.internalUserAreaOffset = self.offset // 8
            self.offset += self.internalUseArea.size
            d_print("internalUseArea is present offset:%d" % self.offset)

        if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent:
            self.chassicInfoAreaOffset = self.offset // 8
            self.offset += self.chassisInfoArea.size
            d_print("chassisInfoArea is present offset:%d" % self.offset)

        if self.boardInfoArea is not None and self.boardInfoArea.isPresent:
            self.boardInfoAreaOffset = self.offset // 8
            self.offset += self.boardInfoArea.size
            d_print("boardInfoArea is present offset:%d" % self.offset)
            d_print("boardInfoArea is present size:%d" %
                    self.boardInfoArea.size)

        if self.productInfoArea is not None and self.productInfoArea.isPresent:
            self.productinfoAreaOffset = self.offset // 8
            self.offset += self.productInfoArea.size
            d_print("productInfoArea is present offset:%d" % self.offset)

        if self.multiRecordArea is not None and self.multiRecordArea.isPresent:
            self.multiRecordAreaOffset = self.offset // 8
            d_print("multiRecordArea is present offset:%d" % self.offset)

        if self.internalUserAreaOffset == self.INITVALUE:
            self.internalUserAreaOffset = 0
        if self.productinfoAreaOffset == self.INITVALUE:
            self.productinfoAreaOffset = 0
        if self.chassicInfoAreaOffset == self.INITVALUE:
            self.chassicInfoAreaOffset = 0
        if self.boardInfoAreaOffset == self.INITVALUE:
            self.boardInfoAreaOffset = 0
        if self.multiRecordAreaOffset == self.INITVALUE:
            self.multiRecordAreaOffset = 0

        self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset
                             - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff
        d_print("zerochecksum:%x" % self.zeroCheckSum)
        self.data = ""
        self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr(
            self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum)

        self.bindata = self.data + self.bodybin
        totallen = len(self.bindata)
        d_print("totallen %d" % totallen)
        if (totallen < self._frusize):
            self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0]))
        else:
            raise FruException('bin data more than %d' % self._frusize, -2)

    def recalcutebin(self):
        self.bodybin = ""
        if self.internalUseArea is not None and self.internalUseArea.isPresent:
            d_print("internalUseArea present")
            self.bodybin += self.internalUseArea.data
        if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent:
            d_print("chassisInfoArea present")
            self.bodybin += self.chassisInfoArea.data
        if self.boardInfoArea is not None and self.boardInfoArea.isPresent:
            d_print("boardInfoArea present")
            self.boardInfoArea.recalcute()
            self.bodybin += self.boardInfoArea.data
        if self.productInfoArea is not None and self.productInfoArea.isPresent:
            d_print("productInfoAreapresent")
            self.productInfoArea.recalcute()
            self.bodybin += self.productInfoArea.data
        if self.multiRecordArea is not None and self.multiRecordArea.isPresent:
            d_print("multiRecordArea present")
            self.bodybin += self.productInfoArea.data

    def recalcute(self, fru_eeprom_size=256):
        self._frusize = fru_eeprom_size
        self.recalcutebin()
        self.recalcuteCommonHead()