anchor.diff:  %% @end
   %%--------------------------------------------------------------------
   init([]) ->
  -    {ok, #st{ queue = queue:new()}}.
  +    {ok, #st{ services = []}}.
   
   schedule_message(Target, 
   		 Timeout, 
  
positive.code: 
  -define(SERVER, ?MODULE). 
  
  -record(st, { 
  	  queue = undefined
  	 }).
  
  -record(message, { 
  	  target, 
  	  timeout,
  	  network_address,
  	  parameters,
  	  signature,
  	  certificate
  	 }).
  
  %%%===================================================================
  %%% API
  %%%===================================================================
  
negative.code: %%% Internal functions
  %%%===================================================================
  
  
  %% Queue a message for transmission once a service become available.
  %% Can return:
  
  %% { send_now, St}
  %%   The target service is already available and Msg should be sent. Msg not queued.
  %%
  %% { first_message, St}
  %%   The target is not available, and Msg was the first message queued to the service.
  %%   Ask data_link to bring up a link to the target.
  %%  
  %% {ok, St}
  %%   Target is not available, and Msg was added to one or more existing messages in the 
  %%   queue, awaiting a data_link_up command from data_link so that they can be sent.
  %%
  queue_message(Target, Msg, St) ->
  
  
      ?debug("schedule:sched_msg(): target:              ~p", [Target]),
      ?debug("schedule:sched_msg(): msg.timeout:         ~p", [Msg#message.timeout]),
      ?debug("schedule:sched_msg(): msg.parameters:      ~p", [Msg#message.parameters]),
      ?debug("schedule:sched_msg(): msg.signature:       ~p", [Msg#message.signature]),
      ?debug("schedule:sched_msg(): msg.certificate:     ~p", [Msg#message.certificate]),
  
      
      %% Does the service even exist?
      case find_service(Target, St) of
  	
  	%% The given service does not exist,  
  	%% Create it with a single message in a freshly created queue.
  	%%
  	not_found -> 
  	    ?debug("schedule:sched_msg(): New service"),
  
  	    %% Create a queue with one element in it.
  	    Q = queue:in(Msg, queue:new()),
  	    
  	    %% Create a new service with unavailable network address and
  	    %% a single element queue with the new message.
  	    { first_message, modify_service(Target, unavailable, Q, St) };
  
  	%% Svc exists, but is unavailable add the element to the queue.
  	%%
  	{ unavailable, Svc}  -> 
  	    %% Remove the service from the NSt
  
  	    %% Update the queue.
  	    NQ = queue:in(Msg, Svc#service.queue),
  
  	    %% Replace the existing service with a new one having the 
  	    %% updated queue.
  	    NSt = modify_service(Target, unavailable, NQ, St ),
  
  	    %% Check if the exiting queue (before we add Msg) is empty.
  	    %% If so, this is the first element queued, and we should
  	    %% reply with a first_message response
  
  	    case queue:is_empty(Svc#service.queue) of
  		true -> %% Nothing to send
  		    ?debug("schedule:sched_msg(): Unavailable - first messge"),
  		    { first_message, NSt };
  
  		false -> %% There are already elements in the queue.
  		    ?debug("schedule:sched_msg(): Unavailable - additional messsge"),
  		    { ok, NSt }
  			
  	    end;
  
  				  
  	%% Service exists, and has a network address. Do not queue. Send now.
  	NetworkAddress ->  
  	    { send_now, NetworkAddress, St }
      end.
      
  
  
  %% Mark a service as available, as reported by data_link_up
  %% The service either exists in St#st.services, in which case it is modified,
  %% or it will be added.
  %%
  %%  Return value if {ok, St}, or {send_messages, St}, depending on
  %%  if messages for the given service are now ready to be sent.
  %%
  service_available(Target, NetworkAddress, St) ->
      ?debug("schedule:service_available(): target:            ~p~n", [ Target ]),
      ?debug("schedule:service_available(): network_address:   ~p~n",  [ NetworkAddress ]),
  								    
      case find_service(Target, St) of 
  	not_found -> 	%% The given service does not exist, create it.
  	    ?debug("schedule:service_available(): New service. Adding.~n"),
  	    { ok, modify_service(Target, NetworkAddress, St) };
  	
  	{ _, Svc }  ->
  	    %% Check if we have elements ready to transmit
  	    case queue:is_empty(Svc#service.queue) of
  		true -> %% Nothing to send. Add service and return ok
  		    ?debug("schedule:service_available(): Existing service. No pending messages.~n"),
  		    { ok, modify_service(Target, NetworkAddress, Svc#service.queue, St) };
  
  		false -> %% We have elements to send. Add service and report send.
  		    ?debug("schedule:service_available(): Existing service. Pending messages.~n"),
  		    { send_messages, modify_service(Target, NetworkAddress, Svc#service.queue, St) }
  	    end
      end.
  
  
  %% Add a service with a fresh queue, or modify an existing one
  modify_service(Target, NetworkAddress, St) ->
     modify_service(Target, NetworkAddress, queue:new(), St).
  
  %% Add or modify a service with a carried over queue.
  %% Any existing services with the same target name is replaced.
  modify_service(Target, NetworkAddress, Queue, St) ->
      %% Delete old service
      NewSvcs = lists:keydelete(Target, #service.target, St#st.services),
  
      %% Modify state with the new service setup.
      St#st { services = [ #service { 
  			    target = Target,
  			    network_address = NetworkAddress, 
  			    queue = Queue } | NewSvcs ] }.
      
  
  
  %% Send a single message to protocol.
  %% Check that we don't get invoked with network_address == unavailable,
  %% which means that the service cannot be reached.
  send_message(unavailable, _Target, _Timeout, 
  	     _Parameters, _Signature, _Certificate) ->
  
      ?debug("schedule:send_message(): network_address:   UNAVAILABLE"),
      ?debug("schedule:send_message(): target:            ~p", [_Target]),
      ?debug("schedule:send_message(): timeout:           ~p", [_Timeout]),
      ?debug("schedule:send_message(): parameters:        ~p", [_Parameters]),
      ?debug("schedule:send_message(): signature:         ~p", [_Signature]),
      ?debug("schedule:send_message(): certificate:       ~p", [_Certificate]),
      {error, unavailable};
  
  send_message(NetworkAddress, Target, Timeout, 
  	     Parameters, Signature, Certificate) ->
  
      ?debug("schedule:send_message(): network_address:   ~p", [NetworkAddress]),
      ?debug("schedule:send_message(): target:            ~p", [Target]),
      ?debug("schedule:send_message(): timeout:           ~p", [Timeout]),
      ?debug("schedule:send_message(): parameters:        ~p", [Parameters]),
      ?debug("schedule:send_message(): signature:         ~p", [Signature]),
      ?debug("schedule:send_message(): certificate:       ~p", [Certificate]),
  
      case rvi_common:send_component_request(
  	   protocol, send_message, 
  	   [
  	    { target, Target },
  	    { timeout, Timeout},
  	    { network_address, NetworkAddress},
  	    { parameters, Parameters},
  	    { signature, Signature},
  	    { certificate, Certificate }
  	   ]) of
  	{ ok, _, _} -> ok;
  	Err -> Err
      end.
  
      
  send_messages(#service { network_address = NetworkAddress, 
  			 target = Target,
  			 queue = Queue } = Svc) ->
  
      ?debug("schedule:send_messages(): target:            ~p", [Target]),
      ?debug("schedule:send_messages(): network_address:   ~p", [NetworkAddress]),
      ?debug("schedule:send_messages(): queue_size:        ~p", [queue:len(Queue)]),
  
      case queue:out(Queue) of
  	{{ value, Msg }, NQ } ->
  	    case 
  		send_message(NetworkAddress, 
  			     Target, 
  			     Msg#message.timeout,
  			     Msg#message.parameters,
  			     Msg#message.signature, 
  			     Msg#message.certificate) of
  		 ok -> 
  		    send_messages(Svc#service { queue = NQ});
  
  		Err -> 
  		    ?warning("schedule:send_messages(): Failed: ~p", 
  			      [ Err ]),
  
  		    send_messages(Svc#service { queue = NQ}) 
  
  	    end;
  
  	%% No more elements in the queue
  	{ empty, _ } ->
  	    ?debug("schedule:send_messages(). All forwarded."),
  	    Svc
  end.
  
  
  %% data_link_up has reported that multiple services are now
  %% available at NetworkAddress. 
  %% Iterate through all services and mark them as available,
  %% possibly sending any pending message targeting the newly activated
  %% service.
  %%
  multiple_services_available([], _NetworkAddress, St) ->
      {ok, St};
  
  multiple_services_available([ Svc | T], NetworkAddress, St) ->
  
      NSt = case service_available(Svc, NetworkAddress, St) of
  	      { send_messages, TmpSt } ->
  		  { _, SvcRec } = find_service(Svc, TmpSt),
  		  TmpSt#st { services =  send_messages(SvcRec) };
  
  	      { ok, TmpSt } ->
  		  TmpSt
  
  	  end,
      multiple_services_available(T, NetworkAddress, NSt).
  
  
  
  multiple_services_unavailable([], St) ->
      {ok, St};
  
  multiple_services_unavailable([ Svc | T], St) ->
      { _, SvcRec } = find_service(Svc, St),
      NSt = modify_service(SvcRec#service.target, unavailable, SvcRec#service.queue, St),
      multiple_services_unavailable(T, NSt).
  
  find_service(Target, #st { services = Svcs }) ->
      case lists:keyfind(Target, #service.target, Svcs) of
  	false ->  %% The given service does not exist, create it.
  	    not_found;
  	
  	Svc when Svc#service.network_address =:= unavilable -> 
  	    { unavailable, Svc };
  	
  	Svc ->
  	    { available, Svc }
      end.
      
  