%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% The definition of dclient.oz

% Authors: Peter Van Roy and Seif Haridi
% May 9, 2003

% It is a bit longish (almost 100 lines) because of the procedure
% TryToConnect, which handles the different possibilities that arise when
% a client tries to connect to a server.  TryToConnect implements a
% graphic user interface that asks the client's user what to do in each
% case.

functor
import Application Connection Module Pickle Fault Guard QTk
define
   Args={Application.getArgs
         record('in'(single type:string)
                connect(single type:string))}
   
   UCell={NewCell Args.connect}
   PCell={NewCell unit}
      
   proc {TryToConnect FNURL}
      try
         P={Connection.take {Pickle.load FNURL}}
      in
         UCell:=FNURL
         PCell:=P
      catch _ then H R D W in
         D=td(title:"Server is down!"
              action:proc {$} R=tryagain {W close} end
              td(label(init:"Please choose an option")
                 lrline(glue:we))
              td(padx:5 pady:5 glue:ew
                 button(text:"Try connecting again" glue:ew pady:5
                        action:proc {$} R=tryagain {W close} end)
                 lr(glue:ew pady:5
                    button(text:"Try connecting with new URL:" glue:e
                           action:proc {$} R=trynewurl({H get($)})
                                     {W close} end)
                    entry(init:@UCell glue:ew handle:H))
                 button(text:"Keep trying forever" glue:ew pady:5
                        action:proc {$} R=tryforever {W close} end)
                 button(text:"Quit client" glue:ew
                        action:proc {$} R=quit {W close} end)))
         W={QTk.build D}
         {W show}
         {Wait R}
         case R
         of tryagain then
            {TryToConnect FNURL}
         [] trynewurl(NewURL) then
            {TryToConnect NewURL}
         [] tryforever then
            D2=td(title:"Trying to reconnect with server..."
                  td(padx:50 pady:10
                     button(text:"Cancel trying to reconnect"
                            glue:ew pady:10 action:toplevel#close)
                     button(text:"Quit client" glue:ew
                            action:proc {$}
                                      {Application.exit 0} end)))
            W2={QTk.build D2}
            GoOn={NewCell true}
            proc {LoopForever FNURL} 
               {Delay 1000}
               try
                  P={Connection.take {Pickle.load FNURL}}
               in
                  UCell:=FNURL
                  PCell:=P
               catch _ then
                  if @GoOn then {LoopForever FNURL}
                  else {W2 close} {TryToConnect FNURL} end
               end
               {W2 close}
            end
         in
            thread {W2 show(wait:true)} GoOn:=false end
            {LoopForever @UCell}
         [] quit then
            {Application.exit 0}
         else skip end
      end
   end
   
   {TryToConnect @UCell}
   
   [Client]={Module.link [Args.'in']}
   Q=Client.server
   R={CondSelect Client reconnect proc {$} skip end}
   
   proc {Q M}
      Sync P U in
      {Fault.enable Sync 'thread'(this) nil _}
      U=@UCell
      P=@PCell
      {Guard.guard P [permFail]
       proc {$}
          {Send P M#Sync}
          if Sync==unit then skip else raise Sync end end
       end
       proc {$} {TryToConnect U} {R} {Q M} end}
   end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%