# -*- coding: utf-8 -*-
#
#
# $Id: bytemsg.py,v 1.4 2004/11/09 08:20:56 xyb Exp $

"""Open Unified Storage System Protocol

Stability: None

@author: U{HD<mailto:hdcola@gmail.com>}

@see: Open Unified Storage System Protocol规范
"""
import struct

class ByteMessage:
    """二进制消息基类

    虚类
    """

    def __init__(self):
        """初始化一个消息"""
        # 消息头
        # self.head = None
        # 消息体
        # self.body = None
        # 消息工具
        # self.msgutilcls = None
        # 当前的消息名称
        # self.msgname = ''
        # 当前协议的名称
        # self.protocolname = ''

    def loadMessage(self, packet):
        """从二进制流中加载出消息对象"""
        # 架载包头
        self.head.loadHead(packet[:len(self.head)])
        self.msgname = self.msgutilcls.commandinfo[self.head.id]
        # 依据消息ID架载包体
        self.body.loadBody(self.msgname, packet[len(self.head):])

    def setMsgName(self, msgname):
        """设置消息名"""
        self.head.setId(self.msgutilcls.nametoid[msgname])
        self.msgname = msgname

    def packed(self):
        """打包消息为二进制流PDU"""
        body = self.body.packed() or ''
        self.head.setLength(len(self.head) + len(body))
        return self.head.packed() + body

    def __str__(self):
        """字符串化"""
        return str(self.head) + '\n' + str(self.body)

    def pack_none(self, fields):
        return None

    def unpack_none(self, message):
        return None

class ByteMessageHead:
    """二进制消息的消息头抽象类"""
    def __init__(self, parent):
        # 长度
        self.length = 12
        # 命令ID
        self.id = 0
        # 序列号
        self.sequence = 0
        # 他爹
        self.parent = parent

    def __len__(self):
        """包头定长12"""
        return 12

    def setId(self,id):
        """设置命令ID"""
        self.id = id

    def setSequence(self,sequence):
        """设置发送序列"""
        self.sequence = sequence

    def setLength(self, length):
        """包的整长"""
        self.length = length

    def loadHead(self, header):
        """转换一个PDU (protocol data unit)到一个消息头
        消息头的格式为length(4字节)、commandid（4字节）、sequence（4字节），共12字节长度
        """
        self.length,self.id,self.sequence = struct.unpack('>III', header)

    def packed(self):
        """转换一个消息头为二进制流
        消息头的格式为length(4字节)、commandid（4字节）、sequence（4字节），共12字节长度
        """
        return struct.pack('>III', self.length, self.id, self.sequence)

    def __str__(self):
        """字符串化"""
        plist = []
        plist.append("消息ID:%s" % self.id)
        plist.append("消息长度：%s" % self.length)
        plist.append("消息序列号：%s" % self.sequence)
        return reduce(lambda x,y: x + "\n" + y, plist)

class ByteMessageBody:
    """二进制报文的消息体抽像类"""
    def __init__(self, parent):
        # 消息的内容
        self.fields = {}
        self.setField = self.fields.__setitem__
        # 他爹
        self.parent = parent

    def loadBody(self, msgname, packet):
        """转换一个二进制流为消息体"""
        # 找到解包的方法
        method = getattr(self.parent , \
                "unpack_%s_%s" %(self.parent.protocolname, msgname), \
                self.parent.unpack_none)
        method(packet)
        self.conversionString()

    def packed(self):
        """转换消息体为二进制流"""
        # 找到打包方法
        method = getattr(self.parent , \
                "pack_%s_%s" %(self.parent.protocolname, self.parent.msgname),\
                self.parent.pack_none)
        return method(self.fields)

    def conversionString(self):
        """去除fileds中字符串中的\x00"""
        for field in self.fields.keys():
            if ( isinstance(self.fields[field],str) ):
                index = self.fields[field].find('\0')
                if index > -1:
                    self.fields[field] = self.fields[field][:index]

    def __str__(self):
        """字符串化"""
        if len(self.fields) > 0:
            plist = []
            for field in self.fields.keys():
                plist.append(str(field) + "："  + str(self.fields[field]))
            return reduce(lambda x,y: x + "\n" + y, plist)
        else:
            return ""

class ByteMessageUtil:
    """消息处理基类"""
    def __init__(self):
        """初始化"""
        self.commandinfo = {}
        self.nametoid = {}

    def getCommandinfo(self):
        """获取命令信息"""
        return self.commandinfo

    def getCommandName(self, commandid):
        return self.commandinfo[commandid]
