/*
** Module   : WebSessionSettings.java
** Abstract : Configuration for web service tests. 
**
** Copyright (c) 2021-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 CA  20210827 Created initial version.
** 002 CA  20210906 Allow override via command line arguments, for: web endpoint, variable initial values and 
**                  oauth1 parameters. 
** 003 CA  20220118 Added Basic authorization.
** 004 TJD 20220809 Implemented logging.
** 005 CA  20240306 Added flag to omit the response body in the results (as for performance testing, the body
**                  may be huge and also not needed).
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.goldencode.harness;

import com.goldencode.util.*;

import java.util.*;

/**
 * Stores configuration for a web test..
 */
public class WebSessionSettings
extends SessionSettings
{
   /** The override endpoint. */
   public static String overrideEndpoint = null;
   
   /** The override 'omitResponseBody' flag. */
   public static Boolean overrideOmitResponseBody = null;
   
   /** The endpoint where the web tests is executed. */
   public String endpoint;

   /** When set, response body is not emitted in the results. */
   public boolean omitResponseBody = false;
   
   /** Flag indicating if SSL self-signed certificates are accepted. */
   public boolean sslAcceptSelfSigned = true;
   
   /** Flag indicating if all SSL certificates are accepted. */
   public boolean sslAcceptAll = true;
   
   /** The trust store file name. */
   public String sslTrustStoreFile = null;
   
   /** The trust store password . */
   public String sslTrustStorePassword = null;
   
   /** Parameters for authorization, per authorization type. */
   public Map<String, Map<String, String>> auth = null;
    
   /**
    * Default constructor.
    */
   public WebSessionSettings()
   {
   }
   
   /**
    * Copy constructor.
    *
    * @param    original
    *           Instance from which to copy.
    */
   public WebSessionSettings(WebSessionSettings original)
   {
      super(original);
      
      this.endpoint              = original.endpoint;
      this.omitResponseBody      = original.omitResponseBody;
      this.sslAcceptAll          = original.sslAcceptAll;
      this.sslAcceptSelfSigned   = original.sslAcceptSelfSigned;
      this.sslTrustStoreFile     = original.sslTrustStoreFile;
      this.sslTrustStorePassword = original.sslTrustStorePassword;
      
      this.auth = original.auth == null ? null : new HashMap<>();
      if (original.auth != null)
      {
         original.auth.forEach((k, v) -> this.auth.put(k, new HashMap<>(v)));
      }
   }
   
   /**
    * Add an web authorization parameter.
    * 
    * @param    authType
    *           The authorization type (only "oauth1" and "basic" is supported at this time).
    * @param    key
    *           The parameter name.
    * @param    val
    *           The parameter value.
    */
   public void addAuthorizationParameter(String authType, String key, String val)
   {
      if (key == null || key.isEmpty())
      {
         throw new IllegalArgumentException("Parameter name is required for " + authType + "!");
      }
      
      if (val == null || val.isEmpty())
      {
         // don't keep empty/null values
         LogHelper.info("Authorization " + authType + " - parameter " + key + 
                            " is ignored, no value specified.");
         return;
      }
      
      if (auth == null)
      {
         auth = new HashMap<>();
      }
      
      authType = authType.toLowerCase();
      
      Map<String, String> params = auth.computeIfAbsent(authType, (k) -> new HashMap<>());
      params.put(key, val);
   }
   
   /**
    * Get the value of the authorization parameter.
    * 
    * @param    authType
    *           The authorization type (only "oauth1" and "basic" is supported at this time).
    * @param    key
    *           The parameter name.
    *           
    * @return   The parameter's value or <code>null</code> if it was not configured.
    */
   public String getAuthorizationParameter(String authType, String key)
   {
      return auth == null ? null : auth.getOrDefault(authType.toLowerCase(), Collections.emptyMap()).get(key);
   }
   
   /**
    * Get text representation of the configurations for this session - each pair represents the configuration
    * name and its value.
    * 
    * @return   See above.
    */
   @Override
   public String[][] getConfigs()
   {
      List<String[]> cfgs = new ArrayList<>();
      cfgs.add(new String[] { "Endpoint", endpoint });
      if (auth != null)
      {
         for (String authType : auth.keySet())
         {
            Map<String, String> params = auth.get(authType);
            
            cfgs.add(new String[] { "AUTHORIZATION: " + authType, "" });

            for (String key : new TreeSet<>(params.keySet()))
            {
               String val = params.get(key);

               cfgs.add(new String[] { key, val });
            }
         }
      }
      
      cfgs.add(new String[] { "SSL SETTINGS", "" });
      cfgs.add(new String[] { "Accept all certificates", Boolean.toString(sslAcceptAll) });
      cfgs.add(new String[] { "Accelt self-signed certificates", Boolean.toString(sslAcceptSelfSigned) });
      cfgs.add(new String[] { "Truststore file", sslTrustStoreFile == null ? "" : sslTrustStoreFile });
      cfgs.add(new String[] { "Truststore password", sslTrustStorePassword == null ? "" : sslTrustStorePassword });
      
      String[][] res = new String[cfgs.size()][];
      
      return cfgs.toArray(res);
   }
   
   /**
    * Duplicate this configuration.
    * 
    * @return   See above.
    */
   @Override
   public SessionSettings duplicate()
   {
      return new WebSessionSettings(this);
   }
}
