with Libsens.MIDI.Messages;             use Libsens.MIDI.Messages;

with Libsens.Virtual.Cc_Change;         use Libsens.Virtual.Cc_Change;
with Libsens.Virtual.Prgm_Change;       use Libsens.Virtual.Prgm_Change;
with Libsens.Virtual.NN_Plugin;         use Libsens.Virtual.NN_Plugin;
with Libsens.Virtual.Gen_Plugin;        use Libsens.Virtual.Gen_Plugin;
with Libsens.Virtual.Nl_Network;        use Libsens.Virtual.Nl_Network;
with Libsens.Virtual.Step_Sequencer;    use Libsens.Virtual.Step_Sequencer;
with Libsens.Virtual.Arp_Sequencer;     Use Libsens.Virtual.Arp_Sequencer;


with PragmARC.REM_NN_Wrapper;
use PragmARC.REM_NN_Wrapper;

with Ada.Directories;                   use Ada.Directories;

with Gnat.OS_Lib;                       use Gnat;

with Text_Io;                           use Text_Io;


package body Libsens.Virtual.Work_Class is

   function Initialize(Class : in Plugin_Enum;
		       Id        : in Plugin_num;
		       Device    : in Device_Num;
		       Ch        : in Channel_Num;
		       Form      : in Form_Index_Type;
		       cat       : in Category_Index_Type)

		      return Abstract_Plugin_Access is

      Plugin : Abstract_Plugin_Access;

   begin
      case Class is
	 when Null_Plugin =>
	    Plugin := new Plugin_Class(Null_Plugin);
	 when Step_Seq =>
	    Plugin := new Step_Seq_Plugin_Record;
	 when Arp_Seq =>
	    Plugin := new Arp_Seq_Plugin_Record;
	 when NN_Mono =>
	    Plugin := new Nn_Mono_Plugin_Record;
	 when NN_Poly =>
	    Plugin := new Nn_Poly_Plugin_Record;
	 when NN_Rythm =>
	    Plugin := new Nn_Rythm_Plugin_Record;
	 when Nl_Mod =>
	    Plugin := new NL_Network_Plugin_Record;
	 when Gen_Bass =>
	    Plugin := new Gen_Bass_Plugin_Record;
	 when Gen_synth =>
	    Plugin := new Gen_synth_Plugin_Record;
	 when Gen_Drums =>
	    Plugin := new Gen_Drums_Plugin_Record;
	 when CC_List =>
	    Plugin := new CC_Change_Plugin_Record;
	 when PC_List =>
	    Plugin := new Prgm_Change_Plugin_Record;
      end case;
      Plugin.Initialize(Id, Device, Ch, Form, Cat);
      return Plugin;
   end Initialize;


   procedure Print (Filename : in String; Plugin : in Abstract_Plugin_Access) is
   begin
      Print(Filename, Plugin.all);
   end Print;




   procedure Read_Plugin(File : in out File_Type; Plugin : out Abstract_Plugin_access) is


      Class  : Plugin_Enum := Null_Plugin;

      Image : access String;

   begin
      --Put_Line("get plugin class...");
      Image := new String ' (Get_line(File));
      if Image'Length /= 0 then
	 Put_Line("Plugin class :" & Image.all);
	 Class := Plugin_Enum'value(Image.all);
	 --Put_Line("Initializing plugin...");
	 Plugin := Initialize(Class, 1, 1, 1, 1, 1);
	 --Put_Line("Plugin initialized...");
	 Plugin.Printed := Boolean'value(Text_Io.Get_Line (File));
	 --Put_Line("Printed setted");
	 Plugin.Mutted := Boolean'value(Text_Io.Get_Line (File));
	 --Put_Line("Mutted setted");
	 Plugin.Form_Id := Form_Index_Type'Value(Text_Io.Get_Line (File));
	 --Put_Line("Form_id setted");
	 Plugin.Cat_Id := Category_Index_Type'Value(Text_Io.Get_Line (File));
	 --Put_Line("Cat setted");
	 Plugin.Ch_Id := Channel_num'Value(Text_Io.Get_Line (File));
	 --Put_Line("Ch_id setted");
	 Plugin.Device_Id:= Device_num'Value(Text_Io.Get_Line (File));
	 --Put_Line("Device_id setted");
	 Plugin.Name := new String ' (Text_Io.Get_Line (File));
	 --Put_Line("name setted");
	 case Class is
	    
	    when Null_Plugin =>
	       null;

	    when Step_Seq =>
	       Step_Seq_Plugin_Record(Plugin.all).Bars_Max := Positive'Value(Text_Io.Get_Line (File));
	       --Put_Line("Bars max setted");
	       for Voice_Id in Step_Seq_Plugin_Record(Plugin.all).Sequencer'Range loop

		  begin
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Id := Positive'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Key := Key_Type'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Sens := Sens_Type'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Length := Length_Type'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Bar := Positive'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Number := Time_Number_Type'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Step := Time_Unit_Type'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Played := boolean'Value(Text_Io.Get_Line (File));

		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Octave := Octave_num'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).In_Loop := boolean'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Note := new String ' (Text_Io.Get_Line (File));
		     --Put_Line("voice N°" & Positive'Image(Voice_Id) & "  setted !");
		  end;
	       end loop;

	       when Pc_List =>
		  Prgm_Change_Plugin_Record(Plugin.all).Bars_Max := Positive'Value(Text_Io.Get_Line (File));
		 -- Put_Line("Bars max setted");
		  for Voice_Id in Prgm_Change_Plugin_Record(Plugin.all).Sequencer'Range loop

		     begin
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Id := Positive'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).MSB_select := Value_Type'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).LSB_Select := Value_Type'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Prgm_Num := Program_Type'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Bar := Positive'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Number := Time_Number_Type'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Step := Time_Unit_Type'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Played := boolean'Value(Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Note := new String ' (Text_Io.Get_Line (File));
			Prgm_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).In_Loop := boolean'Value(Text_Io.Get_Line (File));

			--Put_Line("voice N°" & Positive'Image(Voice_Id) & "  setted !");
		     end;
		  end loop;

	    when CC_List =>
	       CC_Change_Plugin_Record(Plugin.all).Bars_Max := Positive'Value(Text_Io.Get_Line (File));
	       --Put_Line("Bars max setted");
	       for Voice_Id in CC_Change_Plugin_Record(Plugin.all).Sequencer'Range loop

		  begin
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Id := Positive'Value(Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Ctrl_Name := new String ' (Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Ctrl_num := Value_Type'Value(Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Ctrl_val := Value_Type'Value(Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Bar := Positive'Value(Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Number := Time_Number_Type'Value(Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Step := Time_Unit_Type'Value(Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Played := boolean'Value(Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Note := new String ' (Text_Io.Get_Line (File));
		     CC_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).In_Loop := boolean'Value(Text_Io.Get_Line (File));
		     --Put_Line("voice N°" & Positive'Image(Voice_Id) & "  setted !");
		  end;
	       end loop;

	    when Nn_Mono =>

	       begin
		  Nn_Mono_Plugin_Record(Plugin.all).Name := new String ' (Get_Line(File));
		  Nn_Mono_Plugin_Record(Plugin.all).Width := Positive'Value(Get_Line(File));
		  Nn_Mono_Plugin_Record(Plugin.all).Sample_Max := Positive'Value(Get_Line(File));
		  Nn_Mono_Plugin_Record(Plugin.all).Reuse := boolean'Value(Get_Line(File));
		  Nn_Mono_Plugin_Record(Plugin.all).Converged := Real'Value(Get_Line(File));
		  Nn_Mono_Plugin_Record(Plugin.all).Max_Epoch := Positive'Value(Get_Line(File));
	       end;

	    when Nn_Poly =>

	      begin
		  Nn_Poly_Plugin_Record(Plugin.all).Name := new String ' (Get_Line(File));
		  Nn_Poly_Plugin_Record(Plugin.all).Width := Positive'Value(Get_Line(File));
		  Nn_Poly_Plugin_Record(Plugin.all).Sample_Max := Positive'Value(Get_Line(File));
		  Nn_Poly_Plugin_Record(Plugin.all).Reuse := boolean'Value(Get_Line(File));
		  Nn_Poly_Plugin_Record(Plugin.all).Converged := Real'Value(Get_Line(File));
		  Nn_Poly_Plugin_Record(Plugin.all).Max_Epoch := Positive'Value(Get_Line(File));
	       end;

	    when Nn_Rythm =>

	      begin
		  Nn_Rythm_Plugin_Record(Plugin.all).Name := new String ' (Get_Line(File));
		  Nn_Rythm_Plugin_Record(Plugin.all).Width := Positive'Value(Get_Line(File));
		  Nn_Rythm_Plugin_Record(Plugin.all).Sample_Max := Positive'Value(Get_Line(File));
		  Nn_Rythm_Plugin_Record(Plugin.all).Reuse := boolean'Value(Get_Line(File));
		  Nn_Rythm_Plugin_Record(Plugin.all).Converged := Real'Value(Get_Line(File));
		  Nn_Rythm_Plugin_Record(Plugin.all).Max_Epoch := Positive'Value(Get_Line(File));
	       end;

	    when Gen_Bass =>


	       begin

		  Gen_Bass_Plugin_Record(Plugin.all).Max_B_Inf := Positive'Value(Get_Line(File));
		  Gen_Bass_Plugin_Record(Plugin.all).Max_B_Sup := Positive'Value(Get_Line(File));
		  Gen_Bass_Plugin_Record(Plugin.all).Min_Class_Id := Positive'Value(Get_Line(File));
		  Gen_Bass_Plugin_Record(Plugin.all).Min_Value_Id := Positive'Value(Get_Line(File));
		  Gen_Bass_Plugin_Record(Plugin.all).Min_Data_Id := Positive'Value(Get_Line(File));
		  Gen_Bass_Plugin_Record(Plugin.all).Max_Class_Id := Positive'Value(Get_Line(File));
		  Gen_Bass_Plugin_Record(Plugin.all).Max_Value_Id := Positive'Value(Get_Line(File));
		  Gen_Bass_Plugin_Record(Plugin.all).Max_Data_Id := Positive'Value(Get_Line(File));


	       end;


	    when Gen_Synth =>


	       begin

		  Gen_Synth_Plugin_Record(Plugin.all).Max_B_Inf := Positive'Value(Get_Line(File));
		  Gen_Synth_Plugin_Record(Plugin.all).Max_B_Sup := Positive'Value(Get_Line(File));
		  Gen_Synth_Plugin_Record(Plugin.all).Min_Class_Id := Positive'Value(Get_Line(File));
		  Gen_Synth_Plugin_Record(Plugin.all).Min_Value_Id := Positive'Value(Get_Line(File));
		  Gen_Synth_Plugin_Record(Plugin.all).Min_Data_Id := Positive'Value(Get_Line(File));
		  Gen_Synth_Plugin_Record(Plugin.all).Max_Class_Id := Positive'Value(Get_Line(File));
		  Gen_Synth_Plugin_Record(Plugin.all).Max_Value_Id := Positive'Value(Get_Line(File));
		  Gen_Synth_Plugin_Record(Plugin.all).Max_Data_Id := Positive'Value(Get_Line(File));




	       end;

	    when Gen_Drums =>


	       begin

		  Gen_Drums_Plugin_Record(Plugin.all).Max_B_Inf := Positive'Value(Get_Line(File));
		  Gen_Drums_Plugin_Record(Plugin.all).Max_B_Sup := Positive'Value(Get_Line(File));
		  Gen_Drums_Plugin_Record(Plugin.all).Min_Class_Id := Positive'Value(Get_Line(File));
		  Gen_Drums_Plugin_Record(Plugin.all).Min_Value_Id := Positive'Value(Get_Line(File));
		  Gen_Drums_Plugin_Record(Plugin.all).Min_Data_Id := Positive'Value(Get_Line(File));
		  Gen_Drums_Plugin_Record(Plugin.all).Max_Class_Id := Positive'Value(Get_Line(File));
		  Gen_Drums_Plugin_Record(Plugin.all).Max_Value_Id := Positive'Value(Get_Line(File));
		  Gen_Drums_Plugin_Record(Plugin.all).Max_Data_Id := Positive'Value(Get_Line(File));



	       end;

	    when Nl_Mod =>
	       begin



	       	  NL_Network_Plugin_Record(Plugin.all).Gen_Reuse := boolean'Value(Get_Line(File));


	       end;



	    when Arp_Seq =>
	       begin


		  Arp_Seq_Plugin_Record(Plugin.all).Network := new String ' (Get_Line(File));
		  Arp_Seq_Plugin_Record(Plugin.all).Reuse := boolean'Value(Get_Line(File));
		  Arp_Seq_Plugin_Record(Plugin.all).Converged := Real'Value(Get_Line(File));
		  Arp_Seq_Plugin_Record(Plugin.all).Max_Epoch := Positive'Value(Get_Line(File));
		  Arp_Seq_Plugin_Record(Plugin.all).Last_Step := Positive'Value(Get_Line(File));
		  Arp_Seq_Plugin_Record(Plugin.all).transpose := Value_Type'Value(Get_Line(File));
		  Arp_Seq_Plugin_Record(Plugin.all).resolution := T_Figure'Value(Get_Line(File));
		  for I in Arp_Seq_Plugin_Record(Plugin.all).Step_Table'Range loop
		     Arp_Seq_Plugin_Record(Plugin.all).Step_Table(I).Set := boolean'Value(Get_Line(File));		     		     
		  end loop;
		  
		  for I in Arp_Seq_Plugin_Record(Plugin.all).Start_Chord'Range loop
		     Arp_Seq_Plugin_Record(Plugin.all).Start_Chord(I).key := Value_Type'Value(Get_Line(File));
		     Arp_Seq_Plugin_Record(Plugin.all).Start_Chord(I).vel := Value_Type'Value(Get_Line(File));
		     Arp_Seq_Plugin_Record(Plugin.all).Start_Chord(I).len := Value_Type'Value(Get_Line(File));
		     
		  end loop;
	       end;
	 end case;
      end if;

   end Read_Plugin;

   procedure Load_File (Work : in out Work_Record'Class) is
      File : Text_Io.File_Type;
   begin      
      for Plugin_Id in Work.Plugins'Range loop
	 begin
	    Work.Plugins(Plugin_Id) := null;	       
	 end;
      end loop;
      
      if Work.Filename'length = 0 then
	 for Plugin_Id in Work.Plugins'Range loop
	    begin
	       Work.Plugins(Plugin_Id) := Initialize(Null_Plugin, Plugin_Id, 1, 1, 1, 1);
	    end;
	 end loop;
      
	 return;      	 
      end if;
      Put_Line("Openning work filename : " & Work.Filename.all);
      Text_Io.Open(File, Text_Io.In_File, Work.Filename.all);

      -------------
      -- Options --
      Work.Filename := new String  ' (Text_Io.Get_Line (File));
      Work.Options.Track_Length := natural'Value(Text_Io.Get_Line(File));
      Work.Options.Tempo := Tempo_Type'Value(Text_Io.Get_Line (File));
      Work.Options.Signature.Number := Time_Number_Type'Value(Text_Io.Get_Line (File));
      Work.Options.Signature.Unit := Time_Unit_Type'Value(Text_Io.Get_Line (File));
      Work.Options.In_Loop := Boolean'Value(Text_Io.Get_Line (File));
      Work.Options.Current_Form := Form_Index_Type'Value(Text_Io.Get_Line (File));
      
      Work.Options.Filename := new String ' (Base_Name(Work.Filename.all));
      
      -- End Options. --
      ------------------
      -----------------
      -- Plugins_Set --
      for Plugin_Id in Work.Plugins'Range loop
	 begin
	    Read_plugin(File, Work.Plugins(Plugin_Id));	    	    
	    Work.Plugins(Plugin_Id).Id := Plugin_Id;
	    exit when End_Of_File(File);
	 exception
	    when others =>
	       Put_Line("Read plugin : exception IO.");
	 end;
      end loop;

      Text_Io.Close(File);
   end Load_File;




   procedure Initialize(Work : in out Work_Record;
			Work_Id  : in Work_Num;
			Filename : in String) is
   begin
      Work.Filename := new String ' (Filename);
      if Os_Lib.Is_Regular_File(Filename) or else
	Filename'Length = 0 then
	 Work.Load_File;
      end if;
      Work.Id := Work_Id;
   end Initialize;





   procedure Save(Work : in out Work_Record'Class;
		  Filename : in String := "") is

      Name : String_Access := new string ' (Work.Filename.all);
      File : Text_Io.File_Type;
   begin
      if Filename /= "" then
	 Name := new String ' (Filename);
      end if;
      Work.Filename := new String ' (Name.all);
      Create(File, Out_File, Name.all);
      
      -------------
      -- Options --
      Put_Line("-- Options --");
      Work.Options.Filename := new String ' (Base_Name(Name.all));
      Put_Line(File, Work.Filename.all);
      Put_Line(File, Natural'Image(Work.Options.Track_Length));
      Put_Line(File, Tempo_Type'Image(Work.Options.Tempo));
      Put_Line(File, Positive'Image(Work.Options.Signature.Number));
      Put_Line(File, Positive'Image(Work.Options.Signature.Unit));
      Put_Line(File, Boolean'Image(Work.Options.In_Loop));
      Put_Line(File, Form_Index_Type'Image(Work.Options.Current_Form));
      Put_Line("-- End Options. --");
      ------------------
      Close(File);
      ------------------
      Put_Line("-- Plugins_Set --");
      for Plugin_Id in Work.Plugins'Range loop
	 if Work.Plugins(Plugin_Id) /= null then
	    Print(Work.Filename.all, Work.Plugins(Plugin_Id).all);
	 end if;
      end loop;
      Open(File, Append_File, Work.Filename.all);
      Put_Line("End plugins");

      Close(File);
   end Save;



   procedure Finalize(Work : in out Work_Record) is
   begin
      null;
   end Finalize;

   function Get_Plugin(Work : in Work_Record;
		       Plugin_Id : in Plugin_Num)
		      return Abstract_Plugin_Access is
   begin
      return Work.Plugins(Plugin_Id);
   end Get_Plugin;


end Libsens.Virtual.Work_Class;