// Functions for internal use


/**
 * Converts any decimal number into a hexadecimal number
 */
DEFINE_ACTION_FUNCTION TO_HEX_NUMBER
INT_VAR
  value     = 0   // the decimal number
  minDigits = 1   // min. number of digits in return value (not counting sign)
  prefix    = 0   // whether to return number with "0x" prefix
RET
  hexNumber       // returned as string without prefix
BEGIN
  ACTION_IF (minDigits < 1) BEGIN OUTER_SET minDigits = 1 END
  ACTION_IF (minDigits > 8) BEGIN OUTER_SET minDigits = 8 END
  OUTER_TEXT_SPRINT hexNumber ~~
  ACTION_DEFINE_ARRAY digit BEGIN ~0~ ~1~ ~2~ ~3~ ~4~ ~5~ ~6~ ~7~ ~8~ ~9~ ~a~ ~b~ ~c~ ~d~ ~e~ ~f~ END

  ACTION_IF (value < 0) BEGIN
    OUTER_SET signed = 1
    OUTER_SET value = 0 - value
  END ELSE BEGIN
    OUTER_SET signed = 0
  END

  OUTER_WHILE (value != 0) BEGIN
    OUTER_SET curDigit = value BAND 0xf
    OUTER_SET value = value BLSR 4
    OUTER_TEXT_SPRINT hexDigit $EVAL digit(~%curDigit%~)
    OUTER_TEXT_SPRINT hexNumber ~%hexDigit%%hexNumber%~
  END

  OUTER_WHILE (STRING_LENGTH ~%hexNumber%~ < minDigits) BEGIN
    OUTER_TEXT_SPRINT hexNumber ~0%hexNumber%~
  END

  ACTION_IF (prefix) BEGIN
    OUTER_TEXT_SPRINT hexNumber ~0x%hexNumber%~
  END

  ACTION_IF (signed) BEGIN
    OUTER_TEXT_SPRINT hexNumber ~-%hexNumber%~
  END
END

DEFINE_PATCH_FUNCTION TO_HEX_NUMBER
INT_VAR
  value     = 0
  minDigits = 1
  prefix    = 0
RET
  hexNumber
BEGIN
  INNER_ACTION BEGIN
    LAF TO_HEX_NUMBER INT_VAR value = value minDigits = minDigits prefix = prefix RET hexNumber END
  END
END


/**
 * Converts a hexadecimal value back into a decimal number.
 * STR_VAR hexNumber  A string containing a hexadecimal number without prefix.
 * RET value          The resulting decimal number as int value. Returns -1 on error.
 */
DEFINE_ACTION_FUNCTION TO_DEC_NUMBER
STR_VAR
  hexNumber  = ~~
RET
  value
BEGIN
  OUTER_SET value = "-1"

  ACTION_IF (~%hexNumber%~ STRING_EQUAL ~~) BEGIN
    OUTER_SET value = 0
  END ELSE BEGIN
    // checking for sign
    ACTION_IF (~%hexNumber%~ STRING_MATCHES_REGEXP ~-.+~ = 0) BEGIN
      OUTER_SET signed = 1
      OUTER_PATCH_SAVE hexNumber ~%hexNumber%~ BEGIN REPLACE_TEXTUALLY ~^-~ ~~ END
    END ELSE BEGIN
      OUTER_SET signed = 0
    END

    // checking for prefix
    ACTION_IF (~%hexNumber%~ STRING_MATCHES_REGEXP ~^0[xX].+~ = 0) BEGIN
      OUTER_PATCH_SAVE hexNumber ~%hexNumber%~ BEGIN REPLACE_TEXTUALLY ~^0[xX]~ ~~ END
    END

    // converting number
    OUTER_SET curValue = 0
    OUTER_SET scale = 1
    OUTER_SET strlen = STRING_LENGTH ~%hexNumber%~
    OUTER_FOR (idx = strlen - 1; idx >= 0; --idx) BEGIN
      OUTER_PATCH ~%hexNumber%~ BEGIN READ_BYTE idx hexDigit END
      OUTER_SET hexDigit = hexDigit BAND 0xff
      ACTION_IF (hexDigit >= 48 AND hexDigit <= 57) BEGIN // 0..9
        OUTER_SET digit = hexDigit - 48
      END ELSE ACTION_IF (hexDigit >= 65 AND hexDigit <= 70) BEGIN  // A..F
        OUTER_SET digit = hexDigit - 55
      END ELSE ACTION_IF (hexDigit >= 97 AND hexDigit <= 102) BEGIN // a..f
        OUTER_SET digit = hexDigit - 87
      END ELSE BEGIN
        OUTER_SET digit = 0
      END
      OUTER_SET curValue += digit*scale
      OUTER_SET scale = scale BLSL 4
    END

    ACTION_IF (signed) BEGIN
      OUTER_SET curValue = 0 - curValue
    END

    OUTER_SET value = curValue
  END
END

DEFINE_PATCH_FUNCTION TO_DEC_NUMBER
STR_VAR
  hexNumber  = ~~
RET
  value
BEGIN
  INNER_ACTION BEGIN
    LAF TO_DEC_NUMBER STR_VAR hexNumber = EVAL ~%hexNumber%~ RET value END
  END
END


/**
 * Adds a new entry to SPLPROT.2DA and returns its index. If an identical entry already exists it will return 
 * the index of that entry instead.
 * INT_VAR stat     A code from STATS.IDS or an extended stat code starting at 0x100 (256).
 * STR_VAR value    Either a numeric value that is evaluated by "stat", or a default value "*" for specific stats.
 *                  (Note: "-1" indicates a user-defined value.)
 * STR_VAR relation Specifies how to evaluate the value.
 *                  (Note: Not all extended stats require a relation code. Use "*" in this case.)
 * RET index        Entry number that can be used to refer to this operation in various effect opcodes.
 *                  Returns -1 on error.
 */
DEFINE_ACTION_FUNCTION ADD_SPLPROT_ENTRY
INT_VAR
  stat      = "-1"
STR_VAR
  value     = "*"
  relation  = "*"
RET
  index
BEGIN
  OUTER_SET index = "-1"

  ACTION_IF (stat >= 0) BEGIN
    LAF TO_HEX_NUMBER INT_VAR value = stat RET hexNumber END
    OUTER_TEXT_SPRINT valueHex ~0x%hexNumber%~
    ACTION_IF (~%value%~ STRING_EQUAL ~~) BEGIN
      OUTER_TEXT_SPRINT value ~*~
    END
    ACTION_IF (~%relation%~ STRING_EQUAL ~~) BEGIN
      OUTER_TEXT_SPRINT relation ~*~
    END

    ACTION_IF (FILE_EXISTS_IN_GAME ~splprot.2da~) BEGIN
      COPY_EXISTING ~splprot.2da~ ~override~
        READ_2DA_ENTRIES_NOW table 4
        // Search for identical entries
        FOR (idx = 0; idx < table; idx += 1) BEGIN
          READ_2DA_ENTRY_FORMER table idx 1 curStat
          PATCH_IF (~%stat%~ STRING_EQUAL ~%curStat%~ OR ~%valueHex%~ STRING_EQUAL_CASE ~%curStat%~) BEGIN
            READ_2DA_ENTRY_FORMER table idx 2 curValue
            PATCH_IF (~%value%~ STRING_EQUAL ~%curValue%~) BEGIN
              READ_2DA_ENTRY_FORMER table idx 3 curRelation
              PATCH_IF (~%relation%~ STRING_EQUAL ~%curRelation%~) BEGIN
                SET index = idx
                SET idx = table
              END
            END
          END
        END

        PATCH_IF (index < 0) BEGIN
          // Add new entry
          PATCH_IF (stat >= 0x100) BEGIN
            TEXT_SPRINT line ~%table%        %valueHex%        %value%         %relation%~
          END ELSE BEGIN
            TEXT_SPRINT line ~%table%        %stat%          %value%         %relation%~
          END
          INSERT_2DA_ROW table 4 ~%line%~
          SET index = table
        END
      BUT_ONLY
    END
  END
END


/**
 * Adds a new entry to SPLPROT.2DA and returns its index. If an identical entry already exists it will return 
 * the index of that entry instead.
 * INT_VAR stat     A code from STATS.IDS or an extended stat code starting at 0x100 (256).
 * STR_VAR value    Either a numeric value that is evaluated by "stat", or a default value "*" for specific stats.
 *                  (Note: "-1" indicates a user-defined value.)
 * STR_VAR relation Specifies how to evaluate the value.
 *                  (Note: Not all extended stats require a relation code. Use "*" in this case.)
 * RET index        Entry number that can be used to refer to this operation in various effect opcodes.
 *                  Returns -1 on error.
 * 
 * Example Usage:
 * LAF ADD_PORTRAIT_ICON INT_VAR string = RESOLVE_STR_REF(@3070) STR_VAR bam_file = cdia422d RET icon END
 *
 * ADD_SPELL ~iwdification/spl/cdia422.spl~ 2 4 WIZARD_BELTYNS_BURNING_BLOOD
 *   LPF ALTER_EFFECT INT_VAR match_opcode = 142 match_parameter2 = 66 parameter2 = icon END
 *
 * Found here: https://www.gibberlings3.net/forums/topic/28835-toss-your-semi-useful-weidu-macros-here/page/5/#comment-258129
 */
DEFINE_ACTION_FUNCTION ADD_PORTRAIT_ICON
  INT_VAR string = 0
  STR_VAR bam_file = "****"
  RET     icon
  BEGIN

  COPY_EXISTING ~statdesc.2da~ ~override~
    COUNT_2DA_ROWS 3 count
    READ_2DA_ENTRY (count - 1) 0 3 icon
    SET icon += 1

  APPEND ~statdesc.2da~ ~%icon% %string% %bam_file%~

END