{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, OverloadedStrings, CPP, ScopedTypeVariables #-}
module GHCJS.HPlay.Cell(Cell(..),boxCell,bcell,(.=),get,mkscell,scell, gcell, calc) where
import Transient.Internals
import Transient.Move
import GHCJS.HPlay.View
import Data.Typeable
import Unsafe.Coerce
import qualified Data.Map as M hiding ((!))
import Control.Monad.State hiding (get)
import Control.Monad
import Data.Monoid
import Data.List
import Control.Exception
import Data.IORef
import System.IO.Unsafe
#ifdef ghcjs_HOST_OS
import Data.JSString hiding (empty)
#else
#endif
data Cell a = Cell { mk :: Maybe a -> Widget a
, setter :: a -> IO ()
, getter :: IO (Maybe a)}
bcell :: (Show a, Read a, Typeable a) =>TransIO (Cell a)
bcell= genNewId >>= return . boxCell
boxCell :: (Show a, Read a, Typeable a) => ElemID -> Cell a
boxCell id = Cell{ mk= \mv -> getParam (Just id) "text" mv
, setter= \x -> do
me <- elemById id
case me of
Just e -> setProp e "value" (toJSString $ show1 x)
Nothing -> return ()
, getter= getID id}
getID id = withElem id $ \e -> do
ms <- getValue e
case ms of
Nothing -> return Nothing
Just s -> return $ read1 s
where
read1 s=
if typeOf(typeIO getID) /= typestring
then case readsPrec 0 s of
[(v,_)] -> v `seq` Just v
_ -> Nothing
else Just $ unsafeCoerce s
typeIO :: (ElemID -> IO (Maybe a)) -> a
typeIO = undefined
typestring :: TypeRep
typestring= typeOf (undefined :: String)
show1 :: (Show a, Typeable a) => a -> String
show1 x= if typeOf x== typestring
then unsafeCoerce x
else show x
instance Attributable (Cell a) where
(Cell mk setter getter) ! atr = Cell (\ma -> mk ma ! atr) setter getter
(.=) :: MonadIO m => Cell a -> a -> m ()
(.=) cell x = liftIO $ (setter cell ) x
get cell = Transient $ liftIO (getter cell)
infixr 0 .=
gcell :: JSString -> Cloud Double
gcell n= loggedc $ do
vars <- getCloudState rvars <|> return M.empty
localIO $ print ("gcell", n)
case M.lookup n vars of
Just exp -> do inc ; exp !> "executing exp"
Nothing -> error $ "cell not found: " ++ show n
where
inc = do
Tries tries maxtries <- getCloudState rtries <|> error "no tries"
localIO $ print tries
if tries <= maxtries
then localIO $ writeIORef rtries $ Tries (tries+1) maxtries
else local $ do
back Loop
data Loop= Loop deriving (Show,Typeable)
instance Exception Loop
type Expr a = Cloud a
data Tries= Tries Int Int deriving Typeable
rtries= unsafePerformIO $ newIORef $ Tries 0 0
rexprs :: IORef (M.Map JSString (Expr Double))
rexprs= unsafePerformIO $ newIORef M.empty
rvars :: IORef (M.Map JSString (Expr Double))
rvars= unsafePerformIO $ newIORef M.empty
rmodified :: IORef (M.Map JSString ( Double))
rmodified= unsafePerformIO $ newIORef M.empty
mkscell :: JSString -> Expr Double -> Cloud (Cell Double)
mkscell name expr= do
exprs <- onAll $ liftIO (readIORef rexprs) <|> return ( M.empty)
onAll $ liftIO $ writeIORef rexprs $ M.insert name expr exprs
return $ scell name expr
scell :: JSString -> Expr Double -> Cell Double
scell id expr= Cell{ mk= \mv -> Widget $ do
r <- norender $ getParam (Just id) "text" mv `fire` OnChange
mod <- liftIO (readIORef rmodified) <|> return( M.empty)
liftIO $ writeIORef rmodified $ M.insert id r mod
return r
, setter= \x -> withElem id $ \e -> setProp e "value" (toJSString $ show1 x)
, getter= getID id}
calc :: Cloud ()
calc= do
mod <- localIO $ readIORef rmodified
onAll $ liftIO $ print ("LENGTH MOD", M.size mod)
onAll $ liftIO $ print "setCloudState modified"
setCloudState rmodified mod
exprs <- getCloudState rexprs
onAll $ liftIO $ print "setCloudState exprs"
setCloudState rexprs exprs
onAll $ liftIO $ print "setCloudState rvars"
setCloudState rvars M.empty
onAll $ return() `onBack` (\(e::Loop) -> runCloud' $ do localIO $ print "REMOVEVAR"; removeVar e; local (forward Loop) )
exprs <- getCloudState rexprs <|> error "no exprs"
onAll $ liftIO $ print "setCloudState rtries"
setCloudState rtries $ Tries 0 $ 3 * (M.size $ exprs)
nvs <- getCloudState rmodified <|> error "no modified"
onAll $ liftIO $ print ("LENGTH NVS", M.size nvs)
when (not $ M.null nvs) $ calc1
onAll $ liftIO $ print "setCloudState modified"
setCloudState rmodified M.empty
where
calc1= do
return () !> "CALC1"
cells <- getCloudState rexprs <|> error "no exprs"
nvs <- getCloudState rmodified <|> error "no modified2"
onAll $ liftIO $ print "setCloudState vars"
setCloudState rvars $ M.union (M.map return nvs) cells
solve
solve = do
vars <- getCloudState rvars <|> error "no vars"
onAll $ liftIO $ print $ ("LENGHT VARS", M.size vars)
mapM_ (solve1 vars) $ M.toList vars
where
solve1 vars (k,f)= do
localIO $ print ("solve1",k)
x <- f
localIO $ print ("setcloudstate var",k,x)
local $ boxCell k .= x
setCloudState rvars $ M.insert k (return x) vars
return ()
setCloudState r v= allNodes $ writeIORef r v
getCloudState r= onAll . liftIO $ readIORef r
removeVar = \(e:: Loop) -> do
nvs <- getCloudState rmodified <|> error "no modified 3"
exprs <- getCloudState rexprs <|> error " no Exprs2"
case M.keys exprs \\ M.keys nvs of
[] -> error "non solvable circularity in cell dependencies"
(name:_) -> do
localIO $ print ("removeVar",name)
mv <- localIO $ getID name
case mv of
Nothing -> return ()
Just v -> do
onAll $ liftIO $ print "setCloudState modified"
setCloudState rmodified $ M.insert name v nvs
return ()
allNodes :: IO () -> Cloud ()
allNodes mx= loggedc $ (localIO mx) <> (atRemote $ (localIO $ print "UPDATE" >> mx))