@echo off
@rem *************************************************************************
@rem This script supports coordinating the update of the MW_HOME directory
@rem based on an archive file prepared using copyBinary.sh
@rem
@rem First the user will clone their gold master MW_HOME and then apply a patch
@rem allowing for testing and validation.  Then the user will perform
@rem copyBinary.sh on this patched MW_HOME and will distribute the resulting
@rem archive file to each remote node.  Finally, the RolloutService will
@rem coordinate actions on each node in order to shutdown the appropriate
@rem processes, apply the new patched MW_HOME into place, and eventually
@rem restart the processes.
@rem
@rem *************************************************************************
@rem
@rem Important internal variables:
@rem  MW_HOME      - This value is in the environment from the process that is
@rem                 performing the execution.
@rem  BACKUP_DIR   - This indicates the location where the existing OracleHome
@rem                 should be moved to.  It could be later restored in the
@rem                 event of a rollback/revert.
@rem  PATCHED      - This indicates the location of the patch archive which
@rem                 will be applied using pasteBinary, or the patch dir which
@rem                 will be applied using a simple file move operation
@rem  ACTION       - This value should be one of the following:
@rem                prepare
@rem                update
@rem                validate
@rem  REVERT_FROM_ERROR - This will indicate that this opertion is a revert
@rem     and this will require logic to determine whether to
@rem     keep the existing MW_HOME in the BACKUP_DIR or
@rem     to delete it when BACKUP_DIR is an archive file.
@rem  NEW_JAVA_HOME - This value will indicate that a new JAVA_HOME should be
@rem           applied to both the new MW_HOME as well as the particular domain
@rem
@rem  VERBOSE       - This value indicates extra output should be enabled
@rem
@rem *************************************************************************
SETLOCAL ENABLEEXTENSIONS EnableDelayedExpansion

SET SCRIPT_PATH=%~dp0
FOR %%i IN ("%SCRIPT_PATH%") DO SET SCRIPT_PATH=%%~fsi

SET WIN_FIND=%SystemRoot%\system32\find.exe
if NOT EXIST !WIN_FIND! (
  call :warning "Could not locate the Windows version of find.exe under SystemRoot\system32.  We will use the value found in %PATH%.  If a non-Windows version is found, there may be incompatibilities that prevent this script from executing properly."
  SET WIN_FIND=find
)

:: Set the time zone string
for /f "tokens=2*"  %%a in ('reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation /v TimeZoneKeyName') do set TZ_STR=%%b
if DEFINED VERBOSE echo The timezone string is:  %TZ_STR%





IF DEFINED MW_HOME if EXIST "%MW_HOME%" GOTO DIROK (
  call :error "Fatal Error: MW_HOME must be set and must be a valid directory: %MW_HOME%"
  GOTO:FINIS
)



::
:: Initial starting point for the script.  Set some initial values and
:: perform the operation requested
::
:DIROK
if DEFINED VERBOSE (
  call :info "DIROK"
)

if NOT DEFINED ACTION (
  call :error "ACTION must be defined."
  GOTO:FINIS
)

if DEFINED PATCHED (
 set PATCHED=%PATCHED:"=%
)
if DEFINED BACKUP_DIR (
 set BACKUP_DIR=%BACKUP_DIR:"=%
)
set ACTION=%ACTION:"=%
set ERRFILE=%SCRIPT_PATH%\updateErrors.err
set VERBOSE_OUTFILE=%SCRIPT_PATH%\UpdateOracleHome.cmd.out
set PASTE_BIN_OUT=%SCRIPT_PATH%\pasteBin.out
set DETACH_HOME_OUT=%SCRIPT_PATH%\detachHome.out
set ATTACH_HOME_OUT=%SCRIPT_PATH%\attachHOme.out


:: This script lives in domain/bin/patching
set DOMAIN_DIR=%SCRIPT_PATH%\..\..\
:: Patch backup dir for storing backup scripts
set PATCH_BACKUP=patching_backup
set PATCH_BACKUP_DOM=%PATCH_BACKUP%\domain
set PATCH_BACKUP_OH=%PATCH_BACKUP%\ohome
set DOMAIN_FILES[0]=setDomainEnv.cmd
set DOMAIN_FILES[1]=%DOMAIN_DIR%\bin\setDomainEnv.cmd
set DOMAIN_FILES[2]=nodemanager.properties
set DOMAIN_FILES[3]=%DOMAIN_DIR%\nodemanager\nodemanager.properties
set DOMAIN_FILES[4]=tokenValue.properties
set DOMAIN_FILES[5]=%DOMAIN_DIR%\init-info\tokenValue.properties
set DOMAIN_FILES[6]=domain-info.xml
set DOMAIN_FILES[7]=%DOMAIN_DIR%\init-info\domain-info.xml
set DOMAIN_FILES[8]=nodemanager-properties.xml
set DOMAIN_FILES[9]=%DOMAIN_DIR%\init-info\nodemanager-properties.xml
set DOMAIN_FILES[10]=startscript.xml
set DOMAIN_FILES[11]=%DOMAIN_DIR%\init-info\startscript.xml
set DOMAIN_FILES[12]=setNMJavaHome.cmd
set DOMAIN_FILES[13]=%DOMAIN_DIR%\bin\setNMJavaHome.cmd
set FILES_START=0
set FILES_END=13


if /I "%ACTION%" == "prepare" (
  GOTO:prepareUpdateScript
) else if /I "%ACTION%" == "update" (
  GOTO:updateOracleHome
) else if /I "%ACTION%" == "validate" (
  GOTO:validateUpdate
) else if /I "%ACTION%" == "checkreq" (
  GOTO:checkPrereq
) else (
  call :error "Fatal Error: %ACTION% is not supported."
  GOTO:FINIS
)




::
:: PREPARE PHASE OF OPERATIONS
:: validate arguments
:: any necessary cleanup of tmp files or left over files
:: write tmp_update_script with necessary info
:: backup files with JavaHome if necessary
::
:prepareUpdateScript
 if DEFINED VERBOSE (
  call :info "prepareUpdateScript"
 )
 call :validateArguments || GOTO:FINIS

 call :cleanup

 if exist "%TMP_UPDATE_SCRIPT%" (
   call :warning "%TMP_UPDATE_SCRIPT% already exists when trying to write it, attempting to delete again"
   del /F "%TMP_UPDATE_SCRIPT%"
   if exist "%TMP_UPDATE_SCRIPT%" (
     call :error "Failed at second attempt to delete %TMP_UPDATE_SCRIPT%"
   ) else {
     call :info "Successfuly deleted %TMP_UPDATE_SCRIPT% on second attempt"
   )
 )

 :: write the tmp update script
 (
   echo set PATCHED=!PATCHED!
   echo set BACKUP_DIR=!BACKUP_DIR!
   echo set ACTION=update
   echo set REVERT_FROM_ERROR=%REVERT_FROM_ERROR%
   echo set NEW_JAVA_HOME=%NEW_JAVA_HOME%
   echo set VERBOSE=%VERBOSE%


   echo call %SCRIPT_PATH%\UpdateOracleHome.cmd ^> %VERBOSE_OUTFILE% 2^>^&1


   echo if NOT ERRORLEVEL 1 (
   if DEFINED VERBOSE (
     echo type %VERBOSE_OUTFILE%
   )
   if DEFINED NEW_JAVA_HOME (
     echo echo Setting JAVA_HOME to %NEW_JAVA_HOME%
     echo set JAVA_HOME=%NEW_JAVA_HOME%
     echo echo JAVA_HOME is now %%JAVA_HOME%%
     echo exit /b 42
   ) else (
     echo if exist "%%MW_HOME%%\%PATCH_BACKUP_DOM%" (
     echo echo Unsetting JAVA_HOME because we are rolling back to a previous JAVA ver
     echo set JAVA_HOME=
     echo exit /b 42
     echo ^)
   )
   if DEFINED VERBOSE (
     echo ^) else (
     echo type %VERBOSE_OUTFILE%
   )
   echo ^)

 ) >> %TMP_UPDATE_SCRIPT%

 if ERRORLEVEL 1 (
   call :error "Could not write %TMP_UPDATE_SCRIPT%"
   GOTO:FINIS
 )

for /f %%i in ("%TMP_UPDATE_SCRIPT%") do set size=%%~zi
if %size% LEQ 0 (
   call :error "After writing, %TMP_UPDATE_SCRIPT% is still empty"
   GOTO:FINIS
)


 if DEFINED VERBOSE (
   call :info "Wrote %TMP_UPDATE_SCRIPT%"
   type %TMP_UPDATE_SCRIPT%
 )

 ::TODO: chmod %TMP_UPDATE_SCRIPT%?


 if DEFINED NEW_JAVA_HOME (
   call :backupJavaHomeDomainFiles
 )

 call :info "Successfully prepared %TMP_UPDATE_SCRIPT%"

GOTO:done







:: update phase
::
:: first decide what operations we are going to do during udpate
:: call detachHome if using pasteBinary.cmd
:: then move aside existing MW_HOME
:: when patched is a dir, we will copy it into place
:: when patched is an archive, OR we have a new javahome then we will use pasteBin
::
:updateOracleHome

 if DEFINED VERBOSE (
   call :info "updateOracleHome"
 )
 call :validateArguments || GOTO:FINIS
 call :resolve_MW_HOME

 set COPY_PATCHED=
 set USE_PASTE_BIN=
 set PASTE_BIN_OPTIONS=-ohAlreadyCloned true
 set USE_JAVA=%JAVA_HOME%
 if DEFINED NEW_JAVA_HOME (
   set USE_PASTE_BIN=true
   set USE_JAVA=%NEW_JAVA_HOME%
   call :createJavaHomeFormats
 )

 if DEFINED PATCHED (
   if exist "%PATCHED%\" (
     set COPY_PATCHED=true
   ) else (
     set USE_PASTE_BIN=true
     set PASTE_BIN_OPTIONS=-archiveLoc %PATCHED%
   )
 )


 ::call detach first as it modifies files under OracleHome
 if DEFINED USE_PASTE_BIN if /I "!USE_PASTE_BIN!" == "true" (
   :: first detach, pasteBin will always reattach
   call "!MW_HOME!\oui\bin\detachHome.cmd" -noconsole > "%SCRIPT_PATH%\detachHome.out"
   if ERRORLEVEL 1 (
     call :updateError "Could not use detachHome.cmd on !MW_HOME!"
     type "%SCRIPT_PATH%\detachHome.out" >> "%ERRFILE%"
     GOTO:FINIS
   )
 )

 if NOT DEFINED BACKUP_DIR (
   call :backupJavaHomeFiles || (
     call :REATTACH_MW_HOME
     GOTO:FINIS
   )
   set KNOWN_LOCATION=!MW_HOME!
 ) else (
   ::now we can backup_MW_HOME correctly
   call :backup_MW_HOME || (
     call :REATTACH_MW_HOME
     GOTO:FINIS
   )
   set KNOWN_LOCATION=!BACKUP_DIR!
   set KNOWN_LOCATION=!KNOWN_LOCATION:"=!

   if DEFINED COPY_PATCHED if /I "!COPY_PATCHED!" == "true" (
     if DEFINED VERBOSE (
       call :info "Now will move %PATCHED% dir to !FULL_MW_HOME!"
     )
     move "%PATCHED%" "!FULL_MW_HOME!"
     if ERRORLEVEL 1 (
       call :updateError "Could not move %PATCHED% to %FULL_MW_HOME%, restoring !FULL_MW_HOME!"
       move "!BACKUP_DIR!" "!FULL_MW_HOME!"
       if ERRORLEVEL 1 (
         call :updateError "Unrecoverable error - could not restore !FULL_MW_HOME! from !BACKUP_DIR!"
         GOTO:FINIS
       )
       call :REATTACH_MW_HOME
       GOTO:FINIS
     )
     if DEFINED VERBOSE (
       call :info "Successfully moved the PATCHED dir into place, %PATCHED% -> !MW_HOME!"
     )
   )
 )


 if DEFINED USE_PASTE_BIN if /I "!USE_PASTE_BIN!" == "true" (
   if DEFINED VERBOSE (
     call :info "Now will use pasteBinary.cmd with %PASTE_BIN_OPTIONS%"
   )

   if DEFINED VERBOSE (
     call :info "!KNOWN_LOCATION!\oracle_common\bin\pasteBinary.cmd -javaHome !USE_JAVA! -targetOracleHomeLoc !FULL_MW_HOME! -executeSysPrereqs false !PASTE_BIN_OPTIONS! > %SCRIPT_PATH%\pasteBin.out"
   )
   :: pasteBinary
   call "!KNOWN_LOCATION!\oracle_common\bin\pasteBinary.cmd" -javaHome "!USE_JAVA!" -targetOracleHomeLoc "!FULL_MW_HOME!"  -executeSysPrereqs false !PASTE_BIN_OPTIONS! > %SCRIPT_PATH%\pasteBin.out

   if ERRORLEVEL 1 (
     call :updateError "could not run !KNOWN_LOCATION!\oracle_common\bin\pasteBinary.cmd -javaHome !USE_JAVA! -targetOracleHomeLoc !FULL_MW_HOME! -executeSysPrereqs false !PASTE_BIN_OPTIONS! > %SCRIPT_PATH%\pasteBin.out"
     GOTO:MW_HOME_ERROR
   ) else (

     :: we have to do this because pasteBinary does not return error as we expect
     if NOT EXIST "!MW_HOME!\wlserver\server\bin\startNodeManager.cmd" (
       call :updateError "PasteBinary.cmd claimed to have succeeded but we cannot find !MW_HOME! files"
       call :updateError "ran !KNOWN_LOCATION!\oracle_common\bin\pasteBinary.cmd -javaHome !USE_JAVA! -targetOracleHomeLoc !FULL_MW_HOME! -executeSysPrereqs false !PASTE_BIN_OPTIONS! > %SCRIPT_PATH%\pasteBin.out"
       GOTO:MW_HOME_ERROR
     ) else (
       if DEFINED VERBOSE (
         call :info "Successfully used pasteBinary to update !FULL_MW_HOME!"
       )
     )
   )
 )

 call :updateJavaHomeFiles || GOTO:FINIS

 call :info "Successfully updated OracleHome"
GOTO:done


:jrestore
call :restoreJavaHomeFiles
GOTO:EOF

::
::
:REATTACH_MW_HOME
::reattach MW_HOME
 call "!MW_HOME!\oui\bin\attachHome.cmd" -noconsole > %SCRIPT_PATH%\attachHome.out
 if ERRORLEVEL 1 (
   call :updateError "!MW_HOME!"\oui\bin\attachHome.cmd reported error, !MW_HOME! may not be registered"
   type "%SCRIPT_PATH%\attachHome.out" >> %ERRFILE%
 )
GOTO:EOF

::
::
::
:MW_HOME_ERROR
 call :updateError "pasteBinary.cmd failed, restoring !FULL_MW_HOME!"
 type "%SCRIPT_PATH%\pasteBin.out" >> "%ERRFILE%"

 ::reattach MW_HOME
 call "!KNOWN_LOCATION!\oui\bin\attachHome.cmd" -noconsole > %SCRIPT_PATH%\attachHome.out
 if ERRORLEVEL 1 (
   call :updateError "!KNOWN_LOCATION!\oui\bin\attachHome.cmd reported error, !FULL_MW_HOME! may not be registered"
   type "%SCRIPT_PATH%\attachHome.out" >> %ERRFILE%
 )

 if not defined BACKUP_DIR (
   call :info "will now restore all of the files from %PATCH_BACKUP_OH%"
   call :jrestore
 ) else (
   if exist "!FULL_MW_HOME!.err\" (
     rd /S /Q "!FULL_MW_HOME!.err"
   )

   :: if pasteBin created a partial MW_HOME, move it to .err
   if exist "!MW_HOME!" (
     call :updateError "!KNOWN_LOCATION!\oracle_common\bin\pasteBinary.cmd created a partial MW_HOME, saving it to !FULL_MW_HOME!.err"
     move "!MW_HOME!" "!FULL_MW_HOME!.err"
     if ERRORLEVEL 1 (
      call :updateError "Could not preserve the partial MW_HOME after failed pasteBinary.cmd.  Unable to move to !FULL_MW_HOME!.err"
      rd /S /Q "!MW_HOME!"
     )
   )
   call :updateError "moving !BACKUP_DIR! to !FULL_MW_HOME!"
   move "!BACKUP_DIR!" "!FULL_MW_HOME!"
   if ERRORLEVEL 1 (
     call :updateError "Could not restore !FULL_MW_HOME! from !BACKUP_DIR! - unable to execute move !BACKUP_DIR! !FULL_MW_HOME!"
   )
 )
GOTO:FINIS




::
::
::
:restoreFilesFromPatchBackup

 if DEFINED VERBOSE (
   call :info restoreFilesFromPatchBackup
 )
 :: go through our list of files and put them back into place
 for /L %%i in (%FILES_START%,2,%FILES_END%) do (
   set /A loc=%%i + 1
   for %%l in (!loc!) do (
     if exist "!MW_HOME!\%PATCH_BACkUP_DOM%\!DOMAIN_FILES[%%i]!" (
       move "!MW_HOME!\%PATCH_BACKUP_DOM%\!DOMAIN_FILES[%%i]!" "!DOMAIN_FILES[%%l]!"
        if ERRORLEVEL 1 (
         call :updateError "Could not restore !DOMAIN_FILES[%%l]! from !MW_HOME!\%PATCH_BACKUP_DOM%\!DOMAIN_FILES[%%i]!"
         set errorRestoringFile=true
       ) else (
         if DEFINED VERBOSE (
       call :info "Successfully restored !DOMAIN_FILES[%%l]!"
         )
       )
     )
   )
 )
 if /I "!errorRestoringFile!" == "true" (
   GOTO:FINIS
 )
GOTO:EOF



::
::
::
:replaceJavaHomeInFile
 if DEFINED VERBOSE (
   call :info "replaceJavaHomeInFile %1"
 )

 if NOT EXIST %1 (
   exit /b 0
 )

 :: TODO: this method could be clearer by calling establishJAVA_HOME_Values

 :: figure out which format of JAVA_HOME is in the file and then replace it
 call :findJavaHomeFormatToReplace %1 "!SHORT_JAVA_HOME!" || (
   call :findJavaHomeFormatToReplace %1 "!FULL_JAVA_HOME!" || (
     call :findJavaHomeFormatToReplace %1 "!ESC_SHORT_JAVA_HOME!" || (
       call :findJavaHomeFormatToReplace %1 "!ESC_FULL_JAVA_HOME!" || (
         :: if we couldn't find JAVA_HOME in setDomainEnv then we should report an appropriate error
         if /I "%~1" == "!DOMAIN_FILES[1]!" (
           call :updateError "Unable to find JAVA_HOME, !JAVA_HOME!, in any form in %1 and will not be able to rollout a Java update.  This is likely due to the NodeManager instance running with a different JAVA_HOME than the domain."
           call :recoverFromJavaHomeUpdateError
           exit /b 1
         ) else (
           call :warning "Could not find !JAVA_HOME! in any version in %1"
           (call )
           GOTO:EOF
         )
       )
     )
   )
 )

 set USE_NEW_JAVA_HOME=!NEW_JAVA_HOME!
 :: if we found an escaped version of JAVA_HOME in the file, we should repalce it with escaped string
 if /I "!FOUND_JAVA_HOME!" == "!ESC_FULL_JAVA_HOME!" (
   set USE_NEW_JAVA_HOME=!USE_NEW_JAVA_HOME:\=\\!
   set USE_NEW_JAVA_HOME=!USE_NEW_JAVA_HOME:^:=\:!
   call :info "altered USE_NEW_JAVA_HOME to be !USE_NEW_JAVA_HOME!"
 )
 if /I "!FOUND_JAVA_HOME!" == "!ESC_SHORT_JAVA_HOME!" (
   set USE_NEW_JAVA_HOME=!USE_NEW_JAVA_HOME:\=\\!
   set USE_NEW_JAVA_HOME=!USE_NEW_JAVA_HOME:^:=\:!
   call :info "altered USE_NEW_JAVA_HOME to be !USE_NEW_JAVA_HOME!"
 )

 :: now that we have FOUND_JAVA_HOME, attempt to replace it
 if DEFINED VERBOSE (
   call :info "We have found !FOUND_JAVA_HOME! in %~1"
   call :info "Comparing found java home !FOUND_JAVA_HOME! and use new java home !USE_NEW_JAVA_HOME!"
 )

 call :checkPathsUnique "!FOUND_JAVA_HOME!\" "!USE_NEW_JAVA_HOME!\" || (
   call :info "The file already contains !NEW_JAVA_HOME! so we are skipping the replacement of !FOUND_JAVA_HOME!"
   exit /b 0
 )
 call :info "The found java home, !FOUND_JAVA_HOME!, is not the same as the new java home, !NEW_JAVA_HOME!, so we will replace"

 set tmpfile=%~1.tmp
 set jfile=%~1
 if EXIST "!tmpfile!" (
   del /F "!tmpfile!"
 )

 set checkfile=!jfile:setDomainEnv.cmd=!
 if /I "!jfile!" == "!checkfile!" (
   call :myPlainReplace "!FOUND_JAVA_HOME!" "!USE_NEW_JAVA_HOME!" ||GOTO:FINIS
 ) else (
   call :myCMDReplace "!FOUND_JAVA_HOME!" "!USE_NEW_JAVA_HOME!" || GOTO:FINIS
 )

 :: NOTE: to debug it is helpful to keep a bk copy of the jfile
 :: and maybe even keep the tmpfile so when we auto revert
 :: the modified contents can be examined

 move !tmpfile! !jfile! || (
   call :updateError "could not move !tmpfile! to !jfile!"
   call :recoverFromJavaHomeUpdateError
   exit /b 1
 )


 :: validate that file does not contain %JAVA_HOME%
 set checkJAVA_HOME=!FOUND_JAVA_HOME:\=\\!
 set checkJAVA_HOME=!checkJAVA_HOME:^ =^^ !
 for /F "delims=" %%a IN ('findstr /r /N /I "!checkJAVA_HOME!" "!jfile!" ^|!WIN_FIND! /c ^":^"') DO (
   if /I NOT "%%a" == "0" (
     call :updateError "Could not update %1, it still contains %%a instances of !FOUND_JAVA_HOME! when it should have replaced with !NEW_JAVA_HOME!, see !tmpfile!"
     call :info "find !checkJAVA_HOME! in !jfile!"
     findstr /r /N /I "!checkJAVA_HOME!" "!jfile!"
     copy /Y !jfile! !tmpfile!
     call :info "Checking BACKUP_DIR to restore"
     call :recoverFromJavaHomeUpdateError
     GOTO:FINIS
   )
 )
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )



GOTO:EOF


::
:: this replacement block below does not deal well with .cmd lines, but does
:: deal well with xml chars and plain files
::
:myPlainReplace
 if DEFINED DEBUG (
   call :info "will replace %~1 with %~2 in plain txt file !jfile!"
 )
 for /f "skip=2 delims=] tokens=1,*" %%i in ('!WIN_FIND! /n /v "" !jfile!') do (
   set line=%%j
   if defined line (
     set line=!line:%~1=%~2!
     echo.!line!>>!tmpfile!
   ) ELSE echo.>>!tmpfile!
 )
GOTO:EOF


::
:: strange but this replacement block below does not deal well with the xml chars
:: but does deal well with .cmd lines
::
:myCMDReplace
 if DEFINED DEBUG (
   call :info "will replace %~1 with %~2 in cmd file !jfile!"
 )
 for /f "skip=2 tokens=1,* delims=]" %%i in ('!WIN_FIND! /n /v "" !jfile!') do (
   set line=%%j
   if defined line (
     call set "line=%%line:%~1=%~2%%"
     set line=!line:^&=^^^&!
     set line=!line:^<=^^^<!
     set line=!line:^>=^^^>!
     set line=!line:^|=^^^|!
     echo.!line!>>!tmpfile!
   ) ELSE echo.>>!tmpfile!
 )
GOTO:EOF


::
:: Search for the given string (JavaHome format) in the file
:: error when the string is not in the file
::
:findJavaHomeFormatToReplace
  if DEFINED DEBUG (
    call :info "findJavaHomeFormatToReplace %~1 %~2"
  )
  set incomingJAVA_HOME=%~2
  set incomingJAVA_HOME=!incomingJAVA_HOME:"=!
  set checkJAVA_HOME=!incomingJAVA_HOME:\=\\!
  set checkJAVA_HOME=!checkJAVA_HOME:^ =^^ !
  for /F "delims=" %%a IN ('findstr /r /N /I "!checkJAVA_HOME!" %1 ^|!WIN_FIND! /c ^":^"') DO (
    if %%a EQU 0 (
      exit /b 1
    )
  )
   :: if findstr doesn't find a match, it will set the errorlevel to 1, and this is
   :: okay because we want to error when the string is not in the file



  set FOUND_JAVA_HOME=%incomingJAVA_HOME%
  if DEFINED VERBOSE (
    call :info "Found JAVA_HOME to replace: !FOUND_JAVA_HOME! in %~1"
  )
GOTO:EOF


:: updateJavaHomeFiles
::
::
:updateJavaHomeFiles
 if DEFINED VERBOSE (
   call :info updateJavaHomeFiles
 )

 if DEFINED NEW_JAVA_HOME (
   :: go through our list of files and replace JAVA_HOME
   set /A "FILEPATH_START=!FILES_START! + 1"
   for /L %%i in (!FILEPATH_START!, 2, !FILES_END!) do (
     call :replaceJavaHomeInFile "!DOMAIN_FILES[%%i]!" || (
       call :error "Failure replacing JAVA_HOME in !DOMAIN_FILES[%%i]! with NEW_JAVA_HOME: !NEW_JAVA_HOME!"
       :: NOTE the replaceJavaHomeInFile method properly restores files after error
       GOTO:FINIS
     )
   )

   :: validate that domain/bin/setDomainEnv contains our new javahome
   set checkJAVA_HOME=%NEW_JAVA_HOME:\=\\%

   :: if JAVA_HOME is the same then should validate that the JAVA_HOME is from the file
   call :checkPathsUnique "!JAVA_HOME!\" "!NEW_JAVA_HOME!\" || (
     set checkJAVA_HOME=!JAVA_HOME:\=\\!
     call :info "The current JAVA_HOME, !JAVA_HOME!, is the same as the new JAVA_HOME !NEW_JAVA_HOME! so we are validating appropriate file using !checkJAVA_HOME!"
     exit /b 0
   )
   call :info "The java home, !JAVA_HOME!, is NOT the same as the new java home, !NEW_JAVA_HOME!, so we will validate the replacement using !checkJAVA_HOME!"

   :: do appropriate escaping to search for the string
   set checkJAVA_HOME=!checkJAVA_HOME:^ =^^ !




   if DEFINED VERBOSE (
     call :info "Verifying %NEW_JAVA_HOME% is in setDomainEnv.cmd with !checkJava_HOME!"
   )
   for /F "delims=" %%a IN ('findstr /R /N /I "!checkJAVA_HOME!" "%DOMAIN_DIR%\bin\setDomainEnv.cmd" ^|!WIN_FIND! /c ^":^"') DO (
     if "%%a" == "0" (
       call :updateError "Update of %DOMAIN_DIR%\bin\setDomainEnv.cmd did not insert %NEW_JAVA_HOME% to replace !JAVA_HOME!"
       call :info "find output for !checkJAVA_HOME! in %DOMAIN_DIR%\bin\setDomainEnv.cmd"
       findstr /r /N /I "!checkJAVA_HOME!" "%DOMAIN_DIR%\bin\setDomainEnv.cmd"
       copy "%DOMAIN_DIR%\bin\setDomainEnv.cmd" "%DOMAIN_DIR%\bin\setDomainEnv.cmd.tmp"
       call: recoverFromJavaHomeUpdateError
       GOTO:FINIS
     ) else (
       if DEFINED VERBOSE (
         call :info "replaced %JAVA_HOME% with %NEW_JAVA_HOME% in setDomainEnv.cmd"
       )
     )

   )
   :: REVIEW - I think we want to know anytime findst did not find a match - that is an error
   :: so we do not clear the error level here



   :: update NM.properties under OH
   call :replaceJavaHomeInFile "!MW_HOME!\oracle_common\common\nodemanager.properties" || GOTO:FINIS

 ) else (
   if EXIST "!MW_HOME!\%PATCH_BACKUP_DOM%\setDomainEnv.cmd" (
     call :restoreFilesFromPatchBackup || GOTO:FINIS
   )
 )
GOTO:EOF


::
::
:recoverFromJavaHomeUpdateError
 if not defined BACKUP_DIR (
   call :info "will now restore all of the files from %PATCH_BACKUP_OH%"
   call :jrestore
 ) else (
    :: rollback
    :: a better, more intelligent rollback would be to replace the original PATCHED dir
    call :info "Will restore MW_HOME, !MW_HOME! from !BACKUP_DIR!"
   if exist "!FULL_MW_HOME!.err\" (
       call :info "RD on !FULL_MW_HOME!.err"
     rd /S /Q "!FULL_MW_HOME!.err"
   )

   call :info "Move !MW_HOME! to !FULL_MW_HOME!.err"
   move "!MW_HOME!" "!FULL_MW_HOME!.err"
   if ERRORLEVEL 1 (
      call :updateError "Could not preserve the partial MW_HOME after failed pasteBinary.cmd.  Unable to move to !FULL_MW_HOME!.err"
      call :info "RD !MW_HOME!
      rd /S /Q "!MW_HOME!"
   )

   call :updateError "moving !BACKUP_DIR! to !FULL_MW_HOME!"
   move "!BACKUP_DIR!" "!FULL_MW_HOME!"
   if ERRORLEVEL 1 (
     call :updateError "Could not restore !FULL_MW_HOME! from !BACKUP_DIR! - unable to execute move !BACKUP_DIR! !FULL_MW_HOME!"
   )
 )

  call :info "will now restore all of the files from %PATCH_BACKUP_DOM%"
  call :restoreFilesFromPatchBackup
GOTO:EOF


::
:: check that the update did not persist any errors
:: without any error file we can safely assume update was successful
::
:validateUpdate
 if DEFINED VERBOSE (
   call :info "validateUpdate"
 )


 :: we know MW_HOME exists we are being exec from there
 :: so just need to check backup dir and error file?
 :: TODO: anything else we can do to validate
 ::   - validate specific files in OracleHome?
 ::   - if PATCHED is a dir then validate it is gone?
 ::   - if PATCHED is a file should we delete it?
 ::   - other?
 ::   - existance of error file?
 if EXIST "%ERRFILE%" (
   call :error "Update FAILURE.  Attempting to show details from %ERRFILE%"
   type "%ERRFILE%"
   GOTO:FINIS
 )

 call :cleanup

 :: TODO:
 :: BACKUP_DIR should always exist
 :: - mostly as dir
 :: but when REVERT_FROM_ERROR it may exist as archive file

 call :info "Update Successful"

GOTO:done




:: ------------------------------------------------------------
:: -------------------  all "functions" are below -------------
:: ------------------------------------------------------------


::
:: Usually we will be moving MW_HOME to BACKUP_DIR
:: only when the BACKUP exists as an archive and we are REVERT_FROM_FALIURE
:: then we will simply remove MW_HOME and move PATCHED into place
:: all other cases we will overwrite $BACKUP_DIR with MW_HOME
::
:backup_MW_HOME

 if DEFINED REVERT_FROM_ERROR (
   if DEFINED BACKUP_DIR (
     if not exist "!BACKUP_DIR!\" (
       set DELETE_MW_HOME=true
     )
   )
 )

 if DEFINED DELETE_MW_HOME (
   call :deleteMW_HOME_FOR_REVERT || GOTO:FINIS
 ) else (
   :: no matter what we are going to delete BACKUP_DIR if it exists
   if exist "!BACKUP_DIR!" (
     if DEFINED REVERT_FROM_ERROR (
       call :warning "this is unexpected, during a revert the specified BACKUP_DIR !BACKUP_DIR! already exists"
     )
     rd /S /Q !BACKUP_DIR!
     if ERRORLEVEL 1 (
       :: TODO: what can we do here?  move it out of the way?
       call :updateError "Could not remove !BACKUP_DIR!"
       GOTO:FINIS
     )
   )
   :: TODO: does this still happen after skipping this step for NEW_JAVA_HOME?
   :: no patched copy to move into place, so simply copy our existing dir
   if NOT DEFINED PATCHED (
     if DEFINED VERBOSE (
       call :info "Going to copy MW_HOME: !MW_HOME! to BACKUP_DIR: !BACKUP_DIR!"
     )
     xcopy "!MW_HOME!" "!BACKUP_DIR!" /s /e /q /y /i
     if ERRORLEVEL 1 (
       call :updateError "Could not create a backup copy of !MW_HOME! at !BACKUP_DIR!"
       GOTO:FINIS
     )
     if DEFINED VERBOSE (
       call :info "Copied !MW_HOME! to backup: !BACKUP_DIR!"
     )
   ) else (
     :: PATCHED copy will be moved into place, so simply move ours aside
     if DEFINED VERBOSE (
       call :info "Going to move MW_HOME: !MW_HOME! to BACKUP_DIR: !BACKUP_DIR!"
     )

     move "!MW_HOME!" "!BACKUP_DIR!"
     if ERRORLEVEL 1 (
       call :updateError "Could not move !MW_HOME! to backup: !BACKUP_DIR!"
       GOTO:FINIS
     )
     if DEFINED VERBOSE (
       call :info "Moved !MW_HOME! to backup: !BACKUP_DIR!"
     )
   )
 )

GOTO:EOF


::
::
::
::
:createJavaHomeFormats
:: create SHORT_JAVA_HOME, FULL_JAVA_HOME, ESC_SHORT_JAVA_HOME, and ESC_FULL_JAVA_HOME
   :: to replace all of the formats of JAVA_HOME
   for %%i in ("%JAVA_HOME%") do set SHORT_JAVA_HOME=%%~fsi

   call :resolveDir "%JAVA_HOME%" || GOTO:FINIS
   set FULL_JAVA_HOME=!expandDir!
   set ESC_SHORT_JAVA_HOME=!SHORT_JAVA_HOME:\=\\!
   set ESC_FULL_JAVA_HOME=!FULL_JAVA_HOME:\=\\!
   set ESC_SHORT_JAVA_HOME=!ESC_SHORT_JAVA_HOME:^:=\:!
   set ESC_FULL_JAVA_HOME=!ESC_FULL_JAVA_HOME:^:=\:!
   if DEFINED VERBOSE (
     call :info "for !JAVA_HOME!"
     call :info "created SHORT_JAVAHOME: !SHORT_JAVA_HOME!"
     call :info "craeted FULL_JAVA_HOME: !FULL_JAVA_HOME!"
     call :info "created ESC_SHORT_JAVA_HOME: !ESC_SHORT_JAVA_HOME!"
     call :info "created ESC_FULL_JAVA_HOME: !ESC_FULL_JAVA_HOME!"
   )
GOTO:EOF


::
::
::
::
:backupJavaHomeFiles
  if DEFINED VERBOSE (
    call :info "backupJavaHomeFiles"
  )
  ::TODO: code this like the findJavaHomeFormatToReplace where we stop looking once
  :: we have made a backup of the file
  :: figure out which format of JAVA_HOME is in the file and then replace it
  call :findJavaHomeFormatToPreserve "!SHORT_JAVA_HOME!"
  call :findJavaHomeFormatToPreserve "!FULL_JAVA_HOME!"
  call :findJavaHomeFormatToPreserve "!ESC_SHORT_JAVA_HOME!"
  call :findJavaHomeFormatToPreserve "!ESC_FULL_JAVA_HOME!"
GOTO:EOF


::
::
:findJavaHomeFormatToPreserve
 if DEFINED VERBOSE (
   call :info "findJavaHomeFormatToPreserve %%~1"
 )
 set incomingJAVA_HOME=%~1
 set incomingJAVA_HOME=!incomingJAVA_HOME:"=!
 set checkJAVA_HOME=!incomingJAVA_HOME:\\=\\\\!
 set checkJAVA_HOME=!checkJAVA_HOME:^ =^^ !
 if DEFINED VERBOSE (
    call :info "searching for !checkJAVA_HOME! under !MW_HOME!"
  )
 pushd ..
 ::TODO: protect?
 cd /d "!MW_HOME!"
 for /F "delims=" %%a IN ('findstr /s /m /l /i "!checkJAVA_HOME!" *') DO (
   for %%i in ("%%a") do (
     call :copyFileToPatchBackup "%%a" "%%~nxi" "%%~fi"
   )
 )
 ::TODO: if we modify this method so it should return error when checkJAVA_HOME is not found then
 :: returning the error code is appropriate
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )

 popd
GOTO:EOF


::
::
:copyFileToPatchBackup
  if DEFINED VERBOSE (
    call :info "copyFileToPatchBackup %%~3"
  )
  set file_path=%~1
  set file_path=!file_path:%~2=!

  ::if the file path contains %PATCH_BACKUP% then don't back it up again
  ::if not x!file_path:%PATCH_BACKUP%=!==x!file_path!
  echo !file_path! |findstr /L /i %PATCH_BACKUP% > nul && (
    if DEFINED VERBOSE (
      call :info "skipping the backup of %%~3"
    )
    GOTO:EOF
  )
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )

  if not exist "!FULL_MW_HOME!\%PATCH_BACKUP_OH%\!file_path!" (
    md "!FULL_MW_HOME!\%PATCH_BACKUP_OH%\!file_path!"
  )
  copy /Y %~3 "!FULL_MW_HOME!\%PATCH_BACKUP_OH%\!file_path!" > NUL
  if ERRORLEVEL 1 (
    call :updateError "Could not copy %~3 to !FULL_MW_HOME!\%PATCH_BACKUP_OH%\!file_path!"
    GOTO:FINIS
  )
  if DEFINED VERBOSE (
    call :info "Copied %~3 to !FULL_MW_HOME!\%PATCH_BACKUP_OH%\!file_path!"
  )
GOTO:EOF


::
::
::
::
:restoreJavaHomeFiles

  if DEFINED VERBOSE (
    call :info "restoreJavaHomeFiles"
  )
  ::TODO: code this like the findJavaHomeFormatToReplace  where we stop looking
  :: once we found the file

  :: figure out which format of JAVA_HOME is in the file and then replace it
  call :findJavaHomeFormatToRestore "!SHORT_JAVA_HOME!"
  call :findJavaHomeFormatToRestore "!FULL_JAVA_HOME!"
  call :findJavaHomeFormatToRestore "!ESC_SHORT_JAVA_HOME!"
  call :findJavaHomeFormatToRestore "!ESC_FULL_JAVA_HOME!"
  if /I "!errorRestoringFile!" == "true" (
    GOTO:FINIS
  )
GOTO:EOF


::
::
:findJavaHomeFormatToRestore
 if DEFINED VERBOSE (
   call :info "findJavaHomeFormatToRestore %%~1"
 )
 set incomingJAVA_HOME=%~1
 set incomingJAVA_HOME=!incomingJAVA_HOME:"=!
 set checkJAVA_HOME=!incomingJAVA_HOME:\\=\\\\!
 set checkJAVA_HOME=!checkJAVA_HOME:^ =^^ !
 pushd ..
 ::TODO: protect?
 cd /d "!MW_HOME!/%PATCH_BACKUP_OH%"
 for /F "delims=" %%a IN ('findstr /s /m /l /i "!checkJAVA_HOME!" *') DO (
   for %%i in ("%%a") do (
     call :restoreFileFromPatchBackup "%%a" "%%~nxi" "%%~fi"
   )
 )
 ::TODO: if we modify this method so it should return error when checkJAVA_HOME is not found then
  :: returning the error code is appropriate
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )

 popd
GOTO:EOF


::
::
:restoreFileFromPatchBackup
  set file_path=%~1
  set file_path=!file_path:%~2=!

  move /Y %~3 "!FULL_MW_HOME!\!file_path!" > NUL
  if ERRORLEVEL 1 (
    call :updateError "Could not copy %~3 to !FULL_MW_HOME!\!file_path!"
    set errorRestoringBackupFile=true
  )
  if DEFINED VERBOSE (
    call :info "Copied %~3 to !FULL_MW_HOME!\!file_path!"
  )
GOTO:EOF

::
:: during revert we do not need to keep MW_HOME we just created those
:: contents, so we can simply remove it to reduce disk usage and move back in
:: the original
::
:deleteMW_HOME_FOR_REVERT
if DEFINED VERBOSE (
     call :info "PATCHED is an archive file so we simply remove MW_HOME"
   )
   :: this is an archive file, so we simply remove OHome
   rd /S /Q "!MW_HOME!"
   if ERRORLEVEL 1 (
     set tmpMW_HOME="!FULL_MW_HOME!_tmp"
     call :warning "Error removing !MW_HOME! for revert, moving to %tmpMW_HOME%"
     move "!MW_HOME!" "%tmpMW_HOME%"
     if ERRORLEVEL 1 (
       call :updateError "Could not move !MW_HOME! to %tmpMW_HOME% for removal during revert"
       GOTO:FINIS
     )
     if DEFINED VERBOSE (
       call :info "Moved !MW_HOME! to %tmp_MW_HOME%
     )
   )
   if DEFINED VERBOSE (
     call :info "Successfully removed !MW_HOME! for revert"
   )
GOTO:EOF


::
:: need to be able to resolve MW_HOME to work with the full path rather than
:: windows abbreviated version.  The shortened path is maintained even when we
:: move the dir aside.  So operations after that point did not happen as intended
::
:resolve_MW_HOME
 if DEFINED VERBOSE (
   call :info "Before resolveDir MW_HOME is !MW_HOME!"
 )

 set FULL_MW_HOME=!MW_HOME!
 for %%i in ("!MW_HOME!") do set shortMW_HOME=%%~fsi
 if /I "%shortMW_HOME%" == "!MW_HOME!" (
   call :resolveDir "!MW_HOME!" || GOTO:FINIS
   set FULL_MW_HOME=!expandDir!
 )

 :: another option to getfullpath of a shortened dir name
 :: for /f "delims=" %%a in ('powershell -Command "[System.IO.Path]::GetFullPath( '!MW_HOME!' )"') do @set resolvedPath=%%a
 :: set MW_HOME=%resolvedPath%


 if DEFINED VERBOSE (
   call :info "After resolveDir FULL_MW_HOME is !FULL_MW_HOME!"
 )
GOTO:EOF


::
::
::
:backupJavaHomeDomainFiles
 if DEFINED VERBOSE (
   call :info "backupJavaHomeDomainFiles"
 )
 :: backup copies of the domain files
 if NOT EXIST "!FULL_MW_HOME!\%PATCH_BACKUP_DOM%" (
   md !FULL_MW_HOME!\%PATCH_BACKUP_DOM%
   if ERRORLEVEL 1 (
     call :error "Could not write !FULL_MW_HOME!\%PATCH_BACKUP_DOM% dir"
     GOTO:FINIS
   )
   if DEFINED VERBOSE (
     call :info "Created !FULL_MW_HOME!\%PATCH_BACKUP_DOM% dir"
   )
 )

 for /L %%i in (%FILES_START%,2,%FILES_END%) do (
   :: set n = %%i
   set /A loc=%%i + 1
   for %%l in (!loc!) do (
     if exist "!DOMAIN_FILES[%%l]!" (
       copy /v /y !DOMAIN_FILES[%%l]! !FULL_MW_HOME!\%PATCH_BACKUP_DOM%\!DOMAIN_FILES[%%i]!
       if ERRORLEVEL 1 (
         call :error "Could not copy !DOMAIN_FILES[%%l]! to !FULL_MW_HOME!\%PATCH_BACKUP_DOM%\!DOMAIN_FILES[%%i]!"
         GOTO:FINIS
       )
       if DEFINED VERBOSE (
         call :info "Copied !DOMAIN_FILES[%%l]! to !FULL_MW_HOME!\%PATCH_BACKUP_DOM%\!DOMAIN_FILES[%%i]!"
       )
     )
   )
 )
GOTO:EOF


::
::
::
:validateArguments
 if DEFINED VERBOSE (
   call :info "Checking: MW_HOME, PATCHED, BACKUP_DIR, NEW_JAVA_HOME for valid values"
   call :info "Checking: MW_HOME = !MW_HOME!"
   call :info "Checking: PATCHED = !PATCHED!"
   call :info "Checking: BACKUP_DIR = !BACKUP_DIR!"
   call :info "Checking: NEW_JAVA_HOME = !NEW_JAVA_HOME!"
   call :info "Checking: REVERT_FROM_ERROR = !REVERT_FROM_ERROR!"
 )

 if NOT DEFINED PATCHED if NOT DEFINED NEW_JAVA_HOME (
   if NOT DEFINED REVERT_FROM_ERROR (
     call :error "Must supply either PATCHED to update MW_HOME or NEW_JAVA_HOME to update JAVA_HOME, unless this is the REVERT case"
     GOTO:FINIS
   )
   REM the else for this should take PATCH_BACKUP=patching_backup (domain/patching_backup/domain), and move those files back to domain
 )

 ::TODO: can we resolve a relative path properly?
 if DEFINED PATCHED (
   for %%i in ("%PATCHED%") do set PATCHED=%%~fi
   if not exist "!PATCHED!" (
     call :error "PATCHED does not exist: !PATCHED!, it must be set to a valid archive or directory"
     GOTO:FINIS
   )
   if exist "!PATCHED!\" (
     if not exist "!PATCHED!\wlserver\server\bin\startNodeManager.cmd" (
       call :error "PATCHED is a directory but does not seem to be a valid OracleHome, it is missing wlserver\server\bin\startNodeManager.cmd"
       GOTO:FINIS
     )
   )


   ::we have a valid PATCHED value, so validate DOMAIN_DIR is not under MW_HOME
   for %%i in ("%MW_HOME%") do set SHORT_MW_HOME=%%~fsi
   for %%i in ("%DOMAIN_DIR%") do set SHORT_DOM_DIR=%%~fsi
   echo "!SHORT_DOM_DIR!"|findstr /i /c:"!SHORT_MW_HOME!" > nul && (
      call :error "The domain directory %DOMAIN_DIR% is a directory under the OracleHome directory, %MW_HOME%, and this is an invalid topology for ZDT Control"
      GOTO:FINIS
   )
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )

   for %%i in ("%PATCHED%") do set SHORT_PATCHED=%%~fsi
   echo "!SHORT_PATCHED!"|findstr /i /c:"!SHORT_MW_HOME!\" > nul && (
       call :error "The UpdateOracleHome value %PATCHED% is under the OracleHome directory, %MW_HOME%, and this should be moved to be accessible outside of MW_HOME"
       GOTO:FINIS
   )
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )

 )

 if DEFINED NEW_JAVA_HOME (
   if not exist "%NEW_JAVA_HOME%\" (
     call :error "NEW_JAVA_HOME should be a valid directory: %NEW_JAVA_HOME%"
     GOTO:FINIS
   )
   call :checkPathsUnique "!NEW_JAVA_HOME!\" "!MW_HOME!\" || (
      call :error "The RolloutJavaHome value !NEW_JAVA_HOME! is the same as the OracleHome directory, !MW_HOME!.  This is likley a typo and a valid Java directory should be given."
      GOTO:FINIS
   )
 )


 if NOT DEFINED TMP_UPDATE_SCRIPT (
   call :error "The %MW_HOME%\wlserver\server\bin\startNodeManager.cmd script supplies a value for TMP_UPDATE_SCRIPT, but this value is not defined now.  This is likely due to an invalid ZDT topology with a custom NodeManager.  Please make sure the custom NodeManager delegates to the WL_HOME\server\bin\startNodeManager.cmd script."
   GOTO:FINIS
 ) else (
   for %%i in ("%MW_HOME%") do set SHORT_MW_HOME=%%~fsi
   for %%i in ("%TMP_UPDATE_SCRIPT%") do set SHORT_TMP=%%~fsi
   echo "!SHORT_TMP!"|findstr /i /c:"!SHORT_MW_HOME!" > nul && (
     call :error "The TMP_UPDATE_SCRIPT value %TMP_UPDATE_SCRIPT% is under the OracleHome directory, %MW_HOME%, and this should be moved to be accessible outside of MW_HOME.  This is likely due to an improper override of this environment value when starting the NodeManager."
     GOTO:FINIS
   )
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )


 )


 if NOT DEFINED BACKUP_DIR (
   if DEFINED PATCHED (
     call :error "BACKUP_DIR must be defined"
     GOTO:FINIS
   )
 ) else (
   IF !BACKUP_DIR:~-1!==\ SET BACKUP_DIR=!BACKUP_DIR:~0,-1!
    :: TODO: can we properly resolve BACKUP_DIR if relative?
   for %%i in ("!BACKUP_DIR!") do set BACKUP_DIR=%%~fi

   call :checkPathsUnique "!BACKUP_DIR!\" "!MW_HOME!\" || (
     call :error "The BackupOracleHome value !BACKUP_DIR! is the same as the OracleHome directory, !MW_HOME!.  A unique BackupOracleHome dir should be given in order to move the MW_HOME aside for preservation."
     GOTO:FINIS
   )

   for %%i in ("!MW_HOME!") do set SHORT_MW_HOME=%%~fsi
   for %%i in ("!BACKUP_DIR!") do set SHORT_BACKUP_DIR=%%~fsi
   echo "!SHORT_BACKUP_DIR!"|findstr /i /c:"!SHORT_MW_HOME!" > nul && (
     call :error "The BackupOracleHome value !BACKUP_DIR! is under the OracleHome directory, !MW_HOME!, and this should be moved to be stored outside of MW_HOME"
     GOTO:FINIS
   )
   :: if findstr doesn't find a match, it will set the errorlevel to 1, that will make the validateArguments function look like it failed
   :: clear the error level here
   (call )
   for %%i in ("!BACKUP_DIR!") do set BACKUP_PARENT=%%~dpi
   if DEFINED BACKUP_PARENT if NOT EXIST "!BACKUP_PARENT!" (
     call :error "Parent directory of BackupOracleHome, !BACKUP_DIR!, must exist.  Parent directory: !BACKUP_PARENT! not found."
     GOTO:FINIS
   )
 )


 if DEFINED VERBOSE (
   call :info "Verified MW_HOME: !MW_HOME!, PATCHED: !PATCHED!, BACKUP_DIR: !BACKUP_DIR!, and NEW_JAVA_HOME: %NEW_JAVA_HOME% values"
 )
GOTO:EOF


::
::
::
:establishINVLoc
 :: ORA_INV = the place where the dir is now
 :: ORA_INV_TMP = the place where we can move it

 for /F "delims=" %%a IN ('REG QUERY HKLM\Software\Oracle') DO (
   echo %%a | !WIN_FIND! "inst_loc">NUL && (
     if DEFINED VERBOSE (
       call :info "found inst.loc in %%a"
     )
   set INST_LOC=%%a
   )
 )

 for /F "tokens=2*" %%i IN ('echo %INST_LOC%') DO (
   if DEFINED VERBOSE (
     echo "ora_inv is %%j and tmp_ora_inv is %%j_tmp"
   )
   set ORA_INV=%%j
   set ORA_INV_TMP=%%j_tmp
 )


 if not DEFINED ORA_INV (
   call :error "Could not find Oracle registry from HKLM\Software\Oracle"
   GOTO:FINIS
 )

 if exist "!ORA_INV_TMP!" (
   dir !ORA_INV_TMP!
   call :error "%ORA_INV_TMP% already exists, will not be able to temporarily move %ORA_INV% to that location"
   GOTO:FINIS
  )
GOTO:EOF



::
::
::
:resolveFileName
 set rDir=%1
 :: set rfilename=%!2
 if DEFINED DEBUG (
  echo checking file name for %rDir% with %~2
 )

 for /F "tokens=5*" %%a IN ('dir /x !rDir!\..\ ^| !WIN_FIND! /I "%~2"') DO (
  if /I "%%a" == "%~2" (
    set filenameRes=%%b
  )
 )
GOTO:EOF









:innerResolveDir
:: start with rdir as the passed in value
set rDir=%1
if DEFINED DEBUG (
  echo rdir is %rDir%
)
:: re initialize stop to an unset value
set stop=
:: strip the path into three parts dir, path, filename
for %%I in (%rDir%) DO (
 set filename=%%~nxI
 set filepath=%%~pI
 set dir=%%~dI
)

if DEFINED DEBUG (
 echo filename is %filename%
)

:: todo: can we remove this?
:: reinitializefilenameRes before calling resolve
set filenameRes=

:: search for the filename or its short form in the dir listing
call :resolveFileName !rdir! "!filename!"


:: combined now = dir\path
set combined=%dir%%filepath%
if DEFINED DEBUG (
 echo "combined: %combined%"
)

if "%filenameRes%" == "" (
 set filenameRes=%filename%
)
if DEFINED DEBUG (
 echo "now have filenameRes %filenameRes%"
 echo "filename: %filename%"
 echo "Dir: %dir%"
)

IF %combined:~-1%==\ SET combined=%combined:~0,-1%

if /I "%dir%" == "%combined%" (
 if DEFINED DEBUG (
   echo "dir is == combined with %dir% and %combined% or !dir! and !combined!"
 )
 set stop=yes
)
if "!filename!" == "" (
 if DEFINED DEBUG (
   echo "filename is empty"
 )
 set stop=yes
)

set tmp_expandDir=\%filenameRes%!tmp_expandDir!

if /I "%stop%" == "yes" (
 if DEFINED DEBUG (
   echo "combine dir with expandDir from !filename! and set !tmp_expandDir! or %tmp_expandDir% or !expandDir! or %expandDir%"
  )
 set expandDir=%dir%!tmp_expandDir!
) else (
 if DEFINED DEBUG (
   echo "recurse with !combined!"
 )
 call :innerResolveDir "!combined!"
)
GOTO:EOF

:resolveDir
 set tmp_expandDir=
 set expandDir=
 call :innerResolveDir %1
GOTO:EOF


::
:checkPathsUnique
 for %%A in ("%~1") DO for %%B in ("%~2") DO if /I "%%~fsA" == "%%~fsB" (
   exit /b 1
 ) else (
   exit /b 0
 )
GOTO:EOF

::
::
::
:checkPrereq
 if DEFINED VERBOSE (
   call :info "Checking prerequisites"
 )

 call :validateArguments || GOTO:FINIS

 :: any other checks we can make here?

 call :info "checkreq Successful"
GOTO:done

::
::
::
:fileClean
 if exist %1 (
   set mytime=%time::=.%
   echo move %1 to "%~1.!mytime!"
   move %1 "%~1.!mytime!"
   ::del /F %1
   if ERRORLEVEL 1 (
     call :warning "Unable to clean up file %1"
   )
   if exist %1 (
     call :error "File %1 still exists after attempting to move it"
   )
 )
GOTO:EOF

::
::
::
:cleanup
 call :fileClean "%ERRFILE%"
 call :fileClean "%TMP_UPDATE_SCRIPT%"
 call :fileClean "%VERBOSE_OUTFILE%"
 call :fileClean "%PASTE_BIN_OUT%"
 call :fileClean "%DETACH_HOME_OUT%"
 call :fileClean "%ATTACH_HOME_OUT%"

 if DEFINED VERBOSE (
   call :info "Files cleaned"
 )
GOTO:EOF




::
:: print the error but also preserve the message for the ERRFILE
:: so that the errors can be shown during the validation/assertion phase
::
:updateError
 call :getmsg %1
 echo !msg!
 echo !msg! >> %ERRFILE%
GOTO:EOF


::
:: format a message to be used in string format
::
:getmsg
    set msgType=%1
    shift
    set msg="<%date% %time% %TZ_STR%> <!msgType!> <UpdateOracleHome> <%~1>"
GOTO:EOF

::
:: format a message and echo that message
::
:msg
    set msgType=%1
    shift
    set msg="<%date% %time% %TZ_STR%> <!msgType!> <UpdateOracleHome> <%~1>"
    echo !msg!
GOTO:EOF

::
:: format an INFO message and echo that message
::
:info
   call :msg INFO %1
GOTO:EOF

::
:: format a WARNING message and echo that message
::
:warning
echo **********  WARNING *********
:: TODO: and make it appear in log after validation
call :msg WARNING %1
echo **********  WARNING *********
GOTO:EOF

:error
   call :msg ERROR %1
GOTO:EOF


:debug
if NOT DEFINED DEBUG GOTO:EOF
echo **********  DEBUG  **********
echo %1 %2 %3 %4 %5
echo **********  DEBUG  **********
GOTO:EOF

:FINIS
ENDLOCAL
exit /b 1

:done
ENDLOCAL
