----------------------------------------------------------------------------
-- |
-- Module      :  CSPM.Interpreter.GenricBufferPrefix
-- Copyright   :  (c) Fontaine 2009
-- License     :  BSD
-- 
-- Maintainer  :  Fontaine@cs.uni-duesseldorf.de
-- Stability   :  experimental
-- Portability :  GHC-only
--
-- A wrapper around CSPM.Interpreter.Prefix with support for generic buffers.
--
----------------------------------------------------------------------------
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE BangPatterns #-}

module CSPM.Interpreter.GenericBufferPrefix
(
  initPrefix
 ,viewPrefixState
 ,prefixStateNext
 ,prefixStateFinalize
)
where

import qualified CSPM.CoreLanguage as Core
import Language.CSPM.AST as AST hiding (Bindings)

import CSPM.Interpreter.Types as Types
import CSPM.Interpreter.Bindings as Bindings
import CSPM.Interpreter.PatternMatcher
import CSPM.Interpreter.Eval
import qualified CSPM.Interpreter.Prefix as BasePrefix
import CSPM.Interpreter.SSet as SSet

import Data.List as List
import Control.Monad

initPrefix :: PrefixState -> GenericBufferPrefix
initPrefix = lookAhead . BasePrefix.initPrefix

viewPrefixState :: GenericBufferPrefix -> Core.PrefixFieldView INT
viewPrefixState p = case p of
  GBOut (h:_) _ -> Core.FieldOut h
  GBOut [] _ -> error "GenericBuffer.hs : viewPrefixState : internal error : empty buffer"
  GBInput _ -> Core.FieldIn
  GBInputGuard g _ -> Core.FieldGuard g
  GBInputGeneric _ _ -> Core.FieldIn
  GBFinished _ -> error "GenericBuffer.hs : viewPrefixState : no fields left"
 
prefixStateNext :: GenericBufferPrefix -> Field -> Maybe GenericBufferPrefix
prefixStateNext gbPrefix field = case gbPrefix of
  GBOut [h] p -> do
    guard $ h == field
    liftM lookAhead $ BasePrefix.prefixStateNext p (error "GenericBufferDummyFields")
  GBOut (h:t) p -> do
    guard $ h == field
    return $ GBOut t p
  GBInput p -> liftM lookAhead $ BasePrefix.prefixStateNext p field
  GBInputGuard g p -> do
    guard $ field `SSet.member` g
    liftM lookAhead $ BasePrefix.prefixStateNext p field
  GBInputGeneric b p -> return $ GBInputGeneric (field:b) p
  GBFinished _ -> error "GenericBuffer.hs : prefixStateNext : no fields left"

prefixStateFinalize :: GenericBufferPrefix -> Maybe PrefixState
prefixStateFinalize gbPrefix = case gbPrefix of
  GBInputGeneric buffer p -> case buffer of
   [] -> error "GenericBuffer.hs : empty dot tuple"
   [v] -> BasePrefix.prefixStateNext p v >>= BasePrefix.prefixStateFinalize
   l -> BasePrefix.prefixStateNext p (VDotTuple $ reverse l)
      >>= BasePrefix.prefixStateFinalize
  GBFinished p -> BasePrefix.prefixStateFinalize p
  _ -> error "GenericBuffer.hs : stateError"

lookAhead :: PrefixState -> GenericBufferPrefix
lookAhead p | List.null $ prefixFields p = GBFinished p
lookAhead p | isLastInputField p = GBInputGeneric [] p
lookAhead p = case BasePrefix.viewPrefixState p of
  Core.FieldOut v -> case v of
    (VDotTuple l) -> GBOut (splitTuple l) p
    x -> GBOut [x] p
  Core.FieldIn -> GBInput p
  Core.FieldGuard g -> GBInputGuard g p

isLastInputField :: PrefixState -> Bool
isLastInputField (PrefixState {
  prefixFields =  [unLabel -> InComm (unLabel -> VarPat _ )] 
  }) = True
{- todo : fields that end with wildcard c?_ -> x -}
isLastInputField _ = False

splitTuple :: [Value] -> [Value]
splitTuple [] = []
splitTuple l@(h:t) = case h of
  VConstructor c | not $ List.null $ constrFields c
    -> VDotTuple (take len l) : splitTuple (drop len l)
         where len = 1 + (length $ constrFields c)
  _ -> h : splitTuple t