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

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)

def generate_classes(install_dir):
    for uclass in loxi_globals.unified.classes:
        with template_utils.open_output(install_dir, "loci/src/%s.c" % uclass.name) as out:
            util.render_template(out, "class.c",
                push_wire_types_data=push_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)
            # 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)
            # 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())
