//////////////////////////////////////////////////////////////////////////////
// 
//                    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.DecimalNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.TextNode;

import java.math.BigDecimal;
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)
    {
    try
      {
      return Optional.of( DecimalNode.valueOf( new BigDecimal( content)));
      }
    catch( Exception e)
      {
      return Optional.empty();
      }
    }

  /**
   * 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_;
  }

@@ -349,24 +349,83 @@
 d.JsonNode;%0A
+import com.fasterxml.jackson.databind.node.BigIntegerNode;%0A
 import com.f
@@ -600,24 +600,53 @@
 BigDecimal;%0A
+import java.math.BigInteger;%0A
 import java.
@@ -2448,92 +2448,313 @@
     
-try%0A      %7B%0A      return Optional.of( DecimalNode.valueOf( new BigDecimal( content))
+JsonNode jsonNode;%0A%0A    try%0A      %7B%0A      BigDecimal number = new BigDecimal( content);%0A      BigInteger integer;%0A      try%0A        %7B%0A        integer =%0A          Optional.of( number)%0A          .filter( decimal -%3E decimal.scale() == 0)%0A          .map( BigDecimal::toBigIntegerExact)%0A          .orElse( null
 );%0A 
@@ -2754,26 +2754,30 @@
 ull);%0A      
-%7D%0A
+  %7D%0A  
     catch( E
@@ -2794,24 +2794,26 @@
 )%0A      
+  
 %7B%0A      
 return O
@@ -2808,40 +2808,311 @@
     
-return Optional.empty();%0A      %7D
+  integer = null;%0A        %7D%0A%0A      jsonNode =%0A        Optional.ofNullable( integer)%0A        .map( i -%3E (JsonNode) BigIntegerNode.valueOf(i))%0A        .orElse( DecimalNode.valueOf( number));%0A      %7D%0A    catch( Exception e)%0A      %7B%0A      jsonNode = null;%0A      %7D%0A%0A    return Optional.ofNullable( jsonNode);
 %0A   

Convert an integer string to a BigIntegerNode