module Igor2.Data.HypoSpace (

    HSpace, initHSpace, emptyHSpace, 
    countHypos, isEmpty,
    pushHypo, pushHypos, popHypos,
    
    module Igor2.Data.Hypotheses
    
   

) where

import Prelude hiding ((<$>))

import qualified Data.BagHeap as H
import Igor2.Data.Rateable
import Igor2.Data.Hypotheses
import Igor2.Data.IOData

import Syntax.Context
import Igor2.Logging
import Igor2.Ppr

import Control.Arrow ( (***), first, second )
import Control.Monad.Error
import Data.Maybe (mapMaybe)
import Data.List (delete)
import qualified Data.Foldable as F

data HSpace = HS { cntr :: !Int
                 , heap :: H.BagHeap RatingData Hypo}
                 
isEmpty :: HSpace -> Bool
isEmpty = H.isEmpty . heap
 
 -- | /O(1)/, create an empty Search Space
emptyHSpace :: HSpace
emptyHSpace = HS 
    { cntr   = 0
    , heap   = H.empty
    }
    
countHypos :: HSpace -> Int  
countHypos = cntr      
 
-- | /O(1)/, initialise a search space with a 'CovrRule' as inital hypothese
initHSpace :: (MonadPlus m) => CovrRule -> C m HSpace
initHSpace r = liftM (pushHypo emptyHSpace) $ hypo [r]

pushHypo :: HSpace -> Hypo -> HSpace
pushHypo hs h = incCntr $ pushUnsafe hs h

pushHypos :: [Hypo] -> HSpace -> HSpace
pushHypos h hsp  = foldl pushHypo hsp h

popHypos :: HSpace -> ([Hypo],HSpace)
popHypos = (\(hl,hs) -> (hl, decCntrBy (length hl) hs)) . popUnsafe


--------------------------------------------------------------------------------
-- Unsafe helpers
--------------------------------------------------------------------------------

incCntrBy:: Int -> HSpace -> HSpace
incCntrBy i (HS c hp) = HS (c+i) hp

incCntr = incCntrBy 1

decCntrBy :: Int -> HSpace  -> HSpace
decCntrBy i (HS c hp) = HS (c-i) hp

decCntr = decCntrBy 1

pushUnsafe :: HSpace -> Hypo -> HSpace
pushUnsafe (HS c hp) h = HS c (H.insert (rating h) h hp)     

popUnsafe :: HSpace -> ([Hypo],HSpace)
popUnsafe (HS c hp) = ( snd *** (HS c) ) . H.getDelMin $ hp

  
{- ---------------------------------------------------------------------------
-- | Show instances and pretty printing stuff
----------------------------------------------------------------------------- -}
  

instance Show HSpace where
        show = show.pretty            
instance Pretty HSpace where
        pretty hsp = text "HSPACE" <$>
                     parens ( indent 2 $ 
                        text "Total Hypos:"     <+> (int.countHypos $ hsp) <$>
                        text "Rating -> Hypo:" <^> indent 2 (vcat . map pretty . H.elems . heap $ hsp)
--                        text "Rating -> HypoID:" <^> pretty (rateIdsMap hsp) <$>
--                        text "Rule   -> HypoID:" <^> pretty (ruleIdsMap hsp) <$>
--                        text "ID     -> Hypo:  " <$> pretty (hypoIdBimap hsp)
                     )        
 