@startuml ui
skinparam backgroundColor #EEEEEE

namespace crafting.ui #FFFFFF {
    class Menu {
        + title: String
        + options: Vector<String>
    }

    class ConsoleManager {
        {static} + displayMenu(menu: Menu): Int
        {static} + displayMessage(message: String)
    }

    ConsoleManager -right- Menu
}

namespace crafting.engine #FFFFFF {
    class CraftingManager {
        {static} - baseDiscoveryRate: Float
        {static} + craft(user: User*, craftingSkill*: CraftingSkill, recipeId: Int): CraftingResult
        {static} - findRecipeByID(craftingSkill*: CraftingSkill, recipeId: Int): Recipe
        {static} - checkUserHasResources(user: User*, requiredResources: Map<CraftingMaterialType, Int>): Bool
        {static} - calculateDiscoveryRate(recipeModifier: Float, skillModifier: Float): Float
        {static} - checkIfUserDiscoveredRecipe(discoveryChance: Float): Boolean
    }

    CraftingManager -- CraftingSkill
    CraftingManager -right- CraftingResult
    CraftingManager -- crafting.User
    CraftingManager .up.> crafting.ui.ConsoleManager

    class CraftingResult {
        + success: Boolean
        + didLevelUp: Boolean
        + craftingItemId: Int
    }

    class Recipe {
        + id: Int
        + levelUpModifier: Float
        + isUnlocked: Boolean
        + createdItemId: Int
        + requirements: Vector<CraftingRequirement>
        - level: Short
        + levelUp()
    }
    note right of Recipe: A recipe level is how many times the\nbetter version has been discovered.\nThey're the same concept.

    Recipe --o CraftingRequirement: has 1..n >

    class CraftingSkill {
        + id: Short
        + recipes: Vector<Recipe>
        + recipeDiscoveryRate: Float
        - level: Short
    }
    note right of CraftingSkill: `level` is unused right now, but we're\nkeeping it in mind for future scope of implementing a\nlevel system for each crafting tree to unlock base recipes.\n\nTo start with, all recipes will be unlocked.

    CraftingSkill --o Recipe : has 1..n >

    class CraftingRequirement {
        + materialType: CraftingMaterialType
        + quantity: Short
    }

    CraftingRequirement -- CraftingMaterialType

    enum CraftingMaterialType {
        Wood,
        Metal,
        Cloth
    }

    note left of CraftingMaterialType: Down the road, we're thinking of\na "misc" type, that can have different\nflavor text decided by the CraftingMaterial.

    class CraftingMaterial {
        + id: Int
        + displayName: String
        + type: CraftingMaterialType
        + minimumGatheringRate: Int
        + maximumGatheringRate: Int
        + doubleGatherRate: Float
    }

    CraftingMaterial -up- CraftingMaterialType

    class GatheringManager {
        {static} - chance: Float
        {static} + gatherMaterials(): Map<CraftingMaterialType, Int>
        {static} - gatherResource(craftingMaterial: &CraftingMaterial): Int
        {static} - checkIfResourceIsDoubled(craftingMaterial: &craftingMaterial): Bool
    }

    GatheringManager -left- CraftingMaterial
    GatheringManager -up- CraftingMaterialType
    GatheringManager .up.> crafting.ui.ConsoleManager
}

together {
    package sqlite3 {
        class sqlite3.sqlite3Database {
            + openConnection()
        }
        note right of sqlite3.sqlite3Database: This package is fully\ndocumented at\nhttps://www.sqlite.org/cintro.html
    }

    namespace crafting.database #FFFFFF {
        class DatabaseManager {
            + initialize()
            + shutdown()
            + getCraftingSkills(): Vector<CraftingSkill>
            + getRecipes(skillID: Short): Vector<Recipe>
        }
        
        DatabaseManager .down.> sqlite3.sqlite3Database

        note right of DatabaseManager: A lot is unknown about what this needs\nto support, until the other data structures\nhave more concrete implementations.
    }
}

crafting.database .down.+ sqlite3

namespace crafting #FFFFFF {
    class User {
        + craftingSkill: CraftingSkill*
        + inventory: Map<CraftingMaterialType, Int>
    }

    User ..> crafting.engine.CraftingSkill
    User -- crafting.engine.CraftingMaterialType

    class App {
        - _currentUser: User*
        - _isRunning: Bool
        - _appState: AppState

        + start()
        + stop()
        + currentUser(): const User*
    }

    enum AppState {
        MainMenu,
        Gathering,
        Crafting,
        Loading
    }

    App .right.> User
    App -left- AppState
    App .up.> crafting.ui.ConsoleManager
    App .right.> crafting.engine.CraftingManager
    App .right.> crafting.engine.GatheringManager
    App .right.> crafting.database.DatabaseManager
}
@enduml
