#!/usr/bin/env python

import argparse
import logging
import importlib
import os
import sys

# CCPP framework imports
from common import CCPP_INTERNAL_VARIABLE_DEFINITON_FILE
from parse_tools import init_log, set_log_level
from metadata_table import MetadataHeader

###############################################################################
# Set up the command line argument parser and other global variables          #
###############################################################################

parser = argparse.ArgumentParser()
method = parser.add_mutually_exclusive_group(required=True)
method.add_argument('--config', '-c', action='store',
                    help='path to CCPP prebuild configuration file')
method.add_argument('--metafile', '-m', action='store',
                    help='name of metadata file to convert (requires -o)')
parser.add_argument('--outputdir', '-o', action='store',
                    help='directory where to write the html files',
                    required='--metafile' in sys.argv or '-m' in sys.argv)

# List and order of variable attributes to output to HTML
ATTRIBUTES = [ 'local_name', 'standard_name', 'long_name', 'units',
               'type', 'dimensions', 'kind', 'intent', 'optional' ]

###############################################################################
# Functions and subroutines                                                   #
###############################################################################

def parse_arguments():
    """Parse command line arguments."""
    args = parser.parse_args()
    config = args.config
    filename = args.metafile
    outdir = args.outputdir
    return (config, filename, outdir)

def import_config(configfile, logger):
    """Import the configuration from a given configuration file"""

    if not os.path.isfile(configfile):
        raise Exception("Configuration file {0} not found".format(configfile))

    # Import the host-model specific CCPP prebuild config;
    # split into path and module name for import
    configpath = os.path.abspath(os.path.dirname(configfile))
    configmodule = os.path.splitext(os.path.basename(configfile))[0]
    sys.path.append(configpath)
    ccpp_prebuild_config = importlib.import_module(configmodule)

    # Get the base directory for running metadata2html.py from
    # the default build directory value in the CCPP prebuild config
    basedir = os.path.join(os.getcwd(), ccpp_prebuild_config.DEFAULT_BUILD_DIR)
    logger.info('Relative path to CCPP directory from  CCPP prebuild config: {}'.format(
                                                ccpp_prebuild_config.DEFAULT_BUILD_DIR))

    config = {}
    # Definitions in host-model dependent CCPP prebuild config script
    config['variable_definition_files'] = ccpp_prebuild_config.VARIABLE_DEFINITION_FILES
    config['scheme_files']              = ccpp_prebuild_config.SCHEME_FILES
    # Add model-independent, CCPP-internal variable definition files
    config['variable_definition_files'].append(CCPP_INTERNAL_VARIABLE_DEFINITON_FILE)
    # Output directory for converted metadata tables
    config['metadata_html_output_dir'] = ccpp_prebuild_config.METADATA_HTML_OUTPUT_DIR.format(build_dir=basedir)

    return config

def get_metadata_files_from_config(config, logger):
    """Create a list of metadata filenames for a CCPP prebuild configuration"""
    filenames = []
    for sourcefile in config['variable_definition_files'] + config['scheme_files'].keys():
        metafile = os.path.splitext(sourcefile)[0]+'.meta'
        if os.path.isfile(metafile):
            filenames.append(metafile)
        else:
            # DH* Warn for now, raise exception later when
            # old metadata format is no longer supported
            logger.warn("Metadata file {} for source file {} not found, assuming old metadata format".format(
                                                                                       metafile, sourcefile))
    return filenames

def get_output_directory_from_config(config, logger):
    """Return the html output directory for a CCPP prebuild configuration"""
    outdir = config['metadata_html_output_dir']
    if not os.path.isdir(outdir):
        raise Exception("Output directory {} for converted metadata tables does not exist".format(outdir))
    return outdir

def convert_to_html(filename_in, outdir, logger):
    """Convert a metadata file into html (one html file for each table)"""
    if not os.path.isfile(filename_in):
        raise Exception("Metadata file {} not found".format(filename_in))
    logger.info("Converting file {} to HTML".format(filename_in))
    metadata_headers = MetadataHeader.parse_metadata_file(filename_in)
    for metadata_header in metadata_headers:
        filename_out = metadata_header.to_html(outdir, ATTRIBUTES)
        if filename_out:
            logger.info("  ... wrote {}".format(filename_out))

def main():
    # Initialize logging
    logger = init_log('metadata2html')
    set_log_level(logger, logging.INFO)
    # Convert metadata file
    (configfile, filename, outdir) = parse_arguments()
    if configfile:
        config = import_config(configfile, logger)
        filenames = get_metadata_files_from_config(config, logger)
        outdir = get_output_directory_from_config(config, logger)
        for filename in filenames:
            convert_to_html(filename, outdir, logger)
    else:
        convert_to_html(filename, outdir, logger)

if __name__ == '__main__':
    main()