module Data.Apart.Apart (Apart (..), Shape (..), Segment (..), Scattered (..)) where

import Control.Comonad.Cofree (Cofree (..))
import Data.Bifoldable (Bifoldable (..))
import Data.Bifunctor (Bifunctor (..))
import Data.Bitraversable (Bitraversable (..))
import Data.Kind (Type)

import Data.Apart.Shape (Shape (..))

-- | Structure with scattered segments.
data Apart t raw value = Apart
	{ part :: (Cofree (Shape t raw) value) }

instance Functor t => Functor (Apart t raw) where
	fmap f (Apart structure) = Apart $ f <$> structure

instance Functor t => Bifunctor (Apart t) where
	bimap g f (Apart (x :< Ready values)) = Apart $
		f x :< Ready (part . bimap g f . Apart <$> values)
	bimap g f (Apart (x :< Converted raw)) = Apart $
		f x :< (Converted $ g raw)

instance Foldable t => Bifoldable (Apart t) where
	bifoldr g f acc (Apart (x :< Ready values)) = f x $
		foldr (\st a -> bifoldr g f a $ Apart st) acc values
	bifoldr g f acc (Apart (x :< Converted raw)) = f x $ g raw acc

instance Traversable t => Bitraversable (Apart t) where
	bitraverse g f (Apart (x :< Ready values)) = (<$>) Apart $ (:<) <$> f x <*>
		(Ready <$> traverse ((<$>) part . bitraverse g f . Apart) values)
	bitraverse g f (Apart (x :< Converted raw)) = (<$>) Apart $
		(:<) <$> f x <*> (Converted <$> g raw)

type family Segment (structure :: Type -> Type) (value :: Type) :: Type where
	Segment (Cofree t) value = t (Cofree t value)

type family Scattered (structure :: Type -> Type) (value :: Type) (raw :: Type) :: Type where
	Scattered (Cofree t) value raw = Apart t raw value