module Reanimate.Math.Triangulate
  ( Triangulation
  , edgesToTriangulation
  , edgesToTriangulationM
  , trianglesToTriangulation
  , trianglesToTriangulationM
  )
where

import           Control.Monad
import qualified Data.IntSet                   as ISet
import qualified Data.Vector                   as V
import qualified Data.Vector.Mutable           as MV
import           Control.Monad.ST

-- Max edges: n-2
-- Each edge is represented twice: 2n-4
-- Flat structure:
--   edges   :: V.Vector Int -- max length (2n-4)
--   offsets :: V.Vector Int -- length n
-- Combine the two vectors? < n => offsets, >= n => edges?
type Triangulation = V.Vector [Int]

-- FIXME: Move to Common or a Triangulation module
-- O(n)
edgesToTriangulation :: Int -> [(Int, Int)] -> Triangulation
edgesToTriangulation size edges = runST $ do
  v <- edgesToTriangulationM size edges
  V.unsafeFreeze v

edgesToTriangulationM :: Int -> [(Int, Int)] -> ST s (V.MVector s [Int])
edgesToTriangulationM size edges = do
  v <- MV.replicate size []
  forM_ edges $ \(e1, e2) -> do
    MV.modify v (e1 :) e2
    MV.modify v (e2 :) e1
  forM_ [0 .. size - 1] $ \i -> MV.modify v (ISet.toList . ISet.fromList) i
  return v

trianglesToTriangulation :: Int -> V.Vector (Int, Int, Int) -> Triangulation
trianglesToTriangulation size edges = runST $ do
  v <- trianglesToTriangulationM size edges
  V.unsafeFreeze v

trianglesToTriangulationM
  :: Int -> V.Vector (Int, Int, Int) -> ST s (V.MVector s [Int])
trianglesToTriangulationM size trigs = do
  v <- MV.replicate size []
  forM_ (V.toList trigs) $ \(a, b, c) -> do
    MV.modify v (\x -> b : c : x) a
    MV.modify v (\x -> a : c : x) b
    MV.modify v (\x -> a : b : x) c
  forM_ [0 .. size - 1] $ \i -> MV.modify v (ISet.toList . ISet.fromList) i
  return v