content: -- | example of runtime templates, storage and query by using tcache
  {-# OPTIONS -XDeriveDataTypeable -XNoMonomorphismRestriction  -XCPP #-}
  module RuntimeTemplates where
  import Data.TCache.DefaultPersistence
  import Data.TCache.IndexQuery
  import Control.Workflow.Configuration
  import Data.Typeable
  import Data.Monoid
  import Data.ByteString.Lazy.Char8 as BS hiding (index)
  import Control.Exception(SomeException)
  import Control.Monad (when)
  
  -- #define ALONE -- to execute it alone, uncomment this
  
  -- Note:  there are static links in templates in the main menu. unless they
  -- are updated using  witerate/dField, the main menu of this example will not
  -- work when the app run alone since the expected paths are different.
  #ifdef ALONE
  import MFlow.Wai.Blaze.Html.All  hiding(name,select,base)
  import Debug.Trace
  (!>) = flip trace
  main= runNavigation "" $ transientNav runtimeTemplates
  #else
  import MFlow.Wai.Blaze.Html.All hiding(name,select,base, page)
  import Menu
  #endif
  
  
  
  data  MyData= MyData{name :: String} deriving (Typeable,Read, Show)  
  
  instance Indexable MyData where  key=  name     -- just to notify what is the key of the register
  
  instance Serializable MyData where    -- default persistence
     serialize=  pack . show
     deserialize=   read . unpack
     setPersist =   \_ -> Just filePersist      --  in files
  
  data Options= NewName | ListNames  | Exit deriving (Show, Typeable,Eq)
  
  newtype NextReg = NextReg Int deriving Typeable
  
  runtimeTemplates= do
       -- runConfiguration is usedd to create some example registers
       liftIO $ runConfiguration "createDataforTemplates" $ do
               ever $ index name  -- index the name field, so I can query  for it later
                                  -- better, should put this sentence in main
  
               -- create ['a'..'z'] entries. Only the first time
               -- runConfiguration prevent the execution of this again
               once $ atomically $ mapM_ (newDBRef . MyData . return) ['a'..'z']
       process
  
  process= do
       setSessionData $ NextReg 0  
       r <- page  $  edTemplate "edituser" "menuallnames" 
                  $ wlink NewName   << p << "enter a new name"
                <|> wlink ListNames << p << "List names"
                <|> wlink Exit      << p << "Exit to the home page"
  
       case r of
           Exit -> return()
           NewName -> do
                page  $ edTemplate "edituser" "enterallnames"
                      $ pageFlow "enter"
                      $ witerate (
                              do  noCache
                                  name <- dField (getString Nothing `validate` jsval)
                                          <** submitButton "ok" <++ br
                                  -- store the register in the cache
                                  -- Later will be written by the default persistence automatically
                                  liftIO . atomically . newDBRef $ MyData name   
                          **> do
                               n <- countRegisters
                               dField (wraw $ b << show n) <++ fromStr " registers added ")
                     **> wlink () << b << "exit"
  
           ListNames -> do
                -- query for all the names stored in all the registers
                allnames <- getAllNames
  
                let len= Prelude.length allnames
  
                page $ pageFlow "iter" $ iterateResults allnames len
                   **> wlink "templ" << p << "click here to show the result within a runtime template"
  
                setSessionData $ NextReg 0
                page $ edTemplate "edituser" "listallnames"
                     $ pageFlow "iter" $ iterateResults allnames len
                   **> wlink "scroll" << p << "click here to present the results as a on-demand-filled scroll list"
  
                setSessionData $ NextReg 0
                page $ pageFlow "upd" $ appendUpdate ( do
                            NextReg ind <- getSessionData `onNothing` return (NextReg 0)
                            getData ind     len allnames <++ br
                            getData (ind+1) len allnames <++ br
                            getData (ind+2) len allnames <++ br
                            getData (ind+3) len allnames <++ br
                            setSessionData . NextReg $ next ind len
                            wlink "more" << b << "more" <++ br)
  
                    **> wlink () << p << "click here to go to the menu"
  
       if r == Exit then return() else process
  
       where
       getAllNames= liftIO . atomically $ select name $ name .>.  ""
  
       countRegisters= (getAllNames >>= return . Prelude.length)
  
  
       iterateResults allnames len = witerate $ do
            maxAge 300
            NextReg ind <- getSessionData `onNothing` return (NextReg 0)
            dField(getData  ind    len allnames) <++ br
            dField(getData (ind+1) len allnames) <++ br
            dField(getData (ind+2) len allnames) <++ br
            dField(getData (ind+3) len allnames) <++ br
            r <-    dField (wlink (next ind len) << b << "next" ) <++ fromStr " "
                <|> dField (wlink (prev ind len) << b << "prev")
                <|> restp
            setSessionData $ NextReg r
  
  
       getData i len all=  wraw . fromStr $ if i >= len || i < 0 then "" else all !! i
       next i len = case i > len  of  True -> 0 ; _ -> i + 4
       prev i len = case i < 0 of True -> len; _ -> i - 4
  
       jsval s=
           if Prelude.length s > 10 then do
             return $ Just  $ b << "length must be less than 10 chars"
           else return Nothing
  