# 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, 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())
