with Libsens.MIDI.Portmidi;             use Libsens.MIDI.Portmidi;
with Libsens.MIDI.Drivers;              use Libsens.MIDI.Drivers;
with Libsens.MIDI.Messages;             use Libsens.MIDI.Messages;
with Libsens.Virtual.Prgm_change;        use Libsens.Virtual.Prgm_change;

with Libsens.Processing.Common;         use Libsens.Processing.Common;

with Ada.Calendar.Formatting;

with Text_Io;                           use Text_Io;

with Interfaces.C;                      use Interfaces.C;

package body Libsens.Processing.Prgm_Change is
   
   procedure Initialize(Plugin_Process : in Prgm_Change_Processing;Options : in Work_Options_Access) is
   begin
      Plugin_Process.Process.Initialize(Options);
   end Initialize;   
   
   
   procedure Start(Plugin_Process : in Prgm_Change_Processing;Start_Time : in Time; Tempo : in Tempo_Type; Signature : in Time_Signature_Type) is
   begin
      Plugin_Process.Process.Start(Start_Time, Tempo, Signature);
   end Start;
   
   procedure Stop(Plugin_Process : in Prgm_Change_Processing) is
   begin
      Plugin_Process.Process.Stop;
   end Stop;
   
   procedure Halt(Plugin_Process : in Prgm_Change_Processing) is
   begin
      Plugin_Process.Process.Halt;
   end Halt;
   
   
   task body Prgm_Change_Process is      
      
      
      Start_Time  : Time := Clock;
      Quantum     : Duration := 0.0;
      
      Tempo : Tempo_Type := 120.0;	 
      Date      : Time := Clock;
      
      End_Of_Task : Boolean := False;
      Bar_Beat : Bar_Beat_Type;
      Signature : Time_Signature_Type := (4, 4);
      
      Current_Form : Form_Index_Type := 1;
      Current_Break    : Break_Type := Down_Break;
      Prev_Break       : Break_Type := Null_Break;	 
      Next_Break       : Break_Type := Down_Break;
      


      
      Options : access Work_Options_Record;
      
      Bars_Max : Positive := 1;
      
   begin
      while not End_Of_Task loop
	 loop
	    select
	       accept Initialize(Options : in Work_Options_Access) do
		  Put_Line("Plugin id : " &
			     Plugin_Num'Image(Prgm_Change.Plugin.Id) &
			     " ready for process " &
			     Plugin_Enum'Image(Prgm_Change.Plugin.Class));
		  Prgm_Change_Process.Options := Options;
	       end Initialize;
	    or
	       
	       accept Start(Start_Time : in Time; Tempo : in Tempo_Type; Signature : in Time_Signature_Type) do
		  Quantum :=  Duration(60000.0/Float(Tempo))/Signature.Unit/1000.0;
		  Prgm_Change_Process.Tempo := Tempo;
		  Prgm_Change_Process.Signature := Signature;
		  Prgm_Change_Process.Options := Options;
		  Bar_Beat := (1, 1, 1);
		  Prgm_Change_Process.Start_Time := Start_Time;		  
		  Bars_Max := Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).Bars_Max;
	       end Start;
	       exit;
	    or
	       accept  Stop;
	    or
	       accept Halt;
	       End_Of_Task := True;
	       exit;
	    end select;
	 end loop;
	 --Put_Line("Prgm_Change started ::= MIMI 0.1.0");
	 while not End_Of_Task loop
	    select
	       accept Initialize(Options : in Work_Options_Access);
	    or
	       accept Start(Start_Time : in Time; Tempo : in Tempo_Type; Signature : in Time_Signature_Type) do
		  Quantum :=  Duration(60000.0/Float(Tempo))/Signature.Unit/1000.0;
		  Prgm_Change_Process.Tempo := Tempo;
		  Prgm_Change_Process.Signature := Signature;		  
		  
		  Bars_Max := Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).Bars_Max;
	       end Start;
	    or
	       accept  Stop;
	       exit;
	    or
	       accept Halt;
	       End_Of_Task := True;
	       exit;
	    or
	       delay until Start_Time;
	       --Put_Line("Prgm_Change started ::= MIMI 0.1.1");
	       --if current_form = Prgm_Change.plugin.played_form then
	       --  if Prgm_Change.Plugin.Algo = Null_Algo then
	       if (not Prgm_Change.plugin.mutted) 
		 and is_formed(Options.true_table,			       
			       Prgm_Change.Plugin.Cat_id, 
			       Options.Prev_Break, 
			       Options.Next_Break) then
		  --Put_Line("Prgm change started ::= MIMI 0.1.2");
		  for voice_id in Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer'Range loop
				     
		     
		     if bar_beat.bar = Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).Sequencer(voice_id).bar then
			
			if (Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).Sequencer(voice_id).number = bar_beat.time_number) and
			  (Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).Sequencer(voice_id).step = bar_beat.time_unit) then
			   
			   
			   
			   if Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).played then
			      
			      --Put_Line("tutu 1.3");
			      declare
				 
				 date : time := start_time;
				 				   
				 P_Change  : Long := To_Long(Program_Change(Channel_Type(Prgm_Change.plugin.Ch_Id-1), 
												 Long(Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).Prgm_Num)));
				 
				 
				 
									 
				 
			      begin
				 --Put_Line("tutu 1.4");
				 if Prgm_Change.plugin.printed then
				    --Put_Line("tutu 1.4.1");
				    declare				       
				       printed_message : constant printed_message_access := new printed_message_type '
					 (source => new string ' (Positive'image(Positive(Prgm_Change.plugin.id))),
					  destination => new string ' (Positive'Image(Positive(Prgm_Change.plugin.device_id))),
					  data_type => new string ' (control_type'image(control_of(P_Change))),
					  channel => new string ' (channel_type'image(channel_of(P_change))),
					  data1 => new string ' (interfaces.c.long'image(data1(P_Change))),
					  data2 => new string ' (interfaces.c.long'image(data2(P_Change))),
					  hour => new string ' (formatting.image(date, true)),
					  hexa_sum => new string ' (hex_image(P_Change)),
					  long_sum => new string ' (long'image(P_Change)));
				    begin
				       --Put_Line("tutu 1.4.1.0");
				       --print(printed_message.all);
				       
				       Prgm_Change.box.receive(printed_message);
				       --Put_Line("messages sended to message box");
				       
				    end;
				    --Put_Line("tutu 1.4.2");
				    --Put_Line("tutu 1.4.3");
				 end if;
				 --Put_Line("tutu 1.5");
				 
				 Prgm_Change.Event_Process.Receive(Prgm_Change.plugin.Device_Id, date, P_Change, 0.0, tempo);
				 --Put_Line("tutu 1.6");
				 --Put_Line("tutu 1.7");
			      end;
			   end if;
			   
			end if; 
			
		     elsif Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).in_loop and then
		       (((bar_beat.bar-1) mod bars_max)+1 = Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).bar) then
			
			
			if (Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).number = bar_beat.time_number) and
			  (Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).step = bar_beat.time_unit) then
			   
			   
			   if Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).played then
			      
			      
			      --Put_Line("tatata 1.3");
			      declare
				 
				 date : time := start_time;
				 P_Change  : Long := To_Long(Program_Change(Channel_Type(Prgm_Change.plugin.Ch_Id-1), 
												 Long(Prgm_Change_Plugin_Record(Prgm_Change.Plugin.all).sequencer(voice_id).Prgm_Num)));
									 begin
				 --Put_Line("tatata 1.4");
				 if Prgm_Change.plugin.printed then
				    --Put_Line("tatata 1.4.1");
				    declare				       
				       printed_message : constant printed_message_access := new printed_message_type '
					 (source => new string ' (Positive'image(Positive(Prgm_Change.plugin.id))),
					  destination => new string ' (Positive'Image(Positive(Prgm_Change.plugin.device_id))),
					  data_type => new string ' (control_type'image(control_of(P_Change))),
					  channel => new string ' (channel_type'image(channel_of(P_Change))),
					  data1 => new string ' (interfaces.c.long'image(data1(P_Change))),
					  data2 => new string ' (interfaces.c.long'image(data2(P_Change))),
					  hour => new string ' (formatting.image(date, true)),
					  hexa_sum => new string ' (hex_image(P_Change)),
					  long_sum => new string ' (long'image(P_Change)));
				    begin
				       --Put_Line("tatata 1.4.1.0");
				       --print(printed_message.all);
				       
				       Prgm_Change.box.receive(printed_message);
				       --Put_Line("messages sended to message box");
				       
				    end;
				    --Put_Line("tatata 1.4.2");
				    
				    --Put_Line("tatata 1.4.3");
				 end if;
				 --Put_Line("tatata 1.5");				       
				 Prgm_Change.Event_Process.Receive(Prgm_Change.plugin.Device_Id, date, P_Change, 0.0, tempo);
				 --Put_Line("tatata 1.6");				 
				 --Put_Line("tatata 1.7");
			      end;
			      
			   end if;
			end if;
		     end if;
		  end loop;		  
		  start_time := start_time + Quantum;
		  --Put_Line("tatata 3");		     		     
	       else
		  start_time := start_time + Quantum;
	       end if;
	       -- end if;
	       --   end if;
	       --Put_Line("Prgm_Change started ::= MIMI 0.1.275");
	    end select;	    
	    Next(bar_beat, Options.Track_length, signature.number, signature.unit);		  
	    start_time := start_time + quantum;	    
	    --Put_Line("Prgm_Change started ::= MIMI 0.1.276");
	 end loop;
      end loop;
   end Prgm_Change_Process;
   
end Libsens.Processing.Prgm_Change;