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

"""
@brief Main Java Generation module
"""

import logging
import pdb
import os
import shutil

import loxi_globals
from loxi_ir import *
import lang_java
import test_data
from collections import namedtuple
from import_cleaner import ImportCleaner

import template_utils
import loxi_utils.loxi_utils as loxi_utils

import java_gen.java_model as java_model

logger = logging.getLogger(__name__)

def gen_all_java(install_dir):
    basedir= '%s/openflowj' % install_dir
    logger.info("Outputting to %s" % basedir)
    if os.path.exists(basedir):
        shutil.rmtree(basedir)
    os.makedirs(basedir)
    copy_prewrite_tree(basedir)
    gen = JavaGenerator(basedir, JavaGeneratorOptions(instrument=True))
    gen.create_of_interfaces()
    gen.create_of_classes()
    gen.create_of_const_enums()
    gen.create_of_factories()

JavaGeneratorOptions = namedtuple("JavaGeneratorOptions", ("instrument",))

class JavaGenerator(object):
    templates_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')

    def __init__(self, basedir, gen_opts):
        self.basedir = basedir
        self.java_model = java_model.model
        self.gen_opts = gen_opts

    def render_class(self, clazz, template, src_dir=None, **context):
        if not src_dir:
            src_dir = "src/main/java/"

        context['class_name'] = clazz.name
        context['package'] = clazz.package
        context['template_dir'] = self.templates_dir
        context['genopts']= self.gen_opts

        filename = os.path.join(self.basedir, src_dir, "%s/%s.java" % (clazz.package.replace(".", "/"), clazz.name))
        dirname = os.path.dirname(filename)
        if not os.path.exists(dirname):
            os.makedirs(dirname)
        prefix = '//::(?=[ \t]|$)'
        logger.debug("rendering filename: %s" % filename)
        with open(filename, "w") as f:
            template_utils.render_template(f, template, [self.templates_dir], context, prefix=prefix)

        try:
            cleaner = ImportCleaner(filename)
            cleaner.find_used_imports()
            cleaner.rewrite_file(filename)
        except:
            logger.info('Cannot clean imports from file %s' % filename)

    def create_of_const_enums(self):
        for enum in self.java_model.enums:
            if enum.name in ["OFPort"]:
                continue
            self.render_class(clazz=enum,
                    template='const.java', enum=enum, all_versions=self.java_model.versions)

            for version in enum.versions:
                clazz = java_model.OFGenericClass(package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version), name="{}SerializerVer{}".format(enum.name, version.dotless_version))

                if enum.is_bitmask:
                    self.render_class(clazz=clazz, template="const_set_serializer.java", enum=enum, version=version)
                else:
                    self.render_class(clazz=clazz, template="const_serializer.java", enum=enum, version=version)

    def create_of_interfaces(self):
        """ Create the base interfaces for of classes"""
        for interface in self.java_model.interfaces:
            #if not utils.class_is_message(interface.c_name):
            #    continue
            self.render_class(clazz=interface,
                    template="of_interface.java", msg=interface)

    def create_of_classes(self):
        """ Create the OF classes with implementations for each of the interfaces and versions """
        for interface in self.java_model.interfaces:
            for java_class in interface.versioned_classes:
                if self.java_model.generate_class(java_class):
                    if not java_class.is_virtual:
                        self.render_class(clazz=java_class,
                                template='of_class.java', version=java_class.version, msg=java_class,
                                impl_class=java_class.name)

                        self.create_unit_test(java_class.unit_test)
                    else:
                        disc = java_class.discriminator
                        if disc:
                            self.render_class(clazz=java_class,
                                template='of_virtual_class.java', version=java_class.version, msg=java_class,
                                impl_class=java_class.name, model=self.java_model)
                        else:
                            logger.warn("Class %s virtual but no discriminator" % java_class.name)
                else:
                    logger.info("Class %s ignored by generate_class" % java_class.name)

    def create_unit_test(self, unit_tests):
        if unit_tests.has_test_data:
            for i in range(unit_tests.length):
                unit_test = unit_tests.get_test_unit(i)
                if unit_test.has_test_data:
                    self.render_class(clazz=unit_test,
                            template='unit_test.java', src_dir="src/test/java",
                            version=unit_test.java_class.version,
                            test=unit_test, msg=unit_test.java_class,
                            test_data=unit_test.test_data)

    def create_of_factories(self):
        for factory in self.java_model.of_factories:
            self.render_class(clazz=factory, template="of_factory_interface.java", factory=factory)
            for factory_class in factory.factory_classes:
                self.render_class(clazz=factory_class, template="of_factory_class.java", factory=factory_class, model=self.java_model)
            self.render_class(clazz=java_model.OFGenericClass(package="org.projectfloodlight.openflow.protocol", name="OFFactories"), template="of_factories.java", versions=self.java_model.versions)

def copy_prewrite_tree(basedir):
    """ Recursively copy the directory structure from ./java_gen/pre-write
       into $basedir"""
    logger.info("Copying pre-written files into %s" % basedir)
