"""
This file holds self-contained functions that are commonly used by ResSim scripts.
Much of this was ripped from the CRT "NWDJyLib", but only things need for Willamette were included
"""

from hec.model import PairedValuesExt
from hec.model import RunTimeStep
from hec.heclib.util import HecTime

import os, sys, csv, codecs


def fileOpenReadClose(txtFileName):
    """Open a text file and reads the lines, storing as a list"""
    if not os.path.exists(txtFileName): 
        errMsg = "File does not exist: \n%s" %txtFileName
        raise AssertionError, errMsg
    txtFile = open(txtFileName, 'r')
    txtLines = txtFile.readlines()
    txtFile.close()
    return txtLines
    
def stripOutCommentLines(txtLines):
    """
    Strip out comment lines from list of strings (assumes comment character is #).
    Returns a list of strings."""
    newLines = []
    for txtLine in txtLines :
            line = txtLine.strip()
            if len(line) == 0 : pass               # skip blank lines
            elif line.count(",") == len(line) : pass # CSV file with only commas
            elif line.startswith("#") : pass       # commented line
            elif line.startswith('"#') : pass      # commented line
            elif line.startswith('",') : pass      # commented line
            elif line.startswith(codecs.BOM_UTF8): pass #Weird UTF coding
            else : 
                #strip out any inline comments
                if "#" in line:
                    cmtIdx = line.find("#") #returns -1 if not found
                    line = line[:cmtIdx].strip()
                newLines.append(line)
    return newLines
    
def getCSVDictReader(txtLines):
    """
    Gets a CSV DictReader object.
    You can iterate on this object, but not get a specific line.
    Note that the .fieldnames parameter is not available until you've iterated once
    by using .next() or going inside a for-loop.
    If you want a list, use :func:`convertCSVDictReaderToListDict`
    
    :param list txtLines: list of strings (comment lines should already be 
                          erased, and first line should be headers)
    :return list: A list of dictionary objects (one dictionary for each line)
                  keys of the dictionary are the column header names
    """
    return csv.DictReader(txtLines)
    
def convertCSVDictReaderToListDict(csvDictObj):
    """
    Takes a csv.DictReader object and "listifies" it so you don't have to iterate on it
    """
    outList = []
    for d in csvDictObj: outList.append(d)
    return outList
    
def getListOfDictsFromCSV(txtFile):
    """
    Returns a list of dictionaries (one dictionary for each row in the file).
    The keys of the dictionaries are the column header names. 
    
    :param str txtFile: .csv file with the column headings
    """
    lines = fileOpenReadClose(txtFile)
    lines = stripOutCommentLines(lines)
    csvDict = getCSVDictReader(lines)
    listDict = convertCSVDictReaderToListDict(csvDict)
    return listDict

def getElevationStorageTable(reservoirName, network):
    """
    Returns a table that inputs elevation and returns storage
    
    :param str reservoirName: The reservoir name as it exists in ResSim
    :param RssSystem network:
    :return elevStorTable: Can use .interpolate on this object
    :rtype: PairedValuesExt
    """
    reservoirObj = network.findReservoir(reservoirName)
    storageElement = reservoirObj.getStorageFunction()
    storageTable = storageElement.getElevationStorageValues()
    pairedDataContainer = storageTable.getPairedDataContainer()
    elevStorTable = PairedValuesExt() 
    elevStorTable.setData(pairedDataContainer)
    return elevStorTable

    elevStorTable = functions.getElevationStorageTable("Mica", network)
    storElevTable = functions.getStorageElevationTable("Mica", network)
    fullPoolStor = elevStorTable.interpolate(fullPoolElevations["Mica"])

def getHecTimeFromRuntimestep(rtsObj):
    """
    Returns an HecTime object that reflects the true time of the step (2400 hours).
    When Running ResSim daily modeling, the .getHecTime() method does not work
    as it should--it returns an HecTime object with daily granularity, which isn't
    good when trying to retrieve data from other timeseries. This function returns
    the current day with a granularity of minutes.
    
    This function should be used exclusively in the place of .getHecTime()
    
    :param RunTimeStep rtsObj: 
    """
    currentDate = rtsObj.getHecTime().clone()
    '''
    OLD, ResSim 3.2
    # If the hecTime object returned is daily granularity, subtract a day due to midnight shift
    if currentDate.getTimeGranularity() == HecTime.DAY_INCREMENT: # days
        currentDate.subtractDays(1) # Midnight shift
    '''
    currentMonth = currentDate.month()  
    currentDay = currentDate.day()
    currentYear = currentDate.year()
    # If the daily hecTime object does not have a granularity of minutes, 
    # Set the current date to a granularity of minutes (2400 hours at the end of the day)
    if currentDate.getTimeGranularity() == HecTime.DAY_INCREMENT: 
        currentDate.setTimeGranularity(HecTime.MINUTE_INCREMENT) #granularity of minutes
        currentDate.setYearMonthDay(currentYear, currentMonth, currentDay, 1440)
    return currentDate