/***** Using Typedefs *******/


/** Ex 2.2  **/
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT } in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  } in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT } in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type 
in typedef ret_type = { Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uida, sid), abst:int^A(uida, sid), 
						paper:int^A(uida, sid) ]^BOT } in 

 let viewAuthorPapers = fun uida: int^BOT =>   		
	[ ret_type ]( foreach(x in Submissions) with y = {}: ret_type do 
			    	let tuple = !x in
			    	  if(tuple.uid == uida) then tuple::y else y  ) 
 in let n = 42 in (viewAuthorPapers(n)) ;;

/* Type: { Sigma[uid: int^BOT, sid: int^BOT, title: int^A(42, sid), abst: int^A(42, sid), paper: int^A(42, sid)]^BOT } */






/* Ex 2.3 */

typedef sub_elem = Sigma[uid: int^BOT, sid: int^BOT,  title: int^A(uid,sid), abst:int^A(uid,sid), paper:int^A(uid,sid) ]^BOT in
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT } in
typedef sub_type = { ref (sub_elem )^BOT  } in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT } in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type
in typedef sub = { sub_elem }  

in let viewAssignedPapers = fun uidr: int^BOT =>
	 	( foreach(x in Reviews) with res_x = {}: sub do 
	   		let tuple_rev = !x 
	   		  in if(tuple_rev.uid == uidr ) then 
	   			   ( foreach(y in Submissions) with res_y = {}: sub do 
					   let tuple_sub = !y
	   					in if(tuple_sub.sid == tuple_rev.sid) then tuple_sub::res_y else res_y )   
	   			 else res_x ) 
 
  in let r = first(viewAssignedPapers(42)) in r ;;
	  
/* Type: Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid)]^BOT */
	  
	  
	  
	  
	  
/** Ex 2.4 **/

typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT } in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  } in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT } in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type

in let t = first( 
    ( foreach(x in Submissions) with y = {}: { int^A(42,70) } do 
	   let t_sub = !x in 
	     if(t_sub.uid == 42 and t_sub.sid == 70 ) then t_sub.title::y else y ))
         in foreach(x in Submissions) with y = skip do  
		let t_sub = !x 
	    in if(t_sub.uid == 42 and t_sub.sid == 70) then 
	    	  let new_rec  = [uid: int^BOT = t_sub.uid, sid: int^BOT = t_sub.sid, 
	    		   			  title: int^A(uid, sid) = t, abst: int^A(uid, sid) = t_sub.abst, 
	    		   			  paper: int^A(uid, sid) = t_sub.paper ]
	    	  in x := new_rec ;;


/* Type: cmd^BOT */





/*** negative 2.4 ***/

 
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT } in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  } in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT } in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type

in let t = first( ( foreach(x in Submissions) with y = {}: { int^A(42,70) } do 
	   let t_sub = !x in 
	     if(t_sub.uid == 42 and t_sub.sid == 70 ) then t_sub.title::y else y) ) 
   in foreach(x in Submissions) with y = skip do  
		let t_sub = !x 
	    in if(t_sub.uid == 32) then 
	    	  let new_rec  = [uid: int^BOT = t_sub.uid, sid: int^BOT = t_sub.sid, 
	    		   			  title: int^A(uid, sid) = t, abst: int^A(uid, sid) = t_sub.abst, 
	    		   			  paper: int^A(uid, sid) = t_sub.paper ]
	    	  in x := new_rec ;;


/* Wrong type: Expected declared type Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid)]^BOT but found type Sigma[uid: int^BOT, sid: int^BOT, title: int^A(42, 70), abst: int^A(32, sid), paper: int^A(32, sid)]^BOT
 */







/** example between 2.4 and 2.5 from paper **/

typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  } in

let Submissions  = ref {}: sub_type in

typedef y_type =
   {Sigma[uid : int^BOT, sid : int^BOT, title: int^A(42,sid)]^BOT} in

 foreach (x in !Submissions) with y = {} : y_type do
   let t_sub = !x in
     if (t_sub.uid == 42) then
	[uid : int^BOT = t_sub.uid, sid : int^BOT = t_sub.sid,
	 title : int^A(42,sid) = t_sub.title] :: y
     else y
 ;;


/* Type: { Sigma[uid: int^BOT, sid: int^BOT, title: int^A(42, sid)]^BOT } */







/** Ex 2.5  **/

typedef sub_elem = Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT in
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT } in
typedef sub_type = { ref (sub_elem )^BOT  } in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT } in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type
in typedef sub = { sub_elem }
	   			   
in let viewAssignedPapers = fun uidr: int^BOT =>
	 	( foreach(x in Reviews) with res_x = {}: sub do 
			let tuple_rev = !x 
	   		 in if(tuple_rev.uid == uidr ) then 
	   			  ( foreach(y in Submissions) with res_y = {}: sub do 
					   let tuple_sub = !y
	   					in if(tuple_sub.sid == tuple_rev.sid) then tuple_sub::res_y else res_y ) 
	   			 else res_x  )
	   			 
  in let comment = fun u: int^BOT, s: int^BOT, r: sub_elem =>
	   [ int^A(u,s) ] (if(r.uid == u and r.sid == s) then r.paper else 1) in   
    
    let addCommentSubmission = fun uid_r: int^BOT, sidr: int^BOT =>		
	 	( foreach(p in viewAssignedPapers(uid_r)) with dummy = skip do 
	   	    if(p.sid == sidr ) then 
	   		   ( foreach(y in Reviews) with dummy2 = skip do 
				  let trev = !y in
	   				if(trev.sid == p.sid ) then 
	   				   ( let up_rec = [uid: int^BOT = trev.uid, 
	   								sid: int^BOT = trev.sid, 
									PC_only: int^PC(uid,sid) =  comment(p.uid, p.sid, p), 
	   								review: int^A(TOP, sid) = trev.review, 
	   								grade: int^A(TOP, sid) = trev.grade ] 
	   				   in y := up_rec ) ) )
    in addCommentSubmission;;
 
 
 /* Type: (Pi(uid_r: int^BOT, sidr: int^BOT).BOT; cmd^BOT)^BOT */
 
 
 
 /***  negative 2.5 - sem if no fim **/

typedef sub_elem = Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT in
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT } in
typedef sub_type = { ref (sub_elem )^BOT  } in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT } in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type
in typedef sub = { sub_elem }
	   			   
in let viewAssignedPapers = fun uidr: int^BOT =>
	 	( foreach(x in Reviews) with res_x = {}: sub do 
			let tuple_rev = !x 
	   		 in if(tuple_rev.uid == uidr ) then 
	   			  ( foreach(y in Submissions) with res_y = {}: sub do 
					   let tuple_sub = !y
	   					in if(tuple_sub.sid == tuple_rev.sid) then tuple_sub::res_y else res_y ) 
	   			 else res_x  )
	   			 
  in let comment = fun u: int^BOT, s: int^BOT, r: sub_elem =>
	   [ int^A(u,s) ] (if(r.uid == u and r.sid == s) then r.paper else 1) in   
    
    let addCommentSubmission = fun uid_r: int^BOT, sidr: int^BOT =>		
	 	( foreach(p in viewAssignedPapers(uid_r)) with dummy = skip do 
	   	    if(p.sid == sidr ) then 
	   		   ( foreach(y in Reviews) with dummy2 = skip do 
				  let trev = !y in
	   				   ( let up_rec = [uid: int^BOT = trev.uid, 
	   								sid: int^BOT = trev.sid, 
									PC_only: int^PC(uid,sid) =  comment(p.uid, p.sid, p), 
	   								review: int^A(TOP, sid) = trev.review, 
	   								grade: int^A(TOP, sid) = trev.grade ] 
	   				   in y := up_rec ) ) )
    in addCommentSubmission;;

/* Wrong type: Expected declared type Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT but found type Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^A(TOP, sidr), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT
 */
