#!@PYTHON@

# Copyright (C) 2011  Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

"""This utility program generates a C++ header and implementation files
that can be used as a template of C++ python binding for a C++ class.

Usage: ./mkpywrapper.py ClassName
(the script should be run on this directory)

It will generate two files: classname_python.h and classname_python.cc,
many of whose definitions are in the namespace isc::MODULE_NAME::python.
By default MODULE_NAME will be 'dns' (because this tool is originally
intended to be used for the C++ python binding of the DNS library), but
can be changed via the -m command line option.

The generated files contain code fragments that are commonly used in
C++ python binding implementations.  It will define a class named
s_ClassName which is a derived class of PyModule and can meet the
requirement of the CPPPyObjectContainer template class (see
pycppwrapper_util.h).  It also defines (and declares in the header file)
"classname_type", which is of PyTypeObject and is intended to be used
to define details of the python bindings for the ClassName class.

In many cases the header file can be used as a startpoint of the
binding development without modification.  But you may want to make
ClassName::cppobj a constant variable (and you should if you can).
Many definitions of classname_python.cc should also be able to be used
just as defined, but some will need to be changed or removed.  In
particular, you should at least adjust ClassName_init().  You'll
probably also need to add more definitions to that file to provide
complete features of the C++ class.
"""

import datetime, string, sys
from optparse import OptionParser

# Remember the current year to produce the copyright boilerplate
YEAR = datetime.date.today().timetuple()[0]

def dump_file(out_file, temp_file, class_name, module):
    for line in temp_file.readlines():
        line = line.replace("@YEAR@", str(YEAR))
        line = line.replace("@CPPCLASS@_H", class_name.upper() + "_H")
        line = line.replace("@CPPCLASS@", class_name)
        line = line.replace("@cppclass@", class_name.lower())
        line = line.replace("@MODULE@", module)
        out_file.write(line)

def dump_wrappers(class_name, output, module):
    try:
        if output == "-":
            header_file = sys.stdout
        else:
            header_file = open(output + "_python.h", "w")
        header_template_file = open("wrapper_template.h", "r")
        if output == "-":
            impl_file = sys.stdout
        else:
            impl_file = open(output + "_python.cc", "w")
        impl_template_file = open("wrapper_template.cc", "r")
    except:
        sys.stderr.write('Failed to open C++ file(s)\n')
        sys.exit(1)
    dump_file(header_file, header_template_file, class_name, module)
    dump_file(impl_file, impl_template_file, class_name, module)

usage = '''usage: %prog [options] class_name'''

if __name__ == "__main__":
    parser = OptionParser(usage=usage)
    parser.add_option('-o', '--output', action='store', dest='output',
                      default=None, metavar='FILE',
                      help='prefix of output file names [default: derived from the class name]')
    parser.add_option('-m', '--module', action='store', dest='module',
                      default='dns',
                      help='C++ module name of the wrapper (for namespaces) [default: dns]')
    (options, args) = parser.parse_args()

    if len(args) == 0:
        parser.error('input file is missing')

    class_name = args[0]
    if not options.output:
        options.output = class_name.lower()

    dump_wrappers(class_name, options.output, options.module)
