module ADP.Fusion.Core.Term.Edge where

import Data.Strict.Tuple
import Data.Proxy

import Data.PrimitiveArray

import ADP.Fusion.Core.Classes
import ADP.Fusion.Core.Multi



newtype From = From { getFrom :: Int }
  deriving (Eq,Ord,Show)

newtype To = To { getTo :: Int }
  deriving (Eq,Ord,Show)

-- | An edge in a graph. As a parsing symbol, it will provide (From:.To)
-- pairs.

data Edge = Edge

instance Build Edge

instance
  ( Element ls i
  ) => Element (ls :!: Edge) i where
    data Elm (ls :!: Edge) i = ElmEdge !(From:.To) !(RunningIndex i) !(Elm ls i)
    type Arg (ls :!: Edge)   = Arg ls :. (From:.To)
    getArg (ElmEdge e _ ls) = getArg ls :. e
    getIdx (ElmEdge _ i _ ) = i
    {-# Inline getArg #-}
    {-# Inline getIdx #-}

deriving instance (Show i, Show (RunningIndex i), Show (Elm ls i)) => Show (Elm (ls :!: Edge) i)

type instance TermArg Edge = (From:.To)

-- | 'edgeFromTo' creates a @(From:.To)@ structure for edges. How this is
-- filled depends on the @Proxy@. Possible are @Proxy First@ and @Proxy Last@.
-- @First@ denotes that @To@ is the first node to be visited. I.e. @First(From)
-- → Set(To)@. @Last@ on the other hand is @Set(From) → Last(To)@.

class EdgeFromTo k where
  edgeFromTo  Proxy k  SetBoundary  NewBoundary  (From:.To)

newtype SetBoundary = SetBoundary Int

newtype NewBoundary = NewBoundary Int

-- | In case our sets have a @First@ boundary, then we always point from
-- the boundary "into" the set. Hence @SetNode == To@ and @NewNode ==
-- From@.
--
-- @{1,2,(3)} <- (4)@ yields @From 4 :. To 3@. Note the arrow direction @INTO@
-- the set.

instance EdgeFromTo First where
  edgeFromTo Proxy (SetBoundary to) (NewBoundary from) = From from :. To to
  {-# Inline edgeFromTo #-}

-- | And if the set has a @Last@ boundary, then we point from somewhere in
-- the set @To@ the @NewNode@, which is @Last@.
--
-- @{1,2,(3)} -> (4)@ yields @From 3 :. To 4@. Note the arrow direction @OUT
-- OF@ the set.

instance EdgeFromTo Last where
  edgeFromTo Proxy (SetBoundary from) (NewBoundary to) = From from :. To to
  {-# Inline edgeFromTo #-}