{- |
Annotating tree structures with desired properties for rooms.
-}
module Dodge.Layout.Tree.Annotate
    where
import Dodge.Data
import Dodge.RandomHelp
import Dodge.Layout.Tree.Polymorphic
import Dodge.Layout.Tree.Either
import Dodge.Room.Procedural
import Dodge.Room.Branch
import Dodge.Room.RoadBlock
import Dodge.Room.Door
import Dodge.Room.Boss
import Dodge.Room.Treasure
import Dodge.Room.Link
import Dodge.Room.Data
import Dodge.Room.Airlock
import Dodge.Room.Start
import Dodge.Room
import Dodge.Room.Teleport

import Data.Tree
import Control.Monad.State
import System.Random

data Annotation g
    = Lock Int
    | Key  Int
    | Corridor
    | CorridorDebug
    | DoorAno
    | SwitchDoorAno
    | DoorNumAno Int
    | AirlockAno
    | FirstWeapon
    | StartRoom
    | EndRoom
    | OrAno [[Annotation g]]
    | SpecificRoom (State g (Tree (Either Room Room)))
    | BossAno Creature
    | TreasureAno [Creature] [Item]

addLock :: RandomGen g => Int -> Tree [Annotation g] -> State g (Tree [Annotation g])
addLock i t = do
    (beforeLock, afterLock) <- splitTrunk t
    newBefore <- applyToRandomNode (Key i :) beforeLock
    return $ addToTrunk newBefore [Node [Lock i] afterLock]
{- |
Add one corridor between each parent-child link of a tree of annotations.
 -}
padCorridors :: Tree [Annotation g] -> Tree [Annotation g]
padCorridors (Node x xs) = Node [Corridor] [Node x (map padCorridors xs)]
{-
Add one to three corridors between each parent-child link of a tree of annotations.
 -}
randomPadCorridors :: RandomGen g => Tree [Annotation g] -> State g (Tree [Annotation g])
randomPadCorridors  (Node x xs) = do
    n <- state $ randomR (1, 3)
    xs' <- mapM randomPadCorridors xs
    return $ treeFromTrunk (replicate n [Corridor]) (Node x xs')
{- |
Add a corridor to a random out-link of a room.
 -}
roomThenCorridor :: RandomGen g => Room -> State g (Tree (Either Room Room))
roomThenCorridor theRoom = fmap (\r -> Node (Left theRoom) [(pure . Right) r]) 
                                (randomiseOutLinks corridor)
{- |
Create a random room tree structure from a list of annotations.
 -}
annoToRoomTree :: RandomGen g => [Annotation g] -> State g (Tree (Either Room Room))
annoToRoomTree [OrAno as] = do
    a <- takeOne as
    annoToRoomTree a
annoToRoomTree [Corridor] = pure . Right <$> randomiseOutLinks corridor
annoToRoomTree [CorridorDebug] = pure . Right <$> randomiseOutLinks corridorDebug
annoToRoomTree [DoorAno] = roomThenCorridor door
annoToRoomTree [DoorNumAno i,AirlockAno] = airlock i >>=  roomThenCorridor
annoToRoomTree [FirstWeapon] = do
    branchWP <- branchRectWith weaponRoom
    blockedC <- longBlockedCorridor
    join $ takeOne $ return (appendEitherTree branchWP [blockedC]) : replicate 5 weaponRoom
annoToRoomTree [EndRoom] = fmap (pure . Right) (telRoomLev 1)
annoToRoomTree [StartRoom] = startRoom
annoToRoomTree (SpecificRoom rt:_) = rt
annoToRoomTree (BossAno cr : _) = do
    br <- bossRoom cr
    branchRectWith . pure . fmap Left $ treeFromPost [corridor,corridor] br
annoToRoomTree (TreasureAno crs loot : _) =
    branchRectWith . fmap (pure . Left) $ lootRoom crs loot
annoToRoomTree _ = do
    w <- state $ randomR (100,400)
    h <- state $ randomR (200,400)
    fmap (pure . Right) . randomiseOutLinks $ roomRectAutoLinks w h
