# 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.

"""
Code generation

These functions extract data from the IR and render templates with it.
"""

from collections import namedtuple
from itertools import groupby
from StringIO import StringIO
import template_utils
from generic_utils import chunks
import loxi_globals
import loxi_ir.ir as ir
import util
import c_code_gen
import c_gen.of_g_legacy as of_g
import c_gen.type_maps as type_maps
import c_gen.c_type_maps as c_type_maps

CLASS_CHUNK_SIZE = 32

PushWireTypesData = namedtuple('PushWireTypesData',
    ['class_name', 'versioned_type_members'])
PushWireTypesMember = namedtuple('PushWireTypesMember',
    ['name', 'offset', 'length', 'value'])

def push_wire_types_data(uclass):
    if uclass.virtual or not uclass.has_type_members:
        return None

    # Generate a dict of version -> list of PushWireTypesMember
    type_members_by_version = {}
    for version, ofclass in sorted(uclass.version_classes.items()):
        pwtms = []
        for m in ofclass.members:
            if isinstance(m, ir.OFTypeMember):
                if m.name == "version" and m.value == version.wire_version:
                    # Special case for version
                    pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
                else:
                    pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
        type_members_by_version[version] = pwtms

    # Merge versions with identical type members
    all_versions = sorted(type_members_by_version.keys())
    versioned_type_members = []
    for pwtms, versions in groupby(all_versions, type_members_by_version.get):
        versioned_type_members.append((pwtms, list(versions)))

    return PushWireTypesData(
        class_name=uclass.name,
        versioned_type_members=versioned_type_members)

ParseWireTypesData = namedtuple('ParseWireTypesData',
    ['class_name', 'versioned'])
ParseWireTypesVersion = namedtuple('ParseWireTypesVersion',
    ['discriminator', 'subclasses'])
ParseWireTypesSubclass = namedtuple('ParseWireTypesSubclass',
    ['class_name', 'value', 'virtual'])

def parse_wire_types_data(uclass):
    if not uclass.virtual:
        return None

    discriminator = uclass.discriminator

    # Generate a dict of version -> ParseWireTypesVersion
    versioned = {}
    for version, ofclass in sorted(uclass.version_classes.items()):
        subclasses = [ParseWireTypesSubclass(class_name=subclass.name,
                                             value=subclass.member_by_name(discriminator.name).value,
                                             virtual=subclass.virtual)
                      for subclass in ofclass.protocol.classes if subclass.superclass and subclass.superclass.name == ofclass.name]

        subclasses.sort(key=lambda x: x.value)
        versioned[version] = ParseWireTypesVersion(discriminator=discriminator,
                                                   subclasses=subclasses)

    return ParseWireTypesData(class_name=uclass.name,
                              versioned=sorted(versioned.items()))

# Output multiple LOCI classes into each C file. This reduces the overhead of
# parsing header files, which takes longer than compiling the actual code
# for many classes. It also reduces the compiled code size.
def generate_classes(install_dir):
    for i, chunk in enumerate(chunks(loxi_globals.unified.classes, CLASS_CHUNK_SIZE)):
        with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
            for uclass in chunk:
                util.render_template(out, "class.c",
                    push_wire_types_data=push_wire_types_data(uclass),
                    parse_wire_types_data=parse_wire_types_data(uclass))
                # Append legacy generated code
                c_code_gen.gen_new_function_definitions(out, uclass.name)
                c_code_gen.gen_accessor_definitions(out, uclass.name)

# TODO remove header classes and use the corresponding class instead
def generate_header_classes(install_dir):
    for cls in of_g.standard_class_order:
        if cls.find("_header") < 0:
            continue
        with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
            util.render_template(out, "class.c",
                push_wire_types_data=None,
                parse_wire_types_data=None)
            # Append legacy generated code
            c_code_gen.gen_new_function_definitions(out, cls)
            c_code_gen.gen_accessor_definitions(out, cls)

def generate_classes_header(install_dir):
    # Collect legacy code
    tmp = StringIO()
    c_code_gen.gen_struct_typedefs(tmp)
    c_code_gen.gen_new_function_declarations(tmp)
    c_code_gen.gen_accessor_declarations(tmp)
    c_code_gen.gen_generics(tmp)

    with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
        util.render_template(out, "loci_classes.h",
            legacy_code=tmp.getvalue())

def generate_lists(install_dir):
    for cls in of_g.ordered_list_objects:
        with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
            util.render_template(out, "class.c",
                push_wire_types_data=None,
                parse_wire_types_data=None)
            # Append legacy generated code
            c_code_gen.gen_new_function_definitions(out, cls)
            c_code_gen.gen_list_accessors(out, cls)

def generate_strings(install_dir):
    object_id_strs = []
    object_id_strs.append("of_object")
    object_id_strs.extend(of_g.ordered_messages)
    object_id_strs.extend(of_g.ordered_non_messages)
    object_id_strs.extend(of_g.ordered_list_objects)
    object_id_strs.extend(of_g.ordered_pseudo_objects)
    object_id_strs.append("of_unknown_object")

    with template_utils.open_output(install_dir, "loci/src/loci_strings.c") as out:
        util.render_template(out, "loci_strings.c", object_id_strs=object_id_strs)

def generate_init_map(install_dir):
    with template_utils.open_output(install_dir, "loci/src/loci_init_map.c") as out:
        util.render_template(out, "loci_init_map.c", classes=of_g.standard_class_order)

def generate_type_maps(install_dir):
    # Collect legacy code
    tmp = StringIO()
    c_type_maps.gen_type_to_obj_map_functions(tmp)
    c_type_maps.gen_type_maps(tmp)
    c_type_maps.gen_length_array(tmp)
    c_type_maps.gen_extra_length_array(tmp)

    with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
        util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
