with PragmARC.Rem_NN_Wrapper;
use PragmARC.Rem_NN_Wrapper;
with Libsens.Data.Neural, Libsens.Data.Neural.Network;
use Libsens.Data.Neural;

with Ada.Numerics.Float_Random;
use Ada.Numerics.Float_Random;
with Ada.Numerics.Discrete_Random;
with Text_Io;

package body Libsens.Data.lead is   
   
   Network_Size : constant Positive := 25;
   Hidden_Num   : constant Positive := 25;
   
   package Lead_Network is new Libsens.Data.Neural.Network(Network_Size, Hidden_Num);   
   use Lead_Network;
         
   
   
   procedure Rand_Init(Samples : in out Samples_Type) is
      Polyphony : Natural := 0;
      Float_Gen : Generator;
   begin
      Reset(Float_Gen);
      for I in Samples'Range loop
	 for J in 1..Network_Size loop	   
	    if Real(Random(Float_Gen)) >= 0.5 then
	       Samples(I)(J) := 1.0;
	       Polyphony := Polyphony + 1;
	    else
	       Samples(I)(J) := 0.0;
	    end if;	    
	    exit when Polyphony > 4;
	 end loop;
	 
	 Polyphony := 0;
      end loop;
   end Rand_Init;
   
   function Problem_Rand return Node_Set is
      Set : Node_Set(1..Network_Size) := (others => 0.0);
      Float_Gen : Generator;
   begin
      Reset(Float_Gen);
      for I in Set'Range loop
	 if Real(Random(Float_Gen)) >= 0.5 then
	    Set(I) := 1.0;
	 else
	    Set(I) := 0.0;
	 end if;

      end loop;
      return Set;
   end Problem_Rand;
   
   ------------------------
   -- initialize pattern --
   ------------------------               
   procedure Init (Pattern : out Lead_Sentence_Type) is
   begin
      for I in Pattern'Range loop
	 Pattern(I).Key := I;
      end loop;
   end Init;
   
   package Value_Rand is new Ada.Numerics.Discrete_Random(Value_Type);
      
   task body Lead_Gen is
      End_Of_Task : Boolean := False;
      
      Lead_Pattern : Lead_Sentence_Type;
      
      Networks_Path : constant String := "data/networks/";
      
      Network_Name : constant String := "-mod-Lead.wgt";
      
      Network_Filename  : access String;
      
      
      Problem, Response : Node_Set(1..Network_Size) := (others => 0.0);
      
      
      
      Melodic_Samples : Samples_Type(1..128) := (others => (others => 0.0));
      Value_Gen : Value_Rand.Generator;
   begin
      
      while not End_Of_Task loop
	 loop
	    select
	       accept Halt do
	       End_Of_Task := True;
	       end Halt;
	       exit;
	    or
	       accept Initialize(Filename : in String;Reuse : in Boolean; Converged : in Float; Max_Epochs : in Positive) do
		  
		  Rand_Init(Melodic_Samples);
		  
		  Network_Filename := new String ' (Networks_Path & Filename & Network_Name);
		  if not Reuse then
		     Train(Network_Filename.all,
			   Melodic_Samples,
			   Reuse,
			   Real(Converged),
			   Max_Epochs);
		  end if;
		  
	       end Initialize;
	       
	       exit;
	    end select;
	 end loop;
	 while not End_Of_Task loop
	    
	    
	    select
	       
	       accept Halt do
		  End_Of_Task := True;
	       end Halt;
	       exit;
	       
	    or
	       accept Respond(Filename : in String;Channel : in Channel_Type; Seq : in out Seq_Vectors.Vector) do
		  
		  
		  Lead_Pattern := (others => Null_Note);
		  Init(Lead_Pattern);      
		  for I in Word16_Index_Type loop
		     if I = 8 or I = 12 then
			Problem := Problem_Rand;
			Response := Respond(Networks_Path & Filename & Network_Name, Problem);
			for J in Response'Range loop
			   if Response(J) >= 0.5 then
			      Response(J) := 1.0;
			      
			   else
			      Response(J) := 0.0;
			      
			   end if;
			end loop;
			To_Sentence(Response, I, Lead_Pattern);		     		     
			
		     end if;
		  end loop;
		  
		  for I in Lead_Pattern'Range loop		  
		     Lead_Pattern(I).Sens := Value_Rand.Random(Value_Gen);
		     Lead_Pattern(I).Length := Value_Rand.Random(Value_Gen);	    
		  end loop;
		  
		  
		  
		  Pattern(From => Lead_Pattern, Channel => Channel, Seq => Seq);
		  
		  
	       end Respond;
	    or
	       accept Initialize(Filename : in String;Reuse : in Boolean; Converged : in Float; Max_Epochs : in Positive) do
		  
		  Rand_Init(Melodic_Samples);
		  
		  Network_Filename := new String ' (Networks_Path & Filename & Network_Name);
		  
		  Train(Network_Filename.all,
			Melodic_Samples,
			Reuse,
			Real(Converged),
			Max_Epochs);
		  
		  
	       end Initialize;
	    end select;

	 end loop;      
      end loop;
   end Lead_Gen;
   
end Libsens.Data.lead;