#!/usr/bin/env python2.7
# vim: tabstop=4 softtabstop=4 shiftwidth=4 textwidth=80 smarttab expandtab
"""
* Copyright (C) 2011   Sangoma Technologies Corp.
* All Rights Reserved.
*
* Author(s)
* William Adam <william.adam@sangoma.com>
*
* This code is Sangoma Technologies Confidential Property.
* Use of and access to this code is covered by a previously executed
* non-disclosure agreement between Sangoma Technologies and the Recipient.
* This code is being supplied for evaluation purposes only and is not to be
* used for any other purpose.
"""

import sys
import os
import glob
import json
import re
from optparse import OptionParser

base = os.path.dirname(os.path.realpath(__file__))
# Create OUR libs path
lib_path = os.path.normpath(base + '/../libs')
# Append OUR lib to path
sys.path.append(lib_path)
# Ready to play with our libs :)

# Create logger
import logging
import logging.handlers

logger = logging.getLogger(os.path.basename(os.path.abspath(sys.argv[0])))
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
logger.addHandler(handler)

# Get the safepy templates
from safepy import template


def cleanup_files(path):
    # Ready to go, clean up data dir from py* files (except __init__.py)
    files = glob.glob(path + '/*.py*')
    for file in files:
        os.remove(file)
        logger.debug('REMOVE: ' + file)

def create_file(path, name, content):
    path = path + '/' + name + '.py'
    f = open(path, 'w')
    f.write(template.py_header())
    f.write(content)
    f.close()

    logger.debug('CREATE: ' + path)

def build(options):
    # Path variables
    data_path = os.path.normpath(base + '/../data')
    product='nsc'
    if options.product:
        product = options.product

    product_name='NetBorder Session Controller'
    if options.name:
        product_name = options.name

    product_version = 'master'
    if options.version:
        product_version = options.version

    product_dir = product + '_' + product_version
    product_dir = re.sub(r'[\s|-|\.]', "_", product_dir)

    product_data_path = data_path + '/' + product_dir

    logger.info('Product: ' + product)
    logger.info('Name:    ' + product_name)
    logger.info('Version: ' + product_version)
    logger.info('Dir:     ' + product_data_path)

    product_def_file = product_data_path + '/safepy_def.json'

    # Load the product API definition
    prod_def = json.loads(open(product_def_file).read())
    cleanup_files(product_data_path)
    # Create init
    create_file(product_data_path, '__init__', template.py_init())

    def child_object(obj, obj_def):
        module_py = ""
        # Register children
        if 'object' in obj_def:
            for childobj, childobj_def in obj_def['object'].iteritems():

                if 'singleton' not in childobj_def:
                    module_py += template.py_module_object_register(childobj)
                else:
                    module_py += template.py_module_singleton_object_register(childobj)

            for childobj, childobj_def in obj_def['object'].iteritems():
                if 'singleton' not in childobj_def:
                    module_py += template.py_module_object_property(childobj)
                else:
                    module_py += template.py_module_singleton_object_property(childobj)

        return module_py

    def create_object(obj, obj_def, parent=''):
        module_py = ""
            
        # Any sub-object ?
        if 'object' in obj_def:
            for subobj, subobj_def in obj_def['object'].iteritems():
                logger.info("   + Object: " + subobj)
                module_py += create_object(subobj, subobj_def, obj)

        module_py += template.py_module_object_class(obj, parent)
        child_object(obj, obj_def)
        # Register methods
        if 'methods' in obj_def:
            mod_meth = ['list', 'create', 'upload']
            for meth, meth_def in obj_def['methods'].iteritems():
                if meth not in mod_meth:
                    module_py += template.py_module_method_register(meth,
                                            meth_def['request'])
            if 'object' in obj_def:
                for subobj, subobj_def in obj_def['object'].iteritems():
                    module_py += template.py_module_object_register(subobj, obj)

            if 'object' in obj_def:
                for subobj, subobj_def in obj_def['object'].iteritems():
                    module_py += template.py_module_object_property(subobj)

        # Methods body
        if 'methods' in obj_def:
            mod_meth = ['list', 'create', 'upload']
            for meth, meth_def in obj_def['methods'].iteritems():
                if meth not in mod_meth:
                    module_py += template.py_module_method(meth)

        # Create collection if not singleton
        if 'singleton' not in obj_def:
            module_py += template.py_module_object_collection(obj,
                    parent)
            if 'methods' in obj_def:
                mod_meth = ['list', 'create', 'upload']
                for meth, meth_def in obj_def['methods'].iteritems():
                    if meth in mod_meth:
                        module_py += template.py_module_method_register(meth,
                                                    meth_def['request'])
                # Force list method as early REST defintion doesn't have it
                # listed
                if 'list' not in obj_def['methods']:
                    module_py += template.py_module_method_register('list',
                                                    meth_def['request'])
            # Add any collection methods
            if 'methods' in obj_def:
                mod_meth = ['list', 'create', 'upload']
                for meth, meth_def in obj_def['methods'].iteritems():
                    if meth in mod_meth:
                        if 'create' == meth:
                            module_py += template.py_module_method_create(meth)
                        else:
                            module_py += template.py_module_method(meth)

                # Force list method as early REST defintion doesn't have it
                # listed
                if 'list' not in obj_def['methods']:
                    module_py += template.py_module_method('list')

        return module_py


    # Loop around and process
    for mod, mod_def in prod_def.iteritems():
        logger.info("Module: " + mod)
        module_py = template.py_module_import()

        # Check for objects
        if 'object' in mod_def:
            for obj, obj_def in mod_def['object'].iteritems():
                logger.info(" + Object: " + obj)
                module_py += create_object(obj, obj_def)


        # Create module class
        module_py += template.py_module_class(mod)

        module_py += child_object(mod, mod_def)

        create_file(product_data_path, mod, module_py)

    # Create product
    module_py = template.py_product_import()
    for mod, mod_def in prod_def.iteritems():
        module_py += template.py_product_module_import(mod)

    module_py += template.py_product_class(product, product_version, product_name)


    for mod, mod_def in prod_def.iteritems():
        module_py += template.py_product_module_register(mod)

    for mod, mod_def in prod_def.iteritems():
        module_py += template.py_product_module_property(mod)

    create_file(product_data_path, 'product', module_py)

def main():
    #Parse the options
    usage = "usage: %prog [options] arg"
    optParser = OptionParser(usage)
    optParser.add_option('-p', '--product', action='store', type='string',
                        dest='product', metavar='PRODUCT',
                        help="Product")

    optParser.add_option('-v', '--version', action='store', type='string',
                        dest='version', metavar='VERSION',
                        help="Version")

    optParser.add_option('-n', '--name', action='store', type='string',
                        dest='name', metavar='NAME',
                        help="Name")

    (options, args) = optParser.parse_args()

    build(options)

if __name__ == '__main__':
  main()
