with Ada.Unchecked_Deallocation;

with Text_Io;                           use Text_Io;

package body Libsens.Processing.Plugins is
   
   
   task body Event_Process_Type is
      
      
      type Dated_Message_Type;
      task type Event_Type(Dated_Message : access Dated_Message_Type) is
	 entry Initialize(Device : in Device_Num; Message : in Long; Date : in Time; Hour : in Duration);
	 --entry Exhausted;
      end Event_Type;
      
      
      type Dated_Message_Type is limited
	 record
	    Device_Id : Device_Num := 1;
	    Message : Interfaces.C.Long := 0;
	    Hour    : Duration := 0.0;
	    Date    : Time := Clock;
	    Event   : Event_Type(Dated_Message_Type'Access);
	 end record;
      
      
      
      type Dated_Message_Access is access all Dated_Message_Type;
      
      procedure Free is new Ada.Unchecked_Deallocation(Dated_Message_Type, Dated_Message_Access);
      
      type Dated_Messages_Set is array (Positive range <>) of Dated_Message_Access;
      
      task body Event_Type is
      begin
	 accept Initialize(Device : in Device_Num; Message : in Long; Date : in Time; Hour : in Duration) do
	    Dated_Message.Device_Id := Device;
	    Dated_Message.Message := Message;
	    Dated_Message.Date := Date;
	    Dated_Message.Hour := Hour;
	 end Initialize;
	 delay until Dated_Message.Date + Dated_Message.Hour;
	 --  if Driver.Instruments = null then
	 --     --Put_Line("Event :: no instruments");	    
	 --  end if;
	 --  --Put_Line("Event :: send to device id =" & Device_Num'Image(dated_Message.Device_Id));
	 --  if Driver.Instruments.Orchester(Instrument_Id(Dated_Message.Device_Id)) = null then
	 --     --Put_Line("Event :: no device");
	 --  elsif Driver.Instruments.Orchester(Instrument_Id(Dated_Message.Device_Id)).Output_Device_Driver = null then
	 --     --Put_Line("Event :: no driver");	 
	 --  else
	 --     --Put_Line("Event :: write to device");
	 Driver.Instruments.Orchester(Instrument_Id(Dated_Message.Device_Id)).Output_Device_Driver.Output_Driver.Receive(Dated_Message.Message);
	 --     --Put_Line("Event :: device received");
	 --  end if;
	 --accept Exhausted;
      end Event_Type;
            
      
      Dated_Buffer : Dated_Messages_Set(1..512);
      Buffer_Last  : Natural := 0;
      End_Of_Task  : Boolean := False;
      
      
   begin
      while not End_Of_Task loop
	 select	       
	    --  when Buffer_Last >= Dated_buffer'Last =>
	    --  	 accept Receive (Device  : in Device_Num;
	    --  			 Date    : in Time;
	    --  			 Message : in Interfaces.C.Long;
	    --  			 Hour    : in Duration;
	    --  			 Tempo   : in Tempo_Type) do
	    
	    --  	    --Put_Line("Event :: Full");
	    --  	 end Receive;
	    --  or
	    when Buffer_Last < Dated_buffer'Last =>
	       accept Receive (Device  : in Device_Num;
			       Date    : in Time;
			       Message : in Interfaces.C.Long;
			       Hour    : in Duration;
			       Tempo   : in Tempo_Type) do
		  
		  --Put_Line("Event :: receive");
		  Dated_Buffer(Buffer_Last+1) := new Dated_Message_Type;
		  --Put_Line("Event :: receive new event");
		  Dated_Buffer(Buffer_Last+1).Event.Initialize(Device, Message, Date, Hour);		     
		  --Put_Line("Event :: receive new event initialized");
		  Buffer_Last := Buffer_Last + 1;
	       end Receive;
	       if Buffer_Last > 0 then
		  --Put_Line("Event :: buffer not empty");		  
	       
		  for Buffer_Iter in 1..(Buffer_Last) loop
		     --Put_Line("Event :: exhaust...");
		     --select 
		     --Dated_Buffer(Buffer_iter).Event.Exhausted;		     		     
		     if Dated_Buffer(Buffer_iter) /= null and then
		       (Dated_Buffer(Buffer_iter).Date +
		       Dated_Buffer(Buffer_iter).Hour) < Clock-0.25 then
			--Put_Line("Event :: exhausted");
			
			Free(Dated_Buffer(Buffer_iter));
			if Buffer_Iter < Buffer_Last then
			   for Rest in Buffer_Iter .. Buffer_Last loop
			      
			      Dated_Buffer(Rest) := Dated_Buffer(Rest + 1);
			   end loop;		
			   
			   Buffer_Last := Buffer_Last - 1;		     		     
			end if;
		     --or
		--	delay 0.005;
			--Put_Line("Event :: wait");
			
		     end if;
		     --end select;		  
		  end loop;		  		  
	       end if;
	       
	 or 
	    accept Halt do		  		  
	       End_Of_Task := True;
	    end Halt;	    	    	    
	 end select;

      end loop;
      Put_Line("Event halted");
   end Event_Process_Type;
   
end Libsens.Processing.Plugins;