from hec.heclib.dss          import HecDss
from hec.heclib.util         import HecTime
from hec.heclib.util         import Heclib
from hec.plugins.usgs        import UsgsControlFrame
from hec.script              import MessageBox
from java.lang               import Exception as JavaException
from javax.swing             import JFileChooser
from javax.swing             import JOptionPane
from javax.swing.filechooser import FileNameExtensionFilter
import os, sys, threading
#--------------------------------------------#
# conditional imports and global definitions #
#--------------------------------------------#
try :
	from usace.cavi.client import CAVI as cCAVI
	from usace.cavi.script import CAVI as sCAVI
	has_cavi      = True
	cavi_frame    = cCAVI.getBrowserFrame()
	proj_dir      = sCAVI.getWatershed().getProjectDirectory()
	cwms_home     = os.path.join(proj_dir, "..", "..")
	usgs_filename = os.path.join(cwms_home, "database", "Russian.usgs")
	dss_filename  = os.path.join(cwms_home, "database", "Russian_TimeSeries.dss")
	script_dir    = os.path.join(proj_dir, "scripts")
	if not script_dir in sys.path :
		sys.path.append(script_dir)
	try :
		from MessageOutput import Outputter
		outputter = Outputter()
		has_outputter = True
		print("\nMessageOutput.Outputter docstring:\n")
		print(outputter.__doc__)
		print("\nMessageOutput.Outputter.ouput docstring:\n")
		print(outputter.output.__doc__)
	except ImportError :
		has_outputter = False
except ImportError :
	has_cavi      = False
	has_outputter = False
	usgs_filename = None
	dss_filename  = None
#---------------------------#
# static global definitions #
#---------------------------#
script_name       = "1-USGS"
log_filename      = None
max_lookback_days = 60
#-------------------------#
# setup output() function #
#-------------------------#
if has_outputter :
	#--------------------------------------------------------------------------#
	# Use the following properties to control the default behavior of output() #
	#--------------------------------------------------------------------------#
	outputter.messenger     = cavi_frame
	outputter.level         = "INFO"
	outputter.beep          = False
	outputter.acknowledge   = False
	outputter.title         = script_name
	outputter.logmode       = "w"
	outputter.make_log_dir  = False
	outputter.logfile       = log_filename
	output = outputter.output
else :
	#-------------------------------------------------#
	# Create variable log_filename to enable logging. #
	#                                                 #
	# If logging is enabled, use the output_to_log    #
	# variable to turn logging on/off at as desired.  #
	#                                                 #
	# Default behavior of output() is :               #
	#   level       = "NONE"                          #
	#   beep        = False                           #
	#   acknowledge = False                           #
	#   title       = None (defaults to script_name)  #
	#   log         = output_to_log                   #
	#-------------------------------------------------#
	logfile = None
	output_to_log = False
	if log_filename : logfile = open(log_filename, "w")
	def _output(text, level=None, beep=False, acknowledge=False, title=None, log=None) :
		"""
		default output method in lieu of Outputter.output()
		"""
		global logfile, output_to_log
		if beep : print("\a")
		if   not level  or level.upper() == "NONE"    : prefix = ""
		elif level == 1 or level.upper() == "INFO"    : prefix = "INFO: "
		elif level == 2 or level.upper() == "WARNING" : prefix = "WARNING: "
		elif level == 3 or level.upper() == "ERROR"   : prefix = "ERROR: "
		else :
			raise ValueError("Invalid level: %s" % level)
		if prefix :
			for i in range(len(text)) :
				if not text[i].isspace() :
					to_output = "{0}{1}{2}".format(text[:i], prefix, text[i:])
					break
			else :
				to_output = "{0}{1}".format(prefix, text)
		else :
			to_output = text
		print(to_output)
		if logfile and output_to_log if log is None else bool(log) :
			timestr = str(datetime.now())[:-7]
			logfile.write("{0} {1}\n".format(timestr, to_output))
		if acknowledge :
			if not title : title = script_name
			if not level                                  : func = MessageBox.showInformation
			elif level == 0 or level.upper() == "NONE"    : func = MessageBox.showInformation
			elif level == 1 or level.upper() == "INFO"    : func = MessageBox.showInformation
			elif level == 2 or level.upper() == "WARNING" : func = MessageBox.showWarning
			elif level == 3 or level.upper() == "ERROR"   : func = MessageBox.showError
			func(text, title)
	output = _output
#----------------------#
# function choose_file #
#----------------------#
def choose_file(frame, title, starting_dir, description=None, extensions=None, allow_multi_select=False) :
	"""
	Interactively choose file from file system
	"""
	jfc = JFileChooser(starting_dir)
	jfc.setDialogTitle(title)
	jfc.setMultiSelectionEnabled(allow_multi_select)
	if extensions : jfc.setFileFilter(FileNameExtensionFilter(description, extensions))
	if jfc.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION :
		if allow_multi_select :
			return [f.getCanonicalPath() for f in jfc.getSelectedFiles()]
		else :
			return jfc.getSelectedFile().getCanonicalPath()
	return (None, [])[allow_multi_select]
#------------------------#
# function get_usgs_data #
#------------------------#
def get_usgs_data() :
	"""
	Retrieve the data from the USGS
	"""
	global dss_filename, usgs_filename
	if has_cavi :
		frame = cavi_frame
		starting_dir = cwms_home
	else :
		frame = None
		starting_dir = "."
	#------------------------------------------------------------#
	# interactively get the DSS filenme if not already specified #
	#------------------------------------------------------------#
	if not dss_filename :
		dss_filename = choose_file(frame, "Choose HEC-DSS File", starting_dir, "HEC-DSS Files", ["dss"])
		if not dss_filename :
			output("Nothing to do - no DSS file selected", level="WARNING")
			return
		starting_dir = os.path.split(dss_filename)[0]
	#------------------------------------------------------------------#
	# interactively get the USGS data filenme if not already specified #
	#------------------------------------------------------------------#
	if not usgs_filename :
		usgs_filename = choose_file(frame, "Choose USGS Input File", starting_dir, "USGS Input Files", ["usgs"])
		if not usgs_filename :
			output("Nothing to do - no input file selected", level="WARNING")
			return
	#-------------------------------------------------#
	# interactivel get the number of days to retrieve #
	#-------------------------------------------------#
	user_input = JOptionPane.showInputDialog(
			frame,
			"Enter number of days back to retrieve",
			script_name,
			JOptionPane.QUESTION_MESSAGE)
	if user_input is None :
		output("Script canceled.", level="WARNING")
		return 1
		try :
			lookback_days = int(user_input)
		except :
			output("Invalid entry for number of days to retrieve: {0}".format(user_input), level="ERROR")
			return 1
		if lookback_days == 0 :
			output("Nothing to do - zero days to retrieve")
			return 1
		elif lookback_days > max_lookback_days :
			output("Invalid number of days to retrieve: {0}".format(lookback_days), level="ERROR")
	tw = "T-" + user_input + "D, T"
	output("Using time window {0}".format(tw))
	try :
		output("Using USGS file {0}".format(usgs_filename))
		dssFile = HecDss.open(dss_filename, tw)
		output("Using HEC-DSS file {0}".format(dss_filename))
		if has_outputter :
			outputter.capture = True
		usgs = UsgsControlFrame(dssFile)
		usgs.loadStations(usgs_filename)
		istat = usgs.retrieveData()
		dssFile.close()
		if istat == 0 :
			output("Unable to retrieve data from the usgs", level="ERROR", beep=True, acknowledge=True)
			return -1
	except JavaException as e :
		print "Error during data retrieval: {0}".format(e.getMessage())
		return -1
	finally :
		if has_outputter :
			outputter.capture = False
	if has_cavi :
		cavi_frame.getCurrentMode().updatePlotIcons()
	return 0
#-------------------------#
# function clean_dss_file #
#-------------------------#
def clean_dss_file():
	"""
	Delete unwanted WQ data retrieved from the USGS.
	The USGS plugin gets all parameters for a gage, which means it brings along a lot of water quality data.
	"""
	dssFile = HecDss.open(dss_filename)
	try:
		output("---Cleaning water quality paths from dss file---")
		wqpaths = [path for path in dssFile.getPathnameList() if "SPECIFIC" in path \
		or "UNFILTERED" in path \
		or "VOLTAGE" in path \
		or "WATER TEMPERATURE" in path]
		for path in wqpaths:
			output("Deleting {0}".format(path))
		dssFile.delete(wqpaths)
		output("---Finished cleaning water quality paths from dss file---")
		return 0
	except JavaException as e :
		output("Error during file cleaning: {0}".format(e.getMessage()), level="ERROR", beep=True, acknowledge=True)
		return -1
	finally :
		dssFile.close()
#--------------------#
# function ir_to_reg #
#--------------------#
def ir_to_reg():
	"""
	Snaps irregular time series returned by the USGS plugin to regular time series.
	When usgs data is posted in a strange interval, or has some extra values the USGS plugin returns IR data.
	"""
	irpaths = [
				"/DRY C BLW LAMBERT BR/GEYSERVILLE CA/FLOW/*/IR-DAY/USGS/",
				"/RUSSIAN R/CLOVERDALE CA/FLOW/*/IR-DAY/USGS/",
				"/RUSSIAN R/UKIAH CA/FLOW/*/IR-DAY/USGS/"
				"/DRY C BLW LAMBERT BR/GEYSERVILLE CA/STAGE/*/IR-DAY/USGS/",
				"/RUSSIAN R/CLOVERDALE CA/STAGE/*/IR-DAY/USGS/",
				"/RUSSIAN R/UKIAH CA/STAGE/*/IR-DAY/USGS/"
				]
	output("---Snapping IR records to Reg---")
	dssFile = HecDss.open(dss_filename)
	tw90 = "T-" + "90" + "D, T"
	t = HecTime()
	for path in irpaths:
		output("IR Path: {0}".format(path))
		try:
			matObj = dssFile.read(path, tw90)
			t.set(matObj.lastValidDate())
			output("\tlast valid date: {0}".format(t.dateAndTime()))
			newmatObj= matObj.snapToRegularInterval("15MIN", " ", "1MIN", "1MIN")
			output("\tNew Reg Path: {0}".format(newmatObj.getPath()))
			t.set(newmatObj.lastValidDate())
			output("\tlast valid date: {0}".format(t.dateAndTime()))
			dssFile.write(newmatObj)
		except JavaException as e :
			output("\tError during snapping: {0}".format(e.getMessage().replace("\n", "\n\t")), level="WARNING")
	dssFile.close()
	output("---Finished snapping IR records to Reg---")
#---------------#
# function main #
#---------------#
def main() :
	"""
	Run the sequence of functions
	"""
	Heclib.zset("MLVL", "", 0)
	if get_usgs_data() == 0 :
		if clean_dss_file() == 0 :
			ir_to_reg()
			output('Done', beep=True, acknowledge=True)
#
if __name__ == "__main__" :
	#--------------------------------------------------#
	# run the script in another thread to not block UI #
	#--------------------------------------------------#
	threading.Thread(target=main).start()
