<gh_stars>1-10
"""
A set of functions required to post-process TRNSYS simulation output files
"""


import csv
import re

from pybps.util import dict_cleanconvert


def parse_log(file_abspath):
    """Parse warning and error info from TRNSYS generated log file.

    Parses warning and error count when simulation ends with errors.
    If simulation ends successfully, counts number of warnings and return
    successful completion message.

    Args:
        file_abspath: absolute path to result file.

    Returns:
        dict.

    Raises:
        IOError: problem reading out_file
    """

    runsumdict = {}

    # Parse data from Type-46-generated tab separated file and return a list of
    # dicts (one dict per each row of result file)
    pat01 = re.compile(r'Simulation stopped with errors')
    pat02 = re.compile(r'Total Warnings\s+:\s+(\d+)')
    pat03 = re.compile(r'Total Fatal Errors\s+:\s+(\d+)')
    pat04 = re.compile(r'Warning at time')
    with open(file_abspath, 'rU') as log_f:
        temp = log_f.read()
        match = pat01.search(temp)
        if match:
            runsumdict['Message'] = match.group()
            match = pat02.search(temp)
            runsumdict['Warnings'] = int(match.group(1))
            match = pat03.search(temp)
            runsumdict['Errors'] = int(match.group(1))
        else:
            runsumdict['Message'] = "Simulation ended successfully"
            match = pat04.findall(temp)
            runsumdict['Warnings'] = len(match)
            runsumdict['Errors'] = 0

    return runsumdict


def parse_type46(file_abspath):
    """Parse results from TRNSYS Type 46 generated file.

    Parses monthly integrated results from files generated by TRNSYS Type 46,
    also kown as "Printegrator". Also parses min and max instantaneous values
    (and corresponding times) and total values for all variables, but discards
    max and min integrated values, which can be easily deduced from monthly
    integrated values.

    Args:
        file_abspath: absolute path to result file.

    Returns:
        list of dicts (one dict per useful row of result file).

    Raises:
        IOError: problem reading out_file
    """

    # Parse data from Type-46-generated tab separated file and return a list of
    # dicts (one dict per each row of result file)
    with open(file_abspath, 'rU') as out_f:
        next(out_f) # Skip first line which doesn't hold any useful info
        dr = csv.DictReader(out_f, delimiter='\t')
        fieldnames = dr.fieldnames
        dr_list = list(dr)
        dict_list = []
        months_list = ['January','February','March','April','May','June','July','August','September','October','November','December']
        # Verify that the file is a valid Type46 output file
        if fieldnames[0].strip() == 'Month' or fieldnames[0].strip() == 'Period':
            # Check if the given file holds results integrated monthly
            if dr_list[0][fieldnames[0]].strip() in months_list:
                # Build a list of dict (one row from file = one dict)
                for idx, row in enumerate(dr_list):
                    # Only append rows containing results and discard
                    # rows containing max and min integrated values
                    if (any(row[fieldnames[0]].strip()) and
                        (idx not in [16, 21, 25, 26, 30, 31])):
                        dict_list.append(row)
            else:
                # Print error message if integration period is not monthly
                print("Invalid integration period." +
                    "\nFunction only parses monthly integrated results.")
        # Print error message if file format doesn't fit Type 46
        else:
            print("Unrecognized file format.")

        # Post-process generated list of dicts to remove unwanted whitespaced
        # and convert strings with numbers to float type
        for idx, item in enumerate(dict_list):
            dict_list[idx] = dict_cleanconvert(dict_list[idx])

    return dict_list
