'OHRRPGCE GAME - achievement definitions
'(C) Copyright 1997-2020 James Paige, Ralph Versteegen, and the OHRRPGCE Developers
'Dual licensed under the GNU GPL v2+ and MIT Licenses. Read LICENSE.txt for terms and disclaimer of liability.
'
#include "achievements.bi"
#include "reload.bi"
#include "steam.bi"

' uncomment to enable spammy debug output
' #define DEBUG_ACHIEVEMENTS

using Reload

namespace Achievements

  ' Local functions
  declare function type_name_to_enum(name as string) as AchievementType

  dim enable_debug as boolean = false
  dim shared next_id as integer = 0
  dim shared permanent as boolean = false
  dim shared reset_queued as boolean = false
  dim shared achievement_defs() as AchievementDefinition

  ' -- public api --

  sub definitions_load(file_path as string)
    definitions_free

    DIM doc as Docptr
    doc = LoadDocument(file_path, LoadOptions.optIgnoreMissing)
    if doc = null then return

    dim cheevos as Nodeptr = DocumentRoot(doc)
    if cheevos = null then
      FreeDocument(doc)
      return
    end if

    dim num_achievements as integer = CountChildren(cheevos, "achievement")

    ach_debug("loading " & num_achievements & " from disk")

    if num_achievements = 0 then
      erase achievement_defs
    else
      redim achievement_defs(num_achievements - 1)
    end if

    dim i as integer = 0

    READNODE cheevos
      next_id = cheevos."next_id".integer
      permanent = cheevos."permanent".exists

      WITHNODE cheevos."achievement" as cheevo
        with achievement_defs(i)
          .id = GetInteger(cheevo)
          .name = cheevo."name".string
          .achievement_type = type_name_to_enum(cheevo."type".string)
          .max_value = cheevo."max_value".integer
          .progress_interval = cheevo."progress_interval".integer
          .latching = cheevo."latching".exists
          .steam_id = cheevo."steam_id".string

          dim tag as Nodeptr = FirstChild(cheevo."tags".ptr, "tag")
          while tag <> null
            v_append .tags, GetInteger(tag)
            tag = NextSibling(tag, "tag")
          wend
        end with
        ach_debug("Loaded achievement #" & i & ", " & achievement_defs(i).name)
        i += 1
      END WITHNODE
    END READNODE

    FreeDocument(doc)

    if reset_queued then
      'Hopefully this is after the steam data stuff is loaded
      debuginfo "Resetting Steam achievements"
      reset_queued = false

      for i as integer = 0 to ubound(achievement_defs)
        Steam.clear_achievement(achievement_defs(i).steam_id)
      next
    end if
  end sub

  sub definitions_free
    ach_verbose("definitions_free")
    erase achievement_defs

    next_id = 1
    permanent = false
  end sub

  sub definitions_reset
    ach_verbose("definitions_reset")

    reset_queued = true
  end sub

  function definitions_count() as integer
    ach_verbose("definitions_count")
    return ubound(achievement_defs) - lbound(achievement_defs) + 1
  end function

  function get_definition_by_index(index as integer) byref as AchievementDefinition
    ach_verbose("get_definition_by_index(" & index & ")")

    ERROR_IF(index < 0 orelse index > ubound(achievement_defs), "Invalid achievement index, " & index, byval null)

    return achievement_defs(index)
  end function

  function get_definition_by_id(id as integer) byref as AchievementDefinition
    for i as integer = 0 to ubound(achievement_defs)
      if achievement_defs(i).id = id then return achievement_defs(i)
    next
    ERROR_IF(true, "Invalid achievement id, " & id, byval null)
  end function

  function is_permanent() as boolean
    return permanent
  end function

  ' -- members for AchievementDefinition --

  constructor AchievementDefinition
    v_new tags
  end constructor

  destructor AchievementDefinition
    v_free tags
  end destructor

  ' -- internal helpers --

  function type_name_to_enum(name as string) as AchievementType
    select case name
      case "flag"
        return AchievementType.flag
      case "count"
        return AchievementType.count
      case else
        debug "unknown achievement type string: " & name
        return AchievementType.flag
    end select
  end function

  function type_enum_to_name(typ as AchievementType) as string
    select case typ
      case AchievementType.flag
        return "flag"
      case AchievementType.count
        return "count"
      case else
        debug "unknown achievement type enum: " & typ
        return "flag"
    end select
  end function

  sub ach_debug(msg as string)
    if enable_debug then debuginfo "achievements: " & msg
  end sub

end namespace