# Purpose: to copy output files from TestingFilesAndScript\Testing_YYYY_MM_DD_HH_MM_SS folders to TestingFilesAndScript\TestCases ExpectedOutput folders
#           This is required after making updates to HydroPlus that cause test cases to fail, and before the SVN Commit. 
#           This should only be used when it is known the new HydroPlus output is correct, and the expectedoutput is now incorrect.
# Requires: File ListOfTests.txt (which has paths to ExpectedOutput directories) and command line argument Testing_YYYY_MM_DD_HH_MM_SS 
# Run from the directory TestingFilesAndScript.
# At command prompt, give the path to the folder containing the new test results, Testing_YYYY_MM_DD_HH_MM_SS 
# Example of the command prompt C:\iTree\HydroPlus\TestingFilesAndScript>python z_Copy_TestCaseOutput_to_ExpectedOutput.py Testing_2020_11_11_07_08_09
# Created: ESF student Li Zhang, working with Professor T. Endreny in fall 2020
# 2021/11/05: T. Endreny, Clarified variable names, reformatted all indentations, refactored to simplify flow using single input path, 
#               ... and introduced critical caution to refuse deletion of expectedoutput folder content if new output content is missing.
# Ver1 11/05/2021 


#import Python libraries
import subprocess
import os
import time
from random import uniform
import xml.etree.ElementTree as ET
import csv 
import shutil
import glob
from filecmp import dircmp
import sys

#define output and expectedoutput folders containing TestCase files
folder_output = "output"
folder_expectedoutput = "expectedoutput"
#define ListOfTests_file_name as input ListOfTests.txt
ListOfTests_file_name = "ListOfTests.txt"

#if the length of command line input argument is > 1 then the folder with new expectedoutput was provided
if len(sys.argv) > 1:
    folder_newExpectedOutput = sys.argv[1]
    print("\n")
    print("Confirmation: The command line input contains {} as the folder with the new expected output.\n".format(folder_newExpectedOutput))
#else if the length of command line input argument is <= 1 then the folder with new expectedoutput was not likely provided
else:
    print("\n")
    print("Error: The command line input (CLI) must contain the name of the folder with the new expected output.")
    print("Solution: Enter CLI with three items: the python executable, the script, the the folder name.")
    print("Example CLI: >python z_Copy_TestCaseOutput_to_ExpectedOutput.py Testing_YYYY_MM_DD_HH_MM_SS")
    print("Please note: Typing python works when the system environment variable path is set to the python.exe")
    print("Please note: The Testing_YYYY_MM_DD_HH_MM_SS is replaced by a folder with actual date time values.")
    print("Terminating: This error terminates the script.")
    sys.exit()
    
#folder containing model outputs that will be copied into expectedoutput, read from command line >python z_Copy_TestCaseOutput_to_ExpectedOutput.py Testing_2020_11_11_07_08_09
Testing_DateTimeFolder_name = sys.argv[1]


#path to working directory 
TestingFilesAndScript_Folder_path = os.getcwd()

#Create path to folder containing model outputs that will be copied into expectedoutput
Testing_DateTimeFolder_path = os.path.join(TestingFilesAndScript_Folder_path,Testing_DateTimeFolder_name)

Flag_RefusedDelete = False

#open ListOfTests.txt as f, read each line into a tuple
with open(os.path.join(TestingFilesAndScript_Folder_path,ListOfTests_file_name), "r") as f:
    #define data for each line in f with tuple command, reading objects separated by commas
    data=[tuple(line) for line in csv.reader(f)]
    
#For each line in ListOfTests.txt, creating ListOfTests_Input_Row as the line of input as a vector
for ListOfTests_Input_Row in data:
    #skip over the first two lines of the ListOfTests.txt if the first word [0] is a key word for other than the directory
    if ListOfTests_Input_Row[0] == "Executable":
        continue
    if ListOfTests_Input_Row[0] == "TestName":
        continue
    #Define Testing_CaseFolder_name as the unique folder name containing the new output directory
    Testing_CaseFolder_name = str(ListOfTests_Input_Row[0])

    #define TestCase_Folder_path as value of 2nd element in ListOfTests_Input_Row, counting starts at 0
    TestCase_Folder_path = ListOfTests_Input_Row[1]

    #Algorithm to parse TestCase_Folder_path for use with input and expectedoutput folders
    #Find final backslash in TestCase_Folder_path string, which is point where input folder is listed
    str_backslash = "\\"
    TestCase_Folder_w_Input_path = TestCase_Folder_path
    len_backslash_inputs = TestCase_Folder_w_Input_path.rfind(str_backslash)
    len_TestCase_Folder_w_Input_path = len(TestCase_Folder_w_Input_path)
    len_folder_input = (len_TestCase_Folder_w_Input_path - len_backslash_inputs)
    len_TestCase_Folder_path = len_backslash_inputs + 1
    folder_input = TestCase_Folder_w_Input_path[-len_folder_input:]
    TestCase_Folder_path = TestCase_Folder_path[:len_TestCase_Folder_path]

    #Define Testing_Output_path as the path and directory containing the new outputs that will be copied into expectedoutputs
    Testing_Output_path = os.path.join(Testing_DateTimeFolder_path,Testing_CaseFolder_name,folder_output)

    #Define TestCase_ExpectedOutput_path as the path and directory containing the expected outputs that will be overwritten, replaced by new outputs
    TestCase_ExpectedOutput_path = str(TestCase_Folder_path + folder_expectedoutput)
       
    #For each file in the old expected output folder, we delete all files
    for file in glob.glob(TestCase_ExpectedOutput_path+'/*.*'):

        #Critical: First confirm the output folder exists before deleting expected output
        if os.path.exists(Testing_Output_path):
            #try to complete next function
            try:
                #Remove expectedoutput folder files
                os.remove(file) 
            #exception when try failed
            except Exception as e:
                print('Failed to delete {}. Reason: {}.'.format(file, e))
            #Messages: delete and copy
            print("Replacing file {}".format(file))
            print("... with file from {}".format(Testing_Output_path))
        else:
            print('Refused to delete {}'.format(file))
            print('... due to missing output folder {}'.format(Testing_Output_path))
            Flag_RefusedDelete = True
  
    #For every file in the new output directory 
    for file in glob.glob(Testing_Output_path+'/*.*'):
        try:
            #Use shutil function to copy the file to the TestCase_ExpectedOutput_path
            shutil.copy(file, TestCase_ExpectedOutput_path)            
        except Exception as e:
            print('Failed to copy {}. Reason: {}.'.format(file, e))
    
if (Flag_RefusedDelete == True):
    print('\n')
    print('Refused to delete some files listed in {}'.format(ListOfTests_file_name))
    print('... due to their absence in folder {}.'.format(Testing_DateTimeFolder_name))
