-----------------------------------------------------------------------------
-- Copyright 2014, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-- A prefix encodes a sequence of steps already performed (a so-called trace),
-- and allows to continue the derivation at that particular point.
--
-----------------------------------------------------------------------------
--  $Id: Prefix.hs 6535 2014-05-14 11:05:06Z bastiaan $

module Ideas.Common.Strategy.Prefix
   ( Prefix, emptyPrefix, makePrefix, showPrefix
   , prefixToSteps, prefixTree, stepsToRules, lastStepInPrefix, activeLabels
   , searchModePrefix
   ) where

import Data.List
import Data.Maybe
import Ideas.Common.DerivationTree
import Ideas.Common.Rule
import Ideas.Common.Strategy.Abstract
import Ideas.Common.Strategy.Parsing
import Ideas.Common.Strategy.Path

-----------------------------------------------------------
--- Prefixes

-- | Abstract data type for a (labeled) strategy with a prefix (a sequence of
-- executed rules). A prefix is still "aware" of the labels that appear in the
-- strategy. A prefix is encoded as a list of integers (and can be reconstructed
-- from such a list: see @makePrefix@). The list is stored in reversed order.
type Prefix = ParseState LabelInfo

showPrefix :: Prefix a -> String
showPrefix = show . choices

-- | Construct the empty prefix for a labeled strategy
emptyPrefix :: LabeledStrategy a -> a -> Prefix a
emptyPrefix a = fromMaybe (error "emptyPrefix") . makePrefix emptyPath a

-- | Construct a prefix for a given list of integers and a labeled strategy.
makePrefix :: Monad m => Path -> LabeledStrategy a -> a -> m (Prefix a)
makePrefix path = flip (replay path) . mkCore
 where
   mkCore = processLabelInfo id . toCore . toStrategy

-- | Create a derivation tree with a "prefix" as annotation.
prefixTree :: a -> Prefix a -> DerivationTree (Prefix a) a
prefixTree a = fmap fst . updateAnnotations (\_ _ -> snd) . parseDerivationTree a

searchModePrefix :: (Step LabelInfo a -> Bool) -> (Step LabelInfo a -> Step LabelInfo a -> Bool) -> Prefix a -> Prefix a
searchModePrefix = searchModeState

prefixToSteps :: Prefix a -> [Step LabelInfo a]
prefixToSteps = reverse . trace

-- | Retrieves the rules from a list of steps
stepsToRules :: [Step l a] -> [Rule a]
stepsToRules xs = [ r | RuleStep _ r <- xs ]

-- | Returns the last rule of a prefix (if such a rule exists)
lastStepInPrefix :: Prefix a -> Maybe (Step LabelInfo a)
lastStepInPrefix = listToMaybe . trace

-- | Calculate the active labels
activeLabels :: Prefix a -> [LabelInfo]
activeLabels p = nub [l | Enter l <- steps] \\ [l | Exit l <- steps]
   where
      steps = prefixToSteps p