with Gmface.Gm_MIDI.Portmidi;             use Gmface.Gm_MIDI.Portmidi;
with Gmface.Gm_MIDI.Drivers;              use Gmface.Gm_MIDI.Drivers;
with Gmface.Gm_MIDI.Messages;             use Gmface.Gm_MIDI.Messages;

with Gmface.Gm_Virtual.Gmface;
use Gmface.Gm_Virtual.Gmface;

with Gmface.Gm_Virtual.Gmface.Gmface_Work;
use Gmface.Gm_Virtual.Gmface.Gmface_Work;

with Gmface.Gm_Virtual.Gmface.Ctrl_Change;
use Gmface.Gm_Virtual.Gmface.Ctrl_Change;

with Gmface.Gm_Processing.Gm_Common;         use Gmface.Gm_Processing.Gm_Common;

with Ada.Calendar.Formatting;

with Text_Io;                           use Text_Io;

with Interfaces.C;                      use Interfaces.C;

package body Gmface.Gm_Processing.Gmface.Gm_Ctrl_Change   is
   
   procedure Initialize(Plugin_Process : in Ctrl_Change_Processing;Options : in Work_Options_Access) is
   begin
      Plugin_Process.Process.Initialize(Options);
   end Initialize;   
   
   
   procedure Start(Plugin_Process : in Ctrl_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 Ctrl_Change_Processing) is
   begin
      Plugin_Process.Process.Stop;
   end Stop;
   
   procedure Halt(Plugin_Process : in Ctrl_Change_Processing) is
   begin
      Plugin_Process.Process.Halt;
   end Halt;
   
   
   task body Ctrl_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(Ctrl_Change.Plugin.Id) &
			     " ready for process " &
			     Plugin_Enum'Image(Ctrl_Change.Plugin.Class));
		  Ctrl_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;
		  Ctrl_Change_Process.Tempo := Tempo;
		  Ctrl_Change_Process.Signature := Signature;
		  
		  Bar_Beat := (1, 1, 1);
		  Ctrl_Change_Process.Start_Time := Start_Time;		  
		  Bars_Max := Ctrl_Change_Plugin_Record(Ctrl_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("Ctrl_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;
		  Ctrl_Change_Process.Tempo := Tempo;
		  Ctrl_Change_Process.Signature := Signature;		  
		  
		  Bars_Max := Ctrl_Change_Plugin_Record(Ctrl_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("Ctrl_Change started ::= MIMI 0.1.1");
	       --if current_form = Ctrl_Change.plugin.played_form then
	       --  if Ctrl_Change.Plugin.Algo = Null_Algo then
	       if (not Ctrl_Change.plugin.mutted) 
		 and is_formed(Options.true_table,			       
			       Ctrl_Change.Plugin.Cat_id, 
			       Options.Prev_Break, 
			       Options.Next_Break) then
		  --Put_Line("Ctrl change started ::= MIMI 0.1.2");
		  for voice_id in Ctrl_change_Plugin_Record(Ctrl_Change.Plugin.all).sequencer'Range loop
		     
		     
		     if bar_beat.bar = Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).Sequencer(voice_id).bar then
			
			if (Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).Sequencer(voice_id).number = bar_beat.time_number) and
			  (Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).Sequencer(voice_id).step = bar_beat.time_unit) then
			   
			   
			   
			   if Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).sequencer(voice_id).played then
			      
			      --Put_Line("tutu 1.3");
			      declare
				 
				 date : time := start_time;
				 
				 Control_Change  : Long := To_Long(Controlcommand(Channel_Type(Ctrl_Change.Plugin.Ch_Id-1), 
										  Long(Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).Sequencer(Voice_Id).Ctrl_Num),
										  Long(Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).Sequencer(Voice_Id).Ctrl_Val)));
				 
				 
				 
				 
			      begin
				 --Put_Line("tutu 1.4");
				 if Ctrl_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(Ctrl_Change.plugin.id))),
					  destination => new string ' (Positive'Image(Positive(Ctrl_Change.plugin.device_id))),
					  data_type => new string ' (control_type'image(control_of(Control_Change))),
					  channel => new string ' (channel_type'image(channel_of(Control_Change))),
					  data1 => new string ' (interfaces.c.long'image(data1(Control_Change))),
					  data2 => new string ' (interfaces.c.long'image(data2(Control_Change))),
					  hour => new string ' (formatting.image(date, true)),
					  hexa_sum => new string ' (hex_image(Control_Change)),
					  long_sum => new string ' (long'image(Control_Change)));
				    begin
				       --Put_Line("tutu 1.4.1.0");
				       --print(printed_message.all);
				       
				       Ctrl_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");
				 
				 Ctrl_Change.Event_Process.Receive(Ctrl_Change.plugin.Device_Id, date, Control_Change, 0.0, tempo);
				 --Put_Line("tutu 1.6");
				 --Put_Line("tutu 1.7");
			      end;
			   end if;
			   
			end if; 
			
		     elsif Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).sequencer(voice_id).in_loop and then
		       (((bar_beat.bar-1) mod bars_max)+1 = Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).sequencer(voice_id).bar) then
			
			
			if (Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).sequencer(voice_id).number = bar_beat.time_number) and
			  (Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).sequencer(voice_id).step = bar_beat.time_unit) then
			   
			   
			   if Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).sequencer(voice_id).played then
			      
			      
			      --Put_Line("tatata 1.3");
			      declare
				 
				 date : time := start_time;
				 Control_Change  : Long := To_Long(Controlcommand(Channel_Type(Ctrl_Change.Plugin.Ch_Id-1), 
										  Long(Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).Sequencer(Voice_Id).Ctrl_Num),
										  Long(Ctrl_Change_Plugin_Record(Ctrl_Change.Plugin.all).Sequencer(Voice_Id).Ctrl_Val)));
			      begin
				 --Put_Line("tatata 1.4");
				 if Ctrl_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(Ctrl_Change.plugin.id))),
					  destination => new string ' (Positive'Image(Positive(Ctrl_Change.plugin.device_id))),
					  data_type => new string ' (control_type'image(control_of(Control_Change))),
					  channel => new string ' (channel_type'image(channel_of(Control_Change))),
					  data1 => new string ' (interfaces.c.long'image(data1(Control_Change))),
					  data2 => new string ' (interfaces.c.long'image(data2(Control_Change))),
					  hour => new string ' (formatting.image(date, true)),
					  hexa_sum => new string ' (hex_image(Control_Change)),
					  long_sum => new string ' (long'image(Control_Change)));
				    begin
				       --Put_Line("tatata 1.4.1.0");
				       --print(printed_message.all);
				       
				       Ctrl_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");				       
				 Ctrl_Change.Event_Process.Receive(Ctrl_Change.plugin.Device_Id, date, Control_Change, 0.0, tempo);
				 --Put_Line("tatata 1.6");				 
				 --Put_Line("tatata 1.7");
			      end;
			      
			   end if;
			end if;
		     end if;
		  end loop;
		  --Put_Line("tatata 3");		     		     
	       else
		  start_time := start_time + Quantum;
	       end if;
	       -- end if;
	       --   end if;
	       --Put_Line("Ctrl_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("Ctrl_Change started ::= MIMI 0.1.276");
	 end loop;
      end loop;
   end Ctrl_Change_Process;
   

   
end Gmface.Gm_Processing.Gmface.Gm_Ctrl_Change;