/***********************************************************************************
 * Chaga string arithmetic library                                                 *
 * Copyright (C) 2026 Robert James Bruce                                           *
 *                                                                                 *
 * This file is part of the Chaga string arithmetic library.                       *
 *                                                                                 *
 * The Chaga string arithmetic library is free software: you can redistribute it   * 
 * and/or modify it under the terms of the GNU General Public License as published *
 * by the Free Software Foundation, either version 3 of the License, or (at your   *
 * option) any later version.                                                      *
 *                                                                                 *
 * The Chaga string arithmetic library 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 General Public *
 * License for more details.                                                       *
 *                                                                                 *
 * You should have received a copy of the GNU General Public License               *
 * along with the Chaga compiler. If not, see <https://www.gnu.org/licenses/>.     *
 ***********************************************************************************/
#include "include/libchaga-diagnostic_tools.h"

void display_packed_string_integer_structure (psint *packed_string_integer)
{
  size_t i;
  psnc *packed_string_number_component;

  if (packed_string_integer != NULL)
  {
    printf ("\nNUMBER BLOCK:\n");
    printf ("address:               %p\n", packed_string_integer);
    printf ("sign:                  ");
    switch (packed_string_integer->sign)
    {
      case negative:
        printf ("negative");
      break;
      case positive:
        printf ("positive");
      break;
      case zero:
        printf ("zero");
      break;
      case undefined:
        printf ("undefined");
      break;
      default:
        printf ("ERROR: unknown sign\n");
      break;
    }
    putchar ('\n');
    printf ("status flag:           ");
    switch (packed_string_integer->status_flag)
    {
      case NONE:
        printf ("none");
      break;
      case INTERNAL_ERROR:
        printf ("internal error");
      break; 
      case DIVIDE_BY_ZERO:
        printf ("divide by zero");
      break; 
      case REPEATING_NONTERMINATING:
        printf ("repeating nonterminating");
      break; 
      case IMAGINARY:
        printf ("imaginary");
      break; 
      default:
        printf ("ERROR: UNDEFINED STATUS FLAG VALUE!\n");
      break;
    }
    printf ("\n");
    packed_string_number_component = packed_string_integer->left_of_decimal;
    while (packed_string_number_component != NULL)
    {
      printf ("highest digit position:  %lld\n", packed_string_number_component->highest_digit_position);
      printf ("highest nibble position: ");
      switch (packed_string_number_component->highest_nibble_position)
      {
        case lo:
          printf ("lo\n");
        break;
        case hi:
          printf ("hi\n");
        break;
        default:
          printf ("ERROR: unknown value\n");
        break;
      }
      printf ("PACKED NUMBER BLOCK:\n");
      for (i = 0; i < MAX_PACKED_NUMBER_BLOCK_SIZE; i++)
      {
        printf ("%p, value: %02x\n", &packed_string_number_component->packed_number_block[i], packed_string_number_component->packed_number_block[i]);
      }
      printf ("first_number_block:    %p\n", packed_string_number_component->first_number_block);
      printf ("last_number_block:     %p\n", packed_string_number_component->last_number_block);
      printf ("previous number block: %p\n", packed_string_number_component->previous_number_block);
      printf ("next number block:     %p\n", packed_string_number_component->next_number_block);
      packed_string_number_component = packed_string_number_component->next_number_block;
      putchar ('\n');
    }
  }
}




void display_packed_string_float_structure (psflt *packed_string_float)
{
  psnc *left_of_decimal, *right_of_decimal;
  size_t i;

  left_of_decimal  = NULL;
  right_of_decimal = NULL;
  if (packed_string_float != NULL)
  {
    left_of_decimal  = packed_string_float->left_of_decimal;
    right_of_decimal = packed_string_float->right_of_decimal;
    printf ("left_of_decimal:       %p\n", left_of_decimal);
    printf ("right_of_decimal:      %p\n", right_of_decimal);
    printf ("sign:                  ");
    switch (packed_string_float->sign)
    {
      case negative:
        printf ("negative");
      break;
      case positive:
        printf ("positive");
      break;
      case zero:
        printf ("zero");
      break;
      case undefined:
        printf ("undefined");
      break;
      default:
        printf ("ERROR: unknown sign\n");
      break;
    }
    putchar ('\n');
    printf ("status flag:           ");
    switch (packed_string_float->status_flag)
    {
      case NONE:
        printf ("none");
      break;
      case INTERNAL_ERROR:
        printf ("internal error");
      break; 
      case DIVIDE_BY_ZERO:
        printf ("divide by zero");
      break; 
      case REPEATING_NONTERMINATING:
        printf ("repeating nonterminating");
      break; 
      case IMAGINARY:
        printf ("imaginary");
      break; 
      default:
        printf ("ERROR: UNDEFINED STATUS FLAG VALUE!\n");
      break;
    }
    printf ("\n");
  }
  if (left_of_decimal != NULL)
  {
    printf ("LEFT OF DECIMAL:\n");
  }
  while (left_of_decimal != NULL)
  {
    printf ("\nNUMBER BLOCK:\n");
    printf ("address:                %p\n", left_of_decimal);
    printf ("highest digit position: %lld\n", left_of_decimal->highest_digit_position);
    printf ("highest nibble position: ");
    switch (left_of_decimal->highest_nibble_position)
    {
      case lo:
        printf ("lo\n");
      break;
      case hi:
        printf ("hi\n");
      break;
      default:
        printf ("ERROR: unknown value\n");
      break;
    }
    printf ("STRING FLOAT BUFFER:\n");
    for (i = 0; i < MAX_PACKED_NUMBER_BLOCK_SIZE; i++)
    {
      printf ("%p, value: %02x\n", &left_of_decimal->packed_number_block[i], left_of_decimal->packed_number_block[i]);
    }
    printf ("first_number_block:    %p\n", left_of_decimal->first_number_block);
    printf ("last_number_block:     %p\n", left_of_decimal->last_number_block);
    printf ("previous number block: %p\n", left_of_decimal->previous_number_block);
    printf ("next number block:     %p\n", left_of_decimal->next_number_block);
    left_of_decimal = left_of_decimal->next_number_block;
    putchar ('\n');
  }
  if (right_of_decimal != NULL)
  {
    printf ("RIGHT OF DECIMAL:\n");
  }
  while (right_of_decimal != NULL)
  {
    printf ("\nNUMBER BLOCK:\n");
    printf ("address:                %p\n", right_of_decimal);
    printf ("highest digit position: %lld\n", right_of_decimal->highest_digit_position);
    printf ("highest nibble position: ");
    switch (right_of_decimal->highest_nibble_position)
    {
      case lo:
        printf ("lo\n");
      break;
      case hi:
        printf ("hi\n");
      break;
      default:
        printf ("ERROR: unknown value\n");
      break;
    }
    printf ("PACKED_NUMBER_BLOCK:\n");
    for (i = 0; i < MAX_PACKED_NUMBER_BLOCK_SIZE; i++)
    {
      printf ("%p, value: %02x\n", &right_of_decimal->packed_number_block[i], right_of_decimal->packed_number_block[i]);
    }
    printf ("first_number_block:    %p\n", right_of_decimal->first_number_block);
    printf ("last_number_block:     %p\n", right_of_decimal->last_number_block);
    printf ("previous number block: %p\n", right_of_decimal->previous_number_block);
    printf ("next number block:     %p\n", right_of_decimal->next_number_block);
    right_of_decimal = right_of_decimal->next_number_block;
    putchar ('\n');
  }
}




void display_runtime_expression_stack (runtime_expression_node *runtime_expression_stack)
{
  runtime_expression_node *element;
  psint *packed_string_integer;
  psflt *packed_string_float;
  unsigned char *bool_value, *constant_integer, *constant_float, *constant_bool;
  size_t constant_bool_string_length;

  element = runtime_expression_stack;
  while (element != NULL)
  {
    if (element->operator == _none)
    {
      if (element->operand != NULL)
      {
        switch (element->operand_type)
        {
          case _int:
            packed_string_integer = (psint *) element->operand;
            printf ("Operand:  ");
            packed_string_integer_display (packed_string_integer, 0);
            if (element->ok_to_free_memory_for_operand == TRUE)
            {
              printf (" (ok_to_free_memory_for_operand: TRUE)");
            }
            else
            {
              if (element->ok_to_free_memory_for_operand == FALSE)
              {
                printf (" (ok_to_free_memory_for_operand: FALSE)");
              }
            }
            printf ("\n");
          break;
          case _float:
            packed_string_float = (psflt *) element->operand;
            printf ("Operand:  ");
            packed_string_float_display (packed_string_float, 0);
            if (element->ok_to_free_memory_for_operand == TRUE)
            {
              printf (" (ok_to_free_memory_for_operand: TRUE)");
            }
            else
            {
              if (element->ok_to_free_memory_for_operand == FALSE)
              {
                printf (" (ok_to_free_memory_for_operand: FALSE)");
              }
            }
            printf ("\n");
          break;
          case _bool:
            bool_value = (unsigned char *) element->operand;
            if (*bool_value == 0)
            {
              printf ("Operand:  FALSE");
              if (element->ok_to_free_memory_for_operand == TRUE)
              {
                printf (" (ok_to_free_memory_for_operand: TRUE)");
              }
              else
              {
                if (element->ok_to_free_memory_for_operand == FALSE)
                {
                  printf (" (ok_to_free_memory_for_operand: FALSE)");
                }
              }
              printf ("\n");
            }
            else
            {
              if (*bool_value == 1)
              {
                printf ("Operand:  TRUE");
                if (element->ok_to_free_memory_for_operand == TRUE)
                {
                  printf (" (ok_to_free_memory_for_operand: TRUE)");
                }
                else
                {
                  if (element->ok_to_free_memory_for_operand == FALSE)
                  {
                    printf (" (ok_to_free_memory_for_operand: FALSE)");
                  }
                }
                printf ("\n");
              }
            }
          break;
          case _constant_int:
            constant_integer = (unsigned char *) element->operand;
            printf ("Operand: %s\n", constant_integer);
          break;
          case _constant_float:
            constant_float = (unsigned char *) element->operand;
            printf ("Operand: %s\n", constant_float);
          break;
          case _constant_bool:
            constant_bool = (unsigned char *) element->operand;
            constant_bool_string_length = strnlen (constant_bool, 5);
            switch (constant_bool_string_length)
            {
              case 1:
                if (*constant_bool == 'F')
                {
                  printf ("Operand:  FALSE");
                  if (element->ok_to_free_memory_for_operand == TRUE)
                  {
                    printf (" (ok_to_free_memory_for_operand: TRUE)");
                  }
                  else
                  {
                    if (element->ok_to_free_memory_for_operand == FALSE)
                    {
                      printf (" (ok_to_free_memory_for_operand: FALSE)");
                    }
                  }
                  printf ("\n");
                }
                else
                {
                  if (*constant_bool == 'T')
                  {
                    printf ("Operand:  TRUE");
                    if (element->ok_to_free_memory_for_operand == TRUE)
                    {
                      printf (" (ok_to_free_memory_for_operand: TRUE)");
                    }
                    else
                    {
                      if (element->ok_to_free_memory_for_operand == FALSE)
                      {
                        printf (" (ok_to_free_memory_for_operand: FALSE)");
                      }
                    }
                    printf ("\n");
                  }
                }
              break;
              case 4:
                if ((strncmp (constant_bool, "TRUE", 4) == 0) || 
                    (strncmp (constant_bool, "true", 4) == 0))
                {
                  printf ("Operand:  TRUE");
                  if (element->ok_to_free_memory_for_operand == TRUE)
                  {
                    printf (" (ok_to_free_memory_for_operand: TRUE)");
                  }
                  else
                  {
                    if (element->ok_to_free_memory_for_operand == FALSE)
                    {
                      printf (" (ok_to_free_memory_for_operand: FALSE)");
                    }
                  }
                  printf ("\n");
                }
              break; 
              case 5:
                if ((strncmp (constant_bool, "FALSE", 5) == 0) || 
                    (strncmp (constant_bool, "false", 5) == 0))
                {
                  printf ("Operand:  FALSE");
                  if (element->ok_to_free_memory_for_operand == TRUE)
                  {
                    printf (" (ok_to_free_memory_for_operand: TRUE)");
                  }
                  else
                  {
                    if (element->ok_to_free_memory_for_operand == FALSE)
                    {
                      printf (" (ok_to_free_memory_for_operand: FALSE)");
                    }
                  }
                  printf ("\n");
                }
              break;
              default:
                printf ("Operand: UNKNOWN\n");
              break;
            }
          break;
          default:
            printf ("Operand: UNKNOWN\n");
          break;
        }
      }
    }
    else
    {
      switch (element->operator)
      {
        case  _greater_than_or_equal:
          printf ("Operator: >=\n");
        break;
        case _greater_than:
          printf ("Operator: >\n");
        break;
        case _less_than_or_equal:
          printf ("Operator: <=\n");
        break;
        case _less_than:
          printf ("Operator: <\n");
        break;
        case _equal:
          printf ("Operator: ==\n");
        break;
        case _not_equal:
          printf ("Operator: !=\n");
        break;
        case _and:
          printf ("Operator: AND\n");
        break;
        case _or:
          printf ("Operator: OR\n");
        break;
        case _xor:
          printf ("Operator: XOR\n");
        break;
        case _not:
          printf ("Operator: NOT\n");
        break;
        case _plus:
          printf ("Operator: +\n");
        break;
        case _minus:
          printf ("Operator: -\n");
        break;
        case _times:
          printf ("Operator: *\n");
        break;
        case _divide:
          printf ("Operator: /\n");
        break;
        case _modulo:
          printf ("Operator: %%\n");
        break;
        default:
          printf ("Operator: UNKNOWN\n");
        break;
      }
    }
    element = element->next;
  }
}




void display_postfix_expression_compact (runtime_expression_node *runtime_expression_stack)
{
  runtime_expression_node *element;
  psint *packed_string_integer;
  psflt *packed_string_float;
  unsigned char *bool_value, *constant_integer, *constant_float, *constant_bool;
  size_t constant_bool_string_length;

  element = runtime_expression_stack;
  while (element != NULL)
  {
    if (element->operator == _none)
    {
      if (element->operand != NULL)
      {
        switch (element->operand_type)
        {
          case _int:
            packed_string_integer = (psint *) element->operand;
            packed_string_integer_display (packed_string_integer, 0);
            putchar (' ');
          break;
          case _float:
            packed_string_float = (psflt *) element->operand;
            packed_string_float_display (packed_string_float, 0);
            putchar (' ');
          break;
          case _bool:
            bool_value = (unsigned char *) element->operand;
            if (*bool_value == 0)
            {
              printf ("FALSE ");
            }
            else
            {
              if (*bool_value == 1)
              {
                printf ("TRUE ");
              }
            }
          break;
          case _constant_int:
            constant_integer = (unsigned char *) element->operand;
            printf ("%s ", constant_integer);
          break;
          case _constant_float:
            constant_float = (unsigned char *) element->operand;
            printf ("%s ", constant_float);
          break;
          case _constant_bool:
            constant_bool = (unsigned char *) element->operand;
            constant_bool_string_length = strnlen (constant_bool, 5);
            switch (constant_bool_string_length)
            {
              case 1:
                if (*constant_bool == 'F')
                {
                  printf ("FALSE ");
                }
                else
                {
                  if (*constant_bool == 'T')
                  {
                    printf ("TRUE ");
                  }
                }
              break;
              case 4:
                if ((strncmp (constant_bool, "TRUE", 4) == 0) || 
                    (strncmp (constant_bool, "true", 4) == 0))
                {
                  printf ("TRUE ");
                }
              break; 
              case 5:
                if ((strncmp (constant_bool, "FALSE", 5) == 0) || 
                    (strncmp (constant_bool, "false", 5) == 0))
                {
                  printf ("FALSE ");
                }
              break;
              default:
              break;
            }
          break;
          default:
          break;
        }
      }
    }
    else
    {
      switch (element->operator)
      {
        case  _greater_than_or_equal:
          printf (">= ");
        break;
        case _greater_than:
          printf ("> ");
        break;
        case _less_than_or_equal:
          printf ("<= ");
        break;
        case _less_than:
          printf ("< ");
        break;
        case _equal:
          printf ("== ");
        break;
        case _not_equal:
          printf ("!= ");
        break;
        case _and:
          printf ("AND ");
        break;
        case _or:
          printf ("OR ");
        break;
        case _xor:
          printf ("XOR ");
        break;
        case _not:
          printf ("NOT ");
        break;
        case _plus:
          printf ("+ ");
        break;
        case _minus:
          printf ("- ");
        break;
        case _times:
          printf ("* ");
        break;
        case _divide:
          printf ("/ ");
        break;
        case _modulo:
          printf ("%% ");
        break;
        default:
        break;
      }
    }
    element = element->next;
  }
}
