module objectsInAgda where

open import Data.Product
open import interactiveProgramsAgda hiding (main)
open import NativeIO
open import Data.String.Base


record Interface  :  Set₁ where
  field  Method   :  Set
         Result   :  (m : Method)  Set

open Interface public

record Object (I : Interface) : Set where
  coinductive
  field objectMethod : (m : Method I)  Result I m × Object I

open Object public
open import Size


record IOObject (Iᵢₒ : IOInterface) (I : Interface) (i : Size) : Set where
  coinductive
  field method : ∀{j : Size< i} (m : Method I)
                    IO Iᵢₒ  (Result I m × IOObject Iᵢₒ I j)

open IOObject public

{- Example Cell -}

data CellMethod A : Set where
    get  :  CellMethod A
    put  :  A  CellMethod A

CellResult             :  ∀{A}  CellMethod A  Set
CellResult   {A} get   =  A
CellResult   (put _)   =  Unit

cellI                  :  (A : Set)  Interface
Method    (cellI A)    =  CellMethod A
Result    (cellI A) m  =  CellResult m


{- A cell as an Object -}

Cell : Set  Set
Cell A = Object (cellI A)

cell : {A : Set}  A  Cell A
objectMethod (cell a) get       = a    , cell a
objectMethod (cell a) (put a')  = unit , cell a'




{- A cell as an IOObject -}

CellC : (i : Size)  Set
CellC = IOObject ConsoleInterface (cellI String)


simpleCell : ∀{i} (s : String)  CellC i
force (method (simpleCell s)  get) =
  do' (putStrLn ("getting (" ++ s ++ ")")) λ _ 
  return (s , simpleCell s)
force (method (simpleCell _) (put s)) =
  do' (putStrLn ("putting (" ++ s ++ ")")) λ _ 
  return (_ , simpleCell s)


program : ∀{i}  CellC    IO ConsoleInterface i Unit
force (program c) =
  do' getLine          λ s 
  method c (put s)    >>= λ{ (_ , c) 
  method c get        >>= λ{ (s' , c) 
  do (putStrLn s')     λ _ 
  program c }}


main : NativeIO Unit
main = translateIOConsole (program (simpleCell "Start"))