{-# LANGUAGE DeriveDataTypeable #-}

module Data.STData.Data
  ( OpenSData(..), OpenTData(..)
  , SData(..), SLink(..), TData(..), TLink(..)
  , DualSData(..), DualSLink(..), DualTData(..), DualTLink(..)
  , sdataToList
  ) where

import Data.Generics
import Text.Printf
import Data.SExp

-- Standard ST-Data

data OpenSData sl tl =
    AtomSData Atom             -- x
  | SLinkSData sl              -- ( ... )
  | TLinkSData tl              -- t(-( ... )-)
  deriving (Eq, Ord, Show, Typeable, Data)

data OpenTData sl =
    AtomTData String           -- text
  | SLinkTData sl              -- s(-( ... )-)
  deriving (Eq, Ord, Show, Typeable, Data)

newtype SData = SData { unSData :: OpenSData SLink TLink }
  deriving (Eq, Ord, Show, Typeable, Data)

newtype SLink = SLink { unSLink :: OpenLink SData SLink }
  deriving (Eq, Ord, Show, Typeable, Data)

newtype TData = TData { unTData :: OpenTData SLink }
  deriving (Eq, Ord, Show, Typeable, Data)

newtype TLink = TLink { unTLink :: OpenLink TData TLink }
  deriving (Eq, Ord, Show, Typeable, Data)

-- Anti ST-Data

data DualSData =
    PositiveDualSData (OpenSData DualSLink DualTLink)
  | AntiAtomDualSData AntiAtom
  deriving (Eq, Ord, Show, Typeable, Data)

data DualSLink =
    PositiveDualSLink (OpenLink DualSData DualSLink)
  | AntiConsDualSLink String
  deriving (Eq, Ord, Show, Typeable, Data)

data DualTData = DualTData { unDualTData :: OpenTData DualSLink }
  deriving (Eq, Ord, Show, Typeable, Data)

data DualTLink = DualTLink { unDualTLink :: OpenLink DualTData DualTLink }
  deriving (Eq, Ord, Show, Typeable, Data)

sdataToList :: SData -> [SData]
sdataToList (SData (SLinkSData slink)) = slinkToList slink
sdataToList other = error $ printf "cannot convert sdata to list: %s" (show other)

slinkToList :: SLink -> [SData]
slinkToList (SLink NullLink) = []
slinkToList (SLink (ConsLink s ss)) = s : slinkToList ss