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;                           use Text_Io;

package body Libsens.Data.bass is   
   
   Network_Size : constant Positive := 25;
   Hidden_Num   : constant Positive := 25;
   
   package Bass_Network is new Libsens.Data.Neural.Network(Network_Size, Hidden_num);   
   use Bass_Network;
   
   
   
   Float_Gen : Generator;
   
   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 reverse 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);      
   begin      
      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 Bass_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);
   
   
   --  type Feedback_Type is
   --     record
   --  	 Register : Register_Type := (others => 0.0);
   --  	 Is_Set   : Boolean := False;
   --     end record;     
   
   --  Null_Feedback : constant Feedback_type := ((others => 0.0), False);
   
   

   
   task body Bass_Gen is
      
      End_Of_Task : Boolean := False;
      
      Bass_Pattern : Bass_Sentence_Type;
      
      
      Networks_Path : constant String := "./data/networks/";
      
      Network_Name : constant String := "-mod-Bass.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
	 Value_Rand.Reset(Value_Gen);
	 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
		  
		  --Put_Line("Call respond for Bass with filename : " & Filename);
		  --Put_Line("Call respond for Bass with path : " & Networks_Path & Filename & Network_Name);
		  
		  Bass_Pattern := (others => Null_Note);
		  Init(Bass_Pattern);      
		  Problem := Problem_Rand;
		  for I in Word16_Index_Type loop
		     if I = 8 then			   			
			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, Bass_Pattern);		     		     			   
			Problem := Problem_Rand;
			--  for I in Problem'Range loop
			--  	  if response(I) = 1.0 then
			--  	     Problem(I) := 1.0;
			--  	  end if;
			--  end loop;
		     end if;
		  end loop;
		  
		  for I in Bass_Pattern'Range loop		  
		     Bass_Pattern(I).Sens :=  Value_Rand.Random(Value_Gen);
		     Bass_Pattern(I).Length := 2;
		     
		  end loop;
		  
		  
		  
		  
		  
		  --Text_Io.Put_Line("Data bass generate...");
		  Pattern(From => Bass_Pattern, Channel => Channel, seq => Seq);
		  --Text_Io.Put_Line("Data bass generated.");
	       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 Bass_Gen;

end Libsens.Data.bass;