"""
For documentation purpose, run the script with -h flag

System Requirements:
  ArcGIS 10.3 and above
  Python 2.7.X

Dependencies:
  None
"""

import logging
import sys
import os

from argparse import ArgumentParser
from datetime import datetime as dt


###############################################################################
# helper (manipulates handlers for the logic of the application)

def run_app():
    """Run the logic of application"""
    tat, pth, templates, logger = get_input_parameter()
    create_templates(tat, pth, templates, logger)


def create_templates(tat_database, output_path, templates, logger):

    if not arcpy.Exists(tat_database):
        logger.error('The specified Tools and Templates database does not exist. Program Terminating.')
        sys.exit(1)

    tbl_metadata_items = tat_database + "/TEIS_Metadata_Items"
    tbl_metadata_tables = tat_database + "/TEIS_Metadata_Tables"

    if not arcpy.Exists(tbl_metadata_items):
        logger.error('The Tools and Templates database does not contain the '
                     'TEIS_Metadata_Items table. Program Terminating.')
        sys.exit(1)

    if not arcpy.Exists(tbl_metadata_tables):
        logger.error('The Tools and Templates database does not contain the '
                     'TEIS_Metadata_Tables table. Program Terminating.')
        sys.exit(1)

    if not arcpy.Exists(output_path):
        logger.error('The output geodatabase specified does not exist. Program Terminating.')
        sys.exit(1)

    lst_template_names = []
    lst_fgdb_names = []
    lst_sde_names = []
    lst_fc_fields = ['Feature_Class', 'Feature_Type', 'Spatial_Reference']

    for field in arcpy.ListFields(tbl_metadata_items):
        fld_name = str(field.name)
        if fld_name.startswith('STE_') or fld_name.startswith('TEI'):
            lst_template_names.append(fld_name)
        elif fld_name.startswith('FGDB_'):
            lst_fgdb_names.append(fld_name)
        elif fld_name.startswith('SDE_'):
            lst_sde_names.append(fld_name)

    lst_templates_create = []
    if templates:
        for temp in templates:
            if temp in lst_template_names:
                lst_templates_create.append(temp)
            else:
                logger.warning('{} does not exist as a template in the TEIS Metadata Items table'.format(temp))

        if len(lst_templates_create) == 0:
            logger.error('None of the specified templates exist in the TEIS Metadata Items Table.'
                         ' Program Terminating.')
            sys.exit(1)
        lst_template_names = lst_templates_create

    with arcpy.da.SearchCursor(tbl_metadata_tables, lst_fc_fields) as s_cursor:
        for row in s_cursor:
            fc_name = str(row[0])
            if fc_name in lst_template_names:
                fc_type = str(row[1]).upper()

                if str(row[2]) == 'None':
                    sr = None
                else:
                    sr = arcpy.SpatialReference(str(row[2]).replace('_', ' '))

                if 'VIEW' in fc_type:
                    fc_type = fc_type[:-4]

                temp_name = fc_name

                logger.info('Creating {}'.format(temp_name))

                temp_path = output_path + '/' + temp_name

                if arcpy.Exists(output_path + '/' + temp_name):
                    arcpy.Delete_management(output_path + '/' + temp_name)

                if fc_type != 'TABLE':
                    arcpy.CreateFeatureclass_management(output_path, temp_name, fc_type, spatial_reference=sr)
                else:
                    arcpy.CreateTable_management(output_path, temp_name)

                if fc_name.startswith('STE_') or fc_name.endswith('_SENSITIVE'):
                    lst_cursor_fields = lst_sde_names
                else:
                    lst_cursor_fields = lst_fgdb_names

                where_clause = fc_name + ' IS NOT NULL'
                sql_clause = 'ORDER BY ' + fc_name
                with arcpy.da.SearchCursor(tbl_metadata_items, lst_cursor_fields + [fc_name], where_clause=where_clause,
                                           sql_clause=(None, sql_clause)) as s_cursor_2:
                    for itm in s_cursor_2:
                        fld_name = str(itm[0])
                        fld_alias = str(itm[1])
                        fld_type = str(itm[2])
                        fld_width = itm[3]
                        fld_precision = itm[4]
                        fld_scale = itm[5]
                        arcpy.AddField_management(temp_path, field_name=fld_name, field_type=fld_type,
                                                  field_precision=fld_precision, field_scale=fld_scale,
                                                  field_length=fld_width, field_alias=fld_alias)


def get_field_list(tat_database, fc_name, field_prefix='FGDB'):
    tbl_metadata_items = os.path.join(tat_database, 'TEIS_Metadata_Items')

    lst_fgdb_names = []
    dict_fields = {}

    for field in arcpy.ListFields(tbl_metadata_items):
        fld_name = str(field.name)
        if fld_name.startswith(field_prefix + '_'):
            lst_fgdb_names.append(fld_name)

    where_clause = fc_name + ' IS NOT NULL'
    sql_clause = 'ORDER BY ' + fc_name
    with arcpy.da.SearchCursor(tbl_metadata_items, lst_fgdb_names + [fc_name], where_clause=where_clause,
                               sql_clause=(None, sql_clause)) as s_cursor:
        for row in s_cursor:
            fld_name = str(row[0])
            fld_alias = str(row[1])
            fld_type = str(row[2])
            fld_width = row[3]
            fld_precision = row[4]
            fld_scale = row[5]

            dict_fields[fld_name] = [fld_alias, fld_type, fld_width, fld_precision, fld_scale]

    return dict_fields


def add_specified_field(tat_database, fc, field_name, logger):

    if field_name in [f.name for f in arcpy.ListFields(fc)]:
        return

    fc_name = os.path.basename(fc)
    if not fc_name.endswith('Tbl'):
        fc_name = fc_name.split('Tbl')[0] + 'Tbl'

    dict_fields = get_field_list(tat_database, fc_name)

    if field_name in dict_fields:
        logger.info('Adding Field {}'.format(field_name))
        fld_alias = dict_fields[field_name][0]
        fld_type = dict_fields[field_name][1]
        fld_width = dict_fields[field_name][2]
        fld_precision = dict_fields[field_name][3]
        fld_scale = dict_fields[field_name][4]
        arcpy.AddField_management(fc, field_name=field_name, field_type=fld_type,
                                  field_precision=fld_precision, field_scale=fld_scale,
                                  field_length=fld_width, field_alias=fld_alias)


###############################################################################
# handler (defines core functions of the application)

def get_input_parameter():
    """
    Parse arguments and set up logger

    :return: directory where "Data Loading Directory" will be created, version of TEIS data load process
    :rtype: str, str
    """
    try:
        parser = ArgumentParser(
            description='Run this script to create a new template feature class based on the TEIS_Metadata_Items in '
                        'the Tools and Templates geodatabase.  Individual templates can be generated by using a -t '
                        'flag otherwise all templates will be generated.')
        parser.add_argument('tat', help='Path to the tools and templates geodatabase')
        parser.add_argument('pth', help='Geodatabase to create the template(s) in.')
        parser.add_argument('-t', '--templates', nargs='+', type=str, help='Specific template(s) to generate')
        parser.add_argument('--log_level', default='INFO', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
                            help='Log level')
        parser.add_argument('--log_dir', help='Path to log Directory')
        args = parser.parse_args()

        log_name = 'main_logger'
        logger = logging.getLogger(log_name)

        log_fmt = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        log_file_base_name = os.path.basename(sys.argv[0])
        log_file_extension = 'log'
        timestamp = dt.now().strftime('%Y-%m-%d_%H-%M-%S')
        log_file = "{}_{}.{}".format(timestamp, log_file_base_name, log_file_extension)

        logger.setLevel(args.log_level)

        sh = logging.StreamHandler()
        sh.setLevel(args.log_level)
        sh.setFormatter(log_fmt)
        logger.addHandler(sh)

        if args.log_dir:
            try:
                os.makedirs(args.log_dir)
            except OSError:
                pass

            fh = logging.FileHandler(os.path.join(args.log_dir, log_file))
            fh.setLevel(args.log_level)
            fh.setFormatter(log_fmt)
            logger.addHandler(fh)

        # Start the script
        return args.tat, args.pth, args.templates, logger

    except Exception as e:
        logging.exception('Unexpected exception. Program terminating.')
        exit(1)


###############################################################################
# register event (runs the helper with different configurations)

if __name__ == '__main__':
    try:
        # Import arcpy
        import arcpy
    except:
        logging.error('No ArcGIS licenses available to run this tool.  Program terminating.')
        sys.exit(1)
    run_app()
else:
    try:
        # Import arcpy
        import arcpy
    except:
        logging.error('No ArcGIS licenses available to run this tool.  Program terminating.')
        sys.exit(1)

