{-# LANGUAGE DeriveDataTypeable #-}

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

import Data.Generics
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)
  | AntiConsValueDualSLink String
  | AntiConsListDualSLink 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)

sdataSymbolValue :: SData -> Maybe String
sdataSymbolValue (SData (AtomSData (SymbolAtom s))) = Just s
sdataSymbolValue _ = Nothing

sdataToList :: SData -> Maybe [SData]
sdataToList (SData (SLinkSData slink)) = Just $ slinkToList slink
sdataToList _ = Nothing

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

listToSData :: [SData] -> SData
listToSData ss = SData . SLinkSData $ listToSLink ss

listToSLink :: [SData] -> SLink
listToSLink [] = SLink NullLink
listToSLink (s:ss) = SLink . ConsLink s $ listToSLink ss