/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* IBM UrbanCode Deploy
* IBM UrbanCode Release
* IBM AnthillPro
* (c) Copyright IBM Corporation 2002, 2017. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*/
package com.urbancode.air.plugin.websphereliberty;

import groovy.io.FileType
import java.text.SimpleDateFormat
import java.util.regex.Pattern

public abstract class AbstractWebSphereLibertyFileSystemHelper {
   def wlpHomeFile
   def wlpBinFile
   def wlpUserDirFile

   protected AbstractWebSphereLibertyFileSystemHelper(String wlpHome, String wlpUserDir=null) {
       wlpHomeFile = new File(wlpHome);
       if (!wlpHomeFile.isDirectory()) {
           throw new RuntimeException("WebSphere Liberty Home Directory does not exist or is not a file! " + wlpHome);
       }

       wlpBinFile = new File(wlpHomeFile, "bin");
       if (!wlpBinFile.isDirectory()) {
           wlpBinFile = new File(wlpHomeFile, "wlp/bin");
           if (wlpBinFile.isDirectory()) {
               wlpHomeFile = new File(wlpHomeFile, "wlp");
           }
           else { 
               throw new RuntimeException("WebSphere Liberty bin directory does not exist at ${wlpHome}/bin or ${wlpHome}/wlp/bin!");
           }
       }

       if (wlpUserDir?.trim()) {
           wlpUserDirFile = new File(wlpUserDir?.trim());
       }
       else if (System.getenv("WLP_USER_DIR")) {
           wlpUserDirFile = new File(System.getenv("WLP_USER_DIR"));
       }
       else {
           wlpUserDirFile = new File(wlpHomeFile, "usr");
       }
       if (!wlpUserDirFile.isDirectory()) {
           throw new RuntimeException("WebSphere Liberty User Directory does not exist or is not a file! " + wlpUserDirFile.absolutePath);
       }
   }

   // The parameter 'notUsed' is only used to avoid constructor signature collision
   protected AbstractWebSphereLibertyFileSystemHelper(String wlpHome, boolean notUsed) {
       wlpHomeFile = new File(wlpHome);
       if (!wlpHomeFile.isDirectory()) {
           throw new RuntimeException("WebSphere Liberty Home Directory does not exist or is not a file! " + wlpHome);
       }
   }

   protected File getSecurityUtilityExecutable(def isWindows) {
       def secUtilExecutableName = "securityUtility" + (isWindows ? ".bat":"");
       def secUtilExecutable = new File(wlpBinFile, secUtilExecutableName);
       return secUtilExecutable
   }

   protected File getCollectiveExecutable(def isWindows) {
       def collectiveExecutableName = "collective" + (isWindows ? ".bat":"");
       def collectiveExecutable = new File(wlpBinFile, collectiveExecutableName);
       return collectiveExecutable
   }

   protected File getServerExecutable(def isWindows) {
       def serverExecutableName = "server" + (isWindows ? ".bat":"");
       def serverExecutable = new File(wlpBinFile, serverExecutableName);
       return serverExecutable
   }

   // pluginUtility added to liberty in version 16
   protected File getPluginUtilityExecutable(def isWindows) {
       def pluginUtilityExecutableName = "pluginUtility" + (isWindows ? ".bat":"");
       def pluginUtilityExecutable = new File(wlpBinFile, pluginUtilityExecutableName);
       
       if ( !(pluginUtilityExecutable.isFile()) ) {
           throw new RuntimeException("\n\n\"pluginUtility\" not found.  For merging plugin config files, WebSphere Liberty v.16.0.0.3 or newer is required.\n\n");
       }
       return pluginUtilityExecutable
   }

   protected File getServerDirectory(String serverName) {
       def serversDir = new File(wlpUserDirFile, "servers");
       def serverDir = new File(serversDir, serverName);
       if (!serverDir.isDirectory()) {
           throw new RuntimeException("Expected Server Directory does not exist or is not a file! " + serverDir.absolutePath);
       }
       return serverDir;
   }

   protected String[] getServerNames(String searchName) {
       def pattern = ~/^[a-zA-Z0-9].*/  /* Match all filenames starting with alpha-numeric chars */
       def serverNames = [];
       def serversDir = new File(wlpUserDirFile, "servers");

       if (!serversDir.isDirectory()) {
           throw new RuntimeException("Expected Servers Directory does not exist or is not a file! " + serversDir.absolutePath);
       }
       if (searchName != "ALL") {
           pattern = Pattern.compile(searchName);
       }
       serversDir.eachFileMatch(FileType.ANY, pattern) {
           // In case user specified pattern doesn't already, we need to exclude any server names (filenames) 
           // that don't begin with alphanumeric characters.
           if (it.name =~ /^[a-zA-Z0-9].*/ ) {
               serverNames << it.name;
           }
       }
       return serverNames;
   }

   protected int runServerCommand(String serverName, def isWindows, String command, String message) {
       return runServerCommand(serverName, isWindows, command, message, null);
   }

   protected int runServerCommand(String serverName, def isWindows, String command, String message, Closure clos) {
       def serverExecutable = getServerExecutable(isWindows);
       def cmdArgs = [serverExecutable.absolutePath, command, serverName];

       if (isWindows) {
           ch.addEnvironmentVariable("EXIT_ALL", "1");
       }

       ch.addEnvironmentVariable("WLP_USER_DIR", wlpUserDirFile.absolutePath);
       return ch.runCommand(message, cmdArgs, clos);
   }

   protected int mergePluginConfigCommand(String options, def isWindows, String command, String message) {
       return mergePluginConfigCommand(options, isWindows, command, message, null);
   }

   protected int mergePluginConfigCommand(String options, def isWindows, String command, String message, Closure clos) {
       def pluignUtilityExecutable = getPluginUtilityExecutable(isWindows);
       def cmdArgs = [pluignUtilityExecutable.absolutePath, command];

       options = options.replace(" --", "|--");
       cmdArgs.addAll(options.tokenize("|"));

       if (isWindows) {
           ch.addEnvironmentVariable("EXIT_ALL", "1");
       }

       ch.addEnvironmentVariable("WLP_USER_DIR", wlpUserDirFile.absolutePath);
       return ch.runCommand(message, cmdArgs, clos);
   }

    protected void runCollectiveCommand(String serverName, def isWindows, String command, String options, String message) {
       runCollectiveCommand(serverName, isWindows, command, options, message, null);
   }

   protected void runCollectiveCommand(String serverName, def isWindows, String command, String options, String message, Closure clos) {
       def collectiveExecutable = getCollectiveExecutable(isWindows);
       def cmdArgs = [collectiveExecutable.absolutePath, command, serverName];
       // Can't tokenize on space because we need to handle options such as filenames that could contain spaces as part
       // of their value.  This assumes that all options for the collective command begin with "--".
       options = options.trim();  //Remove any trailing spaces
       options = options.replace(" --", ",--");
       cmdArgs.addAll(options.tokenize(","));

       if (isWindows) {
           ch.addEnvironmentVariable("EXIT_ALL", "1");
       }

       ch.addEnvironmentVariable("WLP_USER_DIR", wlpUserDirFile.absolutePath);
       ch.runCommand(message, cmdArgs, clos);
   }

   // Return String with current date and time
   protected String getDateTime() {
       def today = new Date()
       def formattedDateTime = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss.SSS").format(today)
   }

   // Use the securityUtility tool to encode/encrypt the specified string
   // May want to add support for specifying encoding_type so we can do AES encryption as well as default XOR encoding
   protected String encode(String value, def isWindows) {
       def securityUtilExecutable = getSecurityUtilityExecutable(isWindows);
       def cmdArgs = [securityUtilExecutable.absolutePath, "encode", value];

       if (isWindows) {
           ch.addEnvironmentVariable("EXIT_ALL", "1");
       }

       ByteArrayOutputStream os = new ByteArrayOutputStream();
       ByteArrayOutputStream es = new ByteArrayOutputStream();
       ch.runCommand(null, cmdArgs) { proc ->
           proc.waitForProcessOutput(os, es);
       }
       return new String(os.toByteArray());
   }
}
