{-# OPTIONS -XOverlappingInstances
            -XTypeSynonymInstances
            -XFlexibleInstances
            -XUndecidableInstances
            -XOverloadedStrings
            -XNoMonomorphismRestriction
              #-}
module Data.RefSerialize.Serialize where
import GHC.Exts
import Unsafe.Coerce
import Data.List(isPrefixOf,insertBy,elem)
import Data.Char(isAlpha,isAlphaNum,isSpace,isUpper)

import System.Mem.StableName
import System.IO.Unsafe
import Control.Monad (MonadPlus(..))
import Data.ByteString.Lazy.Char8 as B
import qualified Data.HashTable  as HT
import Data.List(sortBy)
import Data.Ord


type MFun=  Char -- usafeCoherced to char to store simply the address of the function
type VarName = String
type ShowF= ByteString
type Context =  HT.HashTable Int (  StableName MFun, MFun,ShowF)

data Error= Error String
data Stat= Stat (Context, ByteString, ByteString)


-- HT to map
empty  =   HT.new (==) HT.hashInt

assocs = sortBy (comparing fst) . unsafePerformIO . HT.toList

insert  k v ht= unsafePerformIO $ HT.insert ht k v >> return ht

lookup  k ht= unsafePerformIO $ HT.lookup ht k

toList  = unsafePerformIO . HT.toList

fromList = unsafePerformIO . HT.fromList HT.hashInt


readContext :: ByteString -> ByteString -> (ByteString, ByteString)
readContext pattern str= readContext1  (pack "") str where

 readContext1 :: ByteString -> ByteString -> (ByteString, ByteString)
 readContext1 s str| B.null str = (s, pack "")
                   | pattern `B.isPrefixOf` str = (s, B.drop n str)
                   | otherwise=   readContext1 (snoc s (B.head str)) (B.tail str)
                    where n= fromIntegral $ B.length pattern


hasht x= unsafePerformIO $ do
       st <- makeStableName $! x
       return (hashStableName st,unsafeCoerce st)

-- !  two variables that point to the same address will have identical varname (derived from import System.Mem.StableName)varName:: a -> String
varName x= "v"++ (show . hash) x
  where hash x= let (ht,_)= hasht x in ht




numVar :: String -> Int
numVar "" = error "refSerialize: numVar: null variable"
numVar var= read  $ Prelude.tail var