{-# OPTIONS_GHC -Wno-unused-imports #-}

-- |
-- [Previous Chapter: Asset Refs]("Mischief.Assets.Tutorial.Refs")
--
-- [Next Chapter: Kdl Assets]("Mischief.Assets.Tutorial.Kdl")
--
-- [Main Page]("Mischief.Assets")
module Mischief.Assets.Tutorial.Control
  ( -- * Chapter 3: Asset Control Flow
    -- $intro

    -- * Active vs. Passive Querying
    -- $passiveactive

    -- * Recursive Loading
    -- $rec

    -- * Events
    -- $events

    -- * One-Shot Observers
    -- $oneshot

    -- * [Next Chapter: Kdl Assets]("Mischief.Assets.Tutorial.Kdl")
  )
where

import Mischief.Assets
import Mischief.ECS

-- $intro
-- Some pointers on controlling the logic control flow when working with assets.

-- $passiveactive
-- Attempting to query for an asset will, by default, prompt the asset to load. This is called
-- /active/ querying.
--
-- For instance, running this every frame:
--
-- @
-- foo <- 'asset' \@Foo \"foo.kdl\"
-- @
--
-- Will prompt Foo to start loading if it hasn't yet.
--
-- Assuming that it takes it less than a frame to load, this should be returning a @Just Foo@ starting with the second frame.
--
-- This mechanism is extremely powerful when used in conjunction with queries, via @qasset@, since
-- queries are designed to stop executing when something you're trying to grab isn't available:
--
-- @
-- 'query_' $ do
--   foo <- 'qasset' \@Foo getB
--   'qlift' $ 'info' ['i'|Reading asset: #{foo}|]
-- @
--
-- You can choose to use /passive/ querying, through the equivalent functions ending in @'@. Such as
-- @'asset''@ and @'qasset''@. These functions will attempt to grab the asset, but they will not prompt it to load.

-- $events
-- You can spawn observers that listen to the @OnLoad@ events, which is triggered each time an asset is loaded.
--
-- @
-- onFoo :: 'OnLoad' Foo -> 'System'
-- onFoo event = ...
-- @
--
-- Since assets are components, you can also listen to @'OnAdd'@, @'OnSet'@, and so on.

-- $rec
-- By default, each asset is loaded lazily. Meaning the least possible amount of I/O operations will be performed in order to get the data you need.
--
-- If asset @A@ contains a reference to asset @B@, neither @'load'@ nor @'asset'@ of @A@ will attempt to load @B@.
-- You can alternatively use the dedicated @'loadRec'@ and @'assetRec'@ which will trigger a recursive loading sequence.
--
-- For all assets you define, you are responsible for specifying the references that will be loaded in such a case. For instance:
--
-- @
-- data Foo = Foo
--   {
--     i :: 'Int',
--     ref1 :: 'AssetRef' Bar
--     ref2 :: 'KdlRef' Baz
--   }
--
-- instance 'Asset' Foo where
--   'rec' foo = do
--     'addRec' foo.ref1
--     'addRec' $ 'toRef' foo.ref2
-- @

-- $oneshot
-- You can use @'runWhen'@ and similar functions to run a system when a specific asset (or group of assets) has been loaded, like so:
--
-- @
-- 'runWhenOne'
--   (
--     foo <- 'qasset' \@Foo \"foo.kdl\"
--     bar <- 'qasset' \@Bar \"bar.kdl\"
--     'pure' (foo, bar)
--   )
--   (\\(foo, bar) -> do
--     ...
--   )
-- @
--
-- Note however, that each time this function is ran, an instance of your query will be scheduled to run at every sync point until
-- it returns a result. In order to not waste a large amount of resources, this should only be used in one-time logic such as
-- on Startup or in an Observer, rather than in logic that runs at a fixed interval.