{-# LANGUAGE LambdaCase #-}

module Art.ContextFree.Probabilistic.Render ( render ) where

import Data.List.NonEmpty
import Data.Maybe
import System.Random
import qualified Art.ContextFree.Definite.Grammar as DG
import qualified Art.ContextFree.Definite.Render as DR
import qualified Art.ContextFree.Probabilistic.Grammar as PG
import qualified Text.Blaze.Svg11 as S

in100 :: Int -> Int
in100 = (`mod` 100) . abs

applyProb :: (Float, PG.Symbol) -> IO (Maybe DG.Symbol)
applyProb (n, g) = randomIO >>= toSym
  where
    toSym num = if in100 num < round n then convert g else pure Nothing

pureJ :: a -> IO (Maybe a)
pureJ = pure . Just

convert :: PG.Symbol -> IO (Maybe DG.Symbol)
convert (PG.NonTerminal syms)
  = let convertsM = (sequence $ applyProb <$> toList syms) :: IO [Maybe DG.Symbol]
        converts = (catMaybes <$> convertsM) :: IO [DG.Symbol]
    in  converts >>= \case
      [] -> pure Nothing
      (s : ss) -> pureJ $ DG.Branch $ s :| ss
convert (PG.Mod mods sym) = fmap (DG.Mod mods) <$> convert sym
convert (PG.Circle r) = pureJ $ DG.Circle r
convert (PG.Poly vecs) = pureJ $ DG.Poly vecs

-- | Create a drawing from a grammar.
--   In order to get a string representation, you'll need to use one of
--   blaze-svg's render functions, for example 'renderSvg'.
render :: PG.Symbol -> IO (Maybe S.Svg)
render sym = fmap DR.render <$> convert sym