//////////////////////////////////////////////////////////////////////////////
// 
//                    Copyright 2022, Cornutum Project
//                             www.cornutum.org
//
//////////////////////////////////////////////////////////////////////////////

package org.cornutum.tcases.openapi.test;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.BigIntegerNode;
import com.fasterxml.jackson.databind.node.DecimalNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.TextNode;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static java.util.stream.Collectors.toList;

/**
 * Base class for response content decoders.
 */
public abstract class AbstractDecoder
  {
  /**
   * Creates a new AbstractDecoder instance.
   */
  protected AbstractDecoder()
    {
    this( false);
    }
  
  /**
   * Creates a new AbstractDecoder instance.
   */
  protected AbstractDecoder( boolean explode)
    {
    explode_ = explode;
    }

  /**
   * Returns true if this decoder expects objects to be encoded in exploded form.
   */
  public boolean isExplode()
    {
    return explode_;
    }

  /**
   * Returns the possible JSON representations of the given content.
   */
  public List<JsonNode> decode( String content)
    {
    return
      Arrays.asList( decodeObject( content), decodeArray( content), decodeValue( content))
      .stream()
      .flatMap( jsons -> jsons.stream())
      .collect( toList());
    }

  /**
   * Returns the possible JSON object representations of the given content.
   */
  public abstract List<JsonNode> decodeObject( String content);

  /**
   * Returns the possible JSON array representations of the given content.
   */
  public abstract List<JsonNode> decodeArray( String content);

  /**
   * Returns the possible JSON value representations of the given content.
   */
  protected List<JsonNode> decodeValue( String content)
    {
    
    return
      Arrays.asList( decodeNumber( content), decodeString( content), decodeNull( content))
      .stream()
      .filter( Optional::isPresent)
      .map( Optional::get)
      .collect( toList());
    }

  /**
   * Returns the JSON number representation of the given content.
   */
  public Optional<JsonNode> decodeNumber( String content)
    {
    JsonNode jsonNode;

    try
      {
      BigDecimal number = new BigDecimal( content);
      BigInteger integer;
      try
        {
        integer =
          Optional.of( number)
          .filter( decimal -> decimal.scale() == 0)
          .map( BigDecimal::toBigIntegerExact)
          .orElse( null);
        }
      catch( Exception e)
        {
        integer = null;
        }

      jsonNode =
        Optional.ofNullable( integer)
        .map( i -> (JsonNode) BigIntegerNode.valueOf(i))
        .orElse( DecimalNode.valueOf( number));
      }
    catch( Exception e)
      {
      jsonNode = null;
      }

    return Optional.ofNullable( jsonNode);
    }

  /**
   * Returns the JSON string representation of the given content.
   */
  public Optional<JsonNode> decodeString( String content)
    {
    return Optional.ofNullable( TextNode.valueOf( content));
    }

  /**
   * Returns the JSON null representation of the given content.
   */
  public Optional<JsonNode> decodeNull( String content)
    {
    return
      Optional.of( Objects.toString( content, ""))
      .filter( String::isEmpty)
      .map( empty -> NullNode.instance);
    }

  private final boolean explode_;
  }

@@ -408,24 +408,80 @@
 ntegerNode;%0A
+import com.fasterxml.jackson.databind.node.BooleanNode;%0A
 import com.f
@@ -520,24 +520,24 @@
 ecimalNode;%0A
-
 import com.f
@@ -2138,13 +2138,8 @@
   %7B%0A
-    %0A
     
@@ -2185,24 +2185,49 @@
 r( content),
+ decodeBoolean( content),
  decodeStrin
@@ -3183,32 +3183,367 @@
 onNode);%0A    %7D%0A%0A
+  /**%0A   * Returns the JSON boolean representation of the given content.%0A   */%0A  public Optional%3CJsonNode%3E decodeBoolean( String content)%0A    %7B%0A    return%0A      Optional.ofNullable( content)%0A      .filter( text -%3E %22true%22.equals( text) %7C%7C %22false%22.equals( text))%0A      .map( text -%3E BooleanNode.valueOf( Boolean.valueOf( text)));%0A    %7D%0A%0A
   /**%0A   * Retur
@@ -3670,32 +3670,38 @@
     %7B%0A    return
+%0A     
  Optional.ofNull
@@ -3705,16 +3705,45 @@
 ullable(
+ content)%0A      .map( text -%3E
  TextNod
@@ -3753,22 +3753,19 @@
 alueOf( 
-con
 te
-n
+x
 t));%0A   

Add decodeBoolean()