# Copyright 2013, Big Switch Networks, Inc.
#
# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
# the following special exception:
#
# LOXI Exception
#
# As a special exception to the terms of the EPL, you may distribute libraries
# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
# that copyright and licensing notices generated by LoxiGen are not altered or removed
# from the LoxiGen Libraries and the notice provided below is (i) included in
# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
# documentation for the LoxiGen Libraries, if distributed in binary form.
#
# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
#
# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
# a copy of the EPL at:
#
# http://www.eclipse.org/legal/epl-v10.html
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# EPL for the specific language governing permissions and limitations
# under the EPL.

import of_g
import loxi_utils.loxi_utils as utils
import unittest

class OFType(object):
    """
    Encapsulates knowledge about the OpenFlow type system.
    """

    version = None
    base = None
    is_array = False
    array_length = None

    def __init__(self, string, version):
        self.version = version
        self.array_length, self.base = utils.type_dec_to_count_base(string)
        self.is_array = self.array_length != 1

    def gen_init_expr(self):
        if utils.class_is_list(self.base):
            v = "[]"
        elif self.base.find("uint") == 0 or self.base in ["char", "of_port_no_t"]:
            v = "0"
        elif self.base == 'of_mac_addr_t':
            v = '[0,0,0,0,0,0]'
        elif self.base == 'of_wc_bmap_t':
            v = 'const.OFPFW_ALL'
        elif self.base in ['of_octets_t', 'of_port_name_t', 'of_table_name_t',
                           'of_desc_str_t', 'of_serial_num_t']:
            v = '""'
        elif self.base == 'of_match_t':
            v = 'common.match()'
        elif self.base == 'of_port_desc_t':
            v = 'common.port_desc()'
        else:
            v = "None"

        if self.is_array:
            return "[" + ','.join([v] * self.array_length) + "]"
        else:
            return v

    def gen_pack_expr(self, expr_expr):
        pack_fmt = self._pack_fmt()
        if pack_fmt and not self.is_array:
            return 'struct.pack("!%s", %s)' % (pack_fmt, expr_expr)
        elif pack_fmt and self.is_array:
            return 'struct.pack("!%s%s", *%s)' % (self.array_length, pack_fmt, expr_expr)
        elif self.base == 'of_octets_t':
            return expr_expr
        elif utils.class_is_list(self.base):
            return '"".join([x.pack() for x in %s])' % expr_expr
        elif self.base == 'of_mac_addr_t':
            return 'struct.pack("!6B", *%s)' % expr_expr
        elif self.base in ['of_match_t', 'of_port_desc_t']:
            return '%s.pack()' % expr_expr
        elif self.base == 'of_port_name_t':
            return self._gen_string_pack_expr(16, expr_expr)
        elif self.base == 'of_table_name_t' or self.base == 'of_serial_num_t':
            return self._gen_string_pack_expr(32, expr_expr)
        elif self.base == 'of_desc_str_t':
            return self._gen_string_pack_expr(256, expr_expr)
        else:
            return "'TODO pack %s'" % self.base

    def _gen_string_pack_expr(self, length, expr_expr):
        return 'struct.pack("!%ds", %s)' % (length, expr_expr)

    def gen_unpack_expr(self, buf_expr, offset_expr):
        pack_fmt = self._pack_fmt()
        if pack_fmt and not self.is_array:
            return "struct.unpack_from('!%s', %s, %s)[0]" % (pack_fmt, buf_expr, offset_expr)
        elif pack_fmt and self.is_array:
            return "list(struct.unpack_from('!%d%s', %s, %s))" % (self.array_length, pack_fmt, buf_expr, offset_expr)
        elif self.base == 'of_octets_t':
            return "%s[%s:]" % (buf_expr, offset_expr)
        elif self.base == 'of_mac_addr_t':
            return "list(struct.unpack_from('!6B', %s, %s))" % (buf_expr, offset_expr)
        elif self.base == 'of_match_t':
            return 'common.match.unpack(buffer(%s, %s))' % (buf_expr, offset_expr)
        elif self.base == 'of_port_desc_t':
            return 'common.port_desc.unpack(buffer(%s, %s))' % (buf_expr, offset_expr)
        elif self.base == 'of_list_action_t':
            return 'action.unpack_list(buffer(%s, %s))' % (buf_expr, offset_expr)
        elif self.base == 'of_list_flow_stats_entry_t':
            return 'common.unpack_list_flow_stats_entry(buffer(%s, %s))' % (buf_expr, offset_expr)
        elif self.base == 'of_list_queue_prop_t':
            return 'common.unpack_list_queue_prop(buffer(%s, %s))' % (buf_expr, offset_expr)
        elif self.base == 'of_list_packet_queue_t':
            return 'common.unpack_list_packet_queue(buffer(%s, %s))' % (buf_expr, offset_expr)
        elif self.base == 'of_port_name_t':
            return self._gen_string_unpack_expr(16, buf_expr, offset_expr)
        elif self.base == 'of_table_name_t' or self.base == 'of_serial_num_t':
            return self._gen_string_unpack_expr(32, buf_expr, offset_expr)
        elif self.base == 'of_desc_str_t':
            return self._gen_string_unpack_expr(256, buf_expr, offset_expr)
        elif utils.class_is_list(self.base):
            element_cls = utils.list_to_entry_type(self.base)[:-2]
            if ((element_cls, self.version) in of_g.is_fixed_length):
                klass_name = self.base[8:-2]
                element_size, = of_g.base_length[(element_cls, self.version)],
                return 'util.unpack_array(common.%s.unpack, %d, buffer(%s, %s))' % (klass_name, element_size, buf_expr, offset_expr)
            else:
                return "None # TODO unpack list %s" % self.base
        else:
            return "None # TODO unpack %s" % self.base

    def _gen_string_unpack_expr(self, length, buf_expr, offset_expr):
        return 'str(buffer(%s, %s, %d)).rstrip("\\x00")' % (buf_expr, offset_expr, length)

    def _pack_fmt(self):
        if self.base == "char":
            return "B"
        if self.base == "uint8_t":
            return "B"
        if self.base == "uint16_t":
            return "H"
        if self.base == "uint32_t":
            return "L"
        if self.base == "uint64_t":
            return "Q"
        if self.base == "of_port_no_t":
            if self.version == of_g.VERSION_1_0:
                return "H"
            else:
                return "L"
        if self.base == "of_fm_cmd_t":
            if self.version == of_g.VERSION_1_0:
                return "H"
            else:
                return "B"
        if self.base in ["of_wc_bmap_t", "of_match_bmap_t"]:
            if self.version in [of_g.VERSION_1_0, of_g.VERSION_1_1]:
                return "L"
            else:
                return "Q"
        return None

class TestOFType(unittest.TestCase):
    def test_init(self):
        from oftype import OFType
        self.assertEquals("None", OFType("of_list_action_t", 1).gen_init_expr())
        self.assertEquals("[0,0,0]", OFType("uint32_t[3]", 1).gen_init_expr())

    def test_pack(self):
        self.assertEquals('struct.pack("!16s", "foo")', OFType("of_port_name_t", 1).gen_pack_expr('"foo"'))

    def test_unpack(self):
        self.assertEquals('str(buffer(buf, 8, 16)).rstrip("\\x00")', OFType("of_port_name_t", 1).gen_unpack_expr('buf', 8))

if __name__ == '__main__':
    unittest.main()
