from __future__ import with_statement
import os
import sys
import urllib
import glob
from shutil import copyfile
import hec2
from com.rma.model import Project
from javax.swing    import JButton, JDialog, JOptionPane, JEditorPane, UIManager
import traceback
import xml.etree.ElementTree as ET
import datetime
import tempfile, shutil
import json
import zipfile
import webbrowser

########adapted from script_downloader.py
#https://github.com/USACE/rts-utils/tree/master


cwms_home = os.getcwd()
watershed_path = Project.getCurrentProject().getProjectDirectory()
################################################################################
def get_remote_data(url):
	try:
		f = urllib.urlopen(url)
		content = f.read()
		f.close()
	except:
		print('Unable to get url contents')
		return False

	if f.code == 404:
		return False

	return content
################################################################################
def download_file(url, dest):
	try:
		print 'Downloading {} to {}'.format(url, dest)
		urllib.urlretrieve(url, dest)
		print("Download Complete!")
	except:
		raise Exception('Unable to download from: {}'.format(url))
################################################################################
#credit: https://stackoverflow.com/questions/12683834/how-to-copy-directory-recursively-in-python-and-overwrite-all
def recursive_overwrite(src, dest, ignore=None):
    if os.path.isdir(src):
        if not os.path.isdir(dest):
            os.makedirs(dest)
        files = os.listdir(src)
        if ignore is not None:
            ignored = ignore(src, files)
        else:
            ignored = set()
        for f in files:
            if f not in ignored:
                recursive_overwrite(os.path.join(src, f),
                                    os.path.join(dest, f),
                                    ignore)
    else:
        shutil.copyfile(src, dest)
#################################################################################
def script_downloader(remote_repo, selection, appConfig):

	update_libs = bool(appConfig['scripts'][selection]['update_libs'])
	config_files = appConfig['scripts'][selection]['config_files']
	watershed_path = Project.getCurrentProject().getProjectDirectory()
	ws_script_dir = os.path.join(watershed_path, 'scripts')

	scriptSrcURL = '{}/{}/{}'.format(remote_repo, appConfig['scripts'][selection]['remote_dir'], appConfig['scripts'][selection]['filename'])
	print(scriptSrcURL)

	scriptDstFilePath = os.path.join(ws_script_dir, appConfig['scripts'][selection]['filename'])
	print scriptDstFilePath

	# Copy the script file
	if get_remote_data(scriptSrcURL):
		try:
			download_file(scriptSrcURL, scriptDstFilePath)
		except:
			JOptionPane.showMessageDialog(None, "Download failed for script '"+selection+"'", "Copy Error", JOptionPane.ERROR_MESSAGE)
			return

	else:
		JOptionPane.showMessageDialog(None, "Source File doesn't seem to exist for '"+selection+"'\n"+scriptSrcURL, \
		"Something went wrong :-(", JOptionPane.ERROR_MESSAGE)
		return

	#################################################################
	# Check for script config files - These will only be downloaded
	# if they don't exist in the local watershed/shared dir
	#################################################################

	print(config_files)
	print('Config file count: {}'.format(len(config_files)))

	# Keep track of what was actually downloaded
	downloaded_configs = []

	if len(config_files) > 0:

		config_files_dir = os.path.join(watershed_path, 'shared')

		for fname in config_files:
			fileSrcURL = '{}/{}/{}/{}'.format(remote_repo, appConfig['scripts'][selection]['remote_dir'], 'shared', fname)
			fileDstPath = os.path.join(config_files_dir, fname)
			if os.path.isfile(fileDstPath):
				saveConfig = JOptionPane.showConfirmDialog(None,"Configuration file exists.\nIf overwritten local changes synced to master copy on gitHub will not be kept.\nOverwrite configuration file?")
				if saveConfig==0:
					download_file(fileSrcURL, fileDstPath)
					downloaded_configs.append(fileDstPath)
				else:
					print 'Skipping download of config file: {}'.format(fname)
			else:
				download_file(fileSrcURL, fileDstPath)
				downloaded_configs.append(fileDstPath)				


	try:
		temp_dir = tempfile.mkdtemp()
		print 'created temp folder {}'.format(temp_dir)

		# Download the master repo zip for the library packages
		repo_url_parts = remote_repo.split('/')
		repo_url_parts[2] = 'github.com'
		repo_url_parts[5] = 'archive'
		repo_url_parts.append('master.zip')
		zip_url = '/'.join(repo_url_parts)

		download_file(zip_url, temp_dir+'/master.zip')

		with zipfile.ZipFile(os.path.join(temp_dir, 'master.zip'), "r") as z:
			z.extractall(temp_dir)

			print('--Files in temp folder--')
			for f in os.listdir(temp_dir):
				print(f)
				if os.path.isdir(os.path.join(temp_dir, f)):

					pkg_dir_src = os.path.join(temp_dir, f, 'appdata', 'rsgis')
					pkg_dir_dst = os.path.join(os.getenv('APPDATA'), 'rsgis')

					print('*'*50)
					print('Copying repo libraries...')
					print 'From: {}'.format(pkg_dir_src)
					print 'To: {}'.format(pkg_dir_dst)
					print('*'*50)

					# Copy the packages/libs from temp folder to destination
					recursive_overwrite(pkg_dir_src, pkg_dir_dst)

					# Check for 3rd party libraries that need to be downloaded
					#------------------------------------------------------------
					for lib_name, lib_obj in appConfig['third_party_libs'].items():
						filename = os.path.basename(lib_obj['url'])
						lib_dest_dir = os.path.join(os.getenv('APPDATA'), 'rsgis', lib_name)
						version_file = os.path.join(lib_dest_dir, 'version.json')

						download_lib = True

						if os.path.isfile(version_file):
							print 'Loading json file {}'.format(version_file)
							with open(version_file) as json_file:
								version = json.load(json_file)['version']
								if version == lib_obj['version']:
									download_lib = False
									print 'Will not download lib: {}'.format(lib_name)


						if download_lib:

							dest_file = os.path.join(lib_dest_dir, filename)
							download_file(lib_obj['url'], dest_file)

							if zipfile.is_zipfile(dest_file):
								with zipfile.ZipFile(dest_file, "r") as z:
									z.extractall(lib_dest_dir)

								# Delete the zip file
								os.remove(dest_file)

							# Write the version to json file for comparison later
							with open(version_file, 'w') as outfile:
								json.dump(lib_obj, outfile)
					#------------------------------------------------------------

	except:
		print('Unable to create temp folder')
		print "Unexpected error:", sys.exc_info()
		print(traceback.print_exc())
	finally:
		shutil.rmtree(temp_dir)
		print 'removing {}'.format(temp_dir)

	try:
		help_url = appConfig['scripts'][selection]['help_url']
	except:
		help_url = None

	msg = 'Script downloaded for '+selection
	if len(downloaded_configs) > 0:
		msg += '\n\nThe following configuration file(s) have been downloaded:'
		for cf in downloaded_configs:
			msg += '\n'+cf

	JOptionPane.showMessageDialog(None, msg, "Success", JOptionPane.INFORMATION_MESSAGE)

	# Prompt for help documentation if available
	if help_url is not None:
		confirm_docs_msg = "Would you like to view to the documentation for this script?"
		confirm_docs_result = JOptionPane.showConfirmDialog(None, confirm_docs_msg)
		if confirm_docs_result == 0:
			webbrowser.open(help_url, new=2, autoraise=True)
		else:
			return


################################################################################
def getAppConfig(filePath):
	try:
		# Read from the config file
		with open(filePath) as f:
			json_data = json.load(f)
			return json_data
	except:
		return False
################################################################################
def isScriptButtonAdded(filename):

	configFile = watershed_path+'/cavi/watershedScripts.xml'
	scriptPresent = False

	if os.path.isfile(configFile):
		tree = ET.parse(configFile)
		root = tree.getroot()
		for scriptType in root.findall('FORECAST'):
			#print scriptType
			for script in scriptType.findall('Script'):
				#print script.attrib
				if script.attrib['File'] == filename:
					return True

	# Return False - Default if node not found in XML file
	return False
################################################################################
def main():

	code_version = '10Nov2022'
	# Get the config file stored on Github.
	# This allows new scripts to be added without this script needing to be replaced on every PC/Server Watershed

	remote_repo = "https://raw.githubusercontent.com/msweier/mvp-CWMS-utils/master"

	remote_config = get_remote_data(remote_repo+'/script_downloader_mvp/downloader_config.json')
	# Verify remote data was returned, otherwise exit
	if remote_config == False:
		errMsg = 'Failed to read remote config file.\n'
		JOptionPane.showMessageDialog(None, errMsg, "Config Error", JOptionPane.ERROR_MESSAGE)
		return

	appConfig = json.loads(remote_config)

	# Check to see if script downloader needs to be updated (by itself)
	fileVersion = appConfig['version']
	code_version_dt = datetime.datetime.strptime(code_version, '%d%b%Y')
	file_version_dt = datetime.datetime.strptime(fileVersion, '%d%b%Y')

	if code_version_dt < file_version_dt:
		msg = "Script Downloader MVP is out of date, please update using this script.\nLatest version: "\
		+appConfig['version']+'\nYour version: '+code_version
		JOptionPane.showMessageDialog(None, msg, "Version Check", JOptionPane.ERROR_MESSAGE)
	else:
		print('Script Downloader MVP Version is current.')

	choices = appConfig['scripts'].keys()
	choices.sort()

	selection = JOptionPane.showInputDialog(
			None,                                               # dialog parent component
			"Select the script to downloader",             		# message
			"Script Downloader - v"+code_version,         		# title
			JOptionPane.PLAIN_MESSAGE,                          # message type (sets default icon)
			None,                                               # icon to override default
			choices,                                            # list of selections
			choices[0])                                         # initial selection

	# If cancel was clicked
	if selection is None:
		return

	script_filename = appConfig['scripts'][selection]['filename']

	script_downloader(remote_repo, selection, appConfig)

	print("Script complete")
################################################################################
if __name__ == '__main__':
	main()