### Imports ###
#Import future with statement
from __future__ import with_statement

#HEC library imports
from hec.heclib.dss import HecDss
from hec.heclib.util import HecTime
from hec.io import TimeSeriesContainer
from hec.lang import DSSPathString

#Python imports
import csv
### End Imports ###

### Functions ###
def getTimeSeriesFromDssFile(dssFileName):
	'''
	Gets all TimeSeriesContainers from the given DSS file name
	:param dssFileName: absolute path of the DSS file
	:type dssFileName: string
	:return tscList: list of all of the TimeSeriesContainers from the DSS file located at dssFileName
	:rtype tscList: list
	'''
	#Initialize a list object that will be populated with TimeSeriesContainers
	tscList = []
	
	### Step 1 ###
	#Open the DSS file using the HecDss class
	dssFile = HecDss.open(dssFileName)

	### Step 2 ###
	#Get condensed catalog from the DSS file
	catalog = dssFile.getCondensedCatalog()

	### Step 3 ###
	#Iterate through the catalog and add each TimeSeriesContainer to tscList
	for condensedReference in catalog:
		### Step 3a ###
		##Getting the string that represents the condensed catalog record
		pathName = condensedReference.toString()
		pathString = DSSPathString(pathName)
		pathString.setDPart("")
		pathNameMinusDPart = pathString.getPathname()
		### Step 3b ###
		##Using pathNameMinusDPart to get a TimeSeriesContainer from dssFile
		tsc = dssFile.get(pathNameMinusDPart)
		### Step 3c ###
		##Add tsc to tscList
		tscList.append(tsc)
	dssFile.close()

	return tscList

def generateCSVDataHeaders(tscList):
	'''
	Generates the CSV data headers for a given list of TimeSeriesContainers
	:param tscList: list of TimeSeriesContainers
	:type tscList: list
	:return headers: list of the CSV header rows
	:rtype headers: list
	'''
	##Initialize return variable
	headers = []

	##Generating a total of 7 rows
	for i in range(0,7):
		##Initialize list for each row
		csvRow = []
		##Define if/elif statement to assign text to the first column of each row
		if i==0:
			csvRow.append("A")
		elif i==1:
			csvRow.append("B")
		elif i==2:
			csvRow.append("C")
		elif i==3:
			csvRow.append("E")
		elif i==4:
			csvRow.append("F")
		elif i==5:
			csvRow.append("Units")
		elif i==6:
			csvRow.append("Type")
		##Skip one column by assigning empty string to the second item for each row
		csvRow.append("")
		
		### Step 4 ###
		##Iterate through the tscList and extract information from the TimeSeriesContainer
		for tsc in tscList:
			### Step 4a ###
			##Get pathName from tsc and create a DSSPathString object
			pathName = tsc.fullName
			pathString = DSSPathString(pathName)
			
			### Step 4b ###
			##Define if/elif statement to assign the correct information depending on which row we are currently on
			if i==0:
				csvRow.append(pathString.getAPart())
			elif i==1:
				csvRow.append(pathString.getBPart())
			elif i==2:
				csvRow.append(pathString.getCPart())
			elif i==3:
				csvRow.append(pathString.getEPart())
			elif i==4:
				csvRow.append(pathString.getFPart())
			elif i==5:
				csvRow.append(tsc.units)
			elif i==6:
				csvRow.append(tsc.type)
		##At the end of each row, add list to the headers object
		headers.append(csvRow)
	
	return headers

def getEarliestAndLatestTimes(tscList):
	'''
	Gets the earliest and latest HecTimes from a given list of TimeSeriesContainers
	:param tscList: list of TimeSeriesContainers
	:type tscList: list
	:return earliestTime: earliest HecTime from the TimeSeriesContainers in tscList
	:return latestTime: latest HecTime from the TimeSeriesContainers in tscList
	:rtype earliestTime: HecTime
	:rtype latestTime: HecTime
	'''
	##Initialize return variables
	earliestHecTime = HecTime()
	latestHecTime = HecTime()
	
	### Step 5 ###
	##Get the minimum value out of all of the first times of the TimeSeriesContainers in tscList
	earliestTime = min([tsc.times[0] for tsc in tscList])
	
	### Step 6 ###
	##Get the maximum value out of all of the last times of the TimeSeriesContainers in tscList
	latestTime = max([tsc.times[-1] for tsc in tscList])
	
	### Step 7 ###
	##Set time of HecTime objects
	earliestHecTime.set(earliestTime)
	latestHecTime.set(latestTime) 
	
	return earliestHecTime, latestHecTime

def generateCSVDataRows(tscList):
	'''
	Generates the CSV data rows for a list of TimeSeriesContainers
	Only intended to be used for daily data
	:param tscList: list of TimeSeriesContainers
	:type tscList: list
	:return dataRows: list of the CSV data rows, containing times and values from each TimeSeriesContainer
	:rtype dataRows: list
	'''
	##Initialize return variable
	dataRows = []
	
	### Step 8 ###
	##Get earliest and latest HecTimes from the tscList
	earliestHecTime, latestHecTime = getEarliestAndLatestTimes(tscList)
	
	##Initialize a timeHolder variable, which will help keep track of the current day that is computing
	timeHolder = HecTime(earliestHecTime)
	
	### Step 9 ###
	##Gathering values from tscList
	### Step 9a ###
	##Fill in the end argument for the range function
	##Total number of values in range = (number of days between earliestHecTime and latestHecTime) + 1
	for i in range(0, earliestHecTime.computeNumberIntervals(latestHecTime,1440) + 1):
		##Initialize the csvRow object as an empty list
		csvRow = []
		##The first column in each row contains a number indicating the row number
		##The row number should start at 1, and will increment by 1 for each new row
		csvRow.append(i+1)
		##The second column in each row contains the date from timeHolder
		##To exclude the hours and minutes from the date, call the method 'date(0)'
		csvRow.append(timeHolder.date(0))
		##Iterate through tscList
		##Use 'tsc' as the iterator variable
		for tsc in tscList:
			### Step 9b ###
			##If value of timeHolder is less than the first time in tsc, output empty string
			if timeHolder.value() < tsc.times[0]:
				csvRow.append("")
			### Step 9c ###
			##If value of timeHolder is greater than the last time in tsc, output empty string
			elif timeHolder.value() > tsc.times[-1]:
				csvRow.append("")
			### Step 9d ###
			##Get currently processing day's value for the TimeSeriesContainer
			##Compute an offset to ensure the value is from the right day
			##offset = (number of days between first time in the TimeSeriesContainer and the earliest time in all of the TimeSeriesContainers)
			else:
				offset = (tsc.times[0] - earliestHecTime.value())/1440
				csvRow.append(str(tsc.values[i - offset]))
		##After each day of iteration, add the csvRow to dataRows and add 1 day to timeHolder
		dataRows.append(csvRow)
		timeHolder.addDays(1)
	return dataRows

def combineTwoLists(list1, list2):
	'''
	Combines two lists sequentially into a single list
	:param list1: first list
	:param list2: second list
	:type list1: list
	:type list2: list
	:return combinedList: combined list of list1 and list2
	:rtype combinedList: list
	'''
	##Initialize return variable
	combinedList = []
	##Add each item in list1 to combinedList
	for item in list1:
		combinedList.append(item)
	##Add each item in list2 to combinedList
	for item in list2:
		combinedList.append(item)

	return combinedList

def writeCSVDataToFile(csvFileName, csvData):
	'''
	Creates new CSV file at csvFileName location
	Writes csvData to the csvFileName
	:param csvFileName: absolute path of the CSV file
	:type csvFileName: string
	:param csvData: all rows of data that will be written out to the CSV file
	:type csvData: list
	:return None: this function doesn't return a value
	:rtype None: NoneType
	'''
	#Open CSV file and write all of the rows of csvData to it at once
	with open(csvFileName, 'wb') as csvFile:
		writer = csv.writer(csvFile)
		writer.writerows(csvData)
	return None
### End Functions ###

### Main Code ###
print("Running script")

##Define workingDirectory (folder that the workshop was unzipped to)
workingDirectory = r'C:\Class\HEC API Scripting Basics\Workshop 1'"\\"

##Define DSS file name
dssFileName = workingDirectory + r'Workshop_1_Input.dss'

##Get all timeseries from DSS file and put into a list of TimeSeriesContainers
### TEST Step 1 ###
print("\n---TEST Step 1---")
tscList = getTimeSeriesFromDssFile(dssFileName)
print("tscList: %s" %tscList)
print("---End TEST Step 1---")
### End TEST Step 1 ###

##Generate the header rows for the CSV file and put into a list of rows
##Within each row, each column is a list item
### TEST Step 2 ###
print("\n---TEST Step 2---")
headers = generateCSVDataHeaders(tscList)
for i,row in enumerate(headers):
	print("headers row %s: %s" %(i,row))
print("---End TEST Step 2---")
### End TEST Step 2 ###

##Generate the data rows for the CSV file and put into a list of rows
##Within each row, each column is a list item
### TEST Step 3 ###
print("\n---TEST Step 3---")
dataRows = generateCSVDataRows(tscList)
for i, row in enumerate(dataRows[0:5]):
	print("dataRows row %s: %s" %(i, row))
print("dataRows total number of rows: %s" %len(dataRows))
print("---End TEST Step 3---")
### End TEST Step 3 ###

### TEST Step 4 ###
print("\n---TEST Step 4---")
##Combine the two lists (headers and dataRows) into a single list
csvData = combineTwoLists(headers, dataRows)
##Define output filename for CSV file
csvFileName = workingDirectory + r'Workshop_1_Output.csv'
##Write the csvData to a CSV file located at csvFileName
writeCSVDataToFile(csvFileName, csvData)
print("---End TEST Step 4---")
### End TEST Step 4 ###

print("Script finished!")
### End Main Code ###