with Gmface.Gm_Virtual.Gmface.Step_Sequencer;
use Gmface.Gm_Virtual.Gmface.Step_Sequencer;
with Gmface.Gm_Virtual.Gmface.Ctrl_Change;
use Gmface.Gm_Virtual.Gmface.Ctrl_Change;
with Gmface.Gm_Virtual.Gmface.Prgm_Change;
use Gmface.Gm_Virtual.Gmface.Prgm_Change;

with Gmface.Gm_MIDI.Messages;           use Gmface.Gm_MIDI.Messages;

with Ada.Directories;                   use Ada.Directories;
with Gnat.OS_Lib;                       use Gnat;
with Text_Io;                           use Text_Io;
package body Gmface.Gm_Virtual.Gmface.Gmface_Work is
   
   
   function image(Signature : in Time_Signature_Type) return String is
      
   begin      
      
      return 
	Positive'Image(Signature.Number) & '/' &
	Positive'Image(signature.Unit);
   end Image;      
   
   
   function Image(Bar_Beat : in Bar_Beat_Type) return String is
      
   begin
      
      return Positive'Image(Bar_Beat.Bar) & '.' &
	Positive'Image(Bar_Beat.Time_Number) & '.' &
	Positive'Image(Bar_Beat.Time_unit);
   end Image;
   
   procedure Next(Bar_Beat    : in out Bar_Beat_Type;
		  Bar         : in Natural;
		  Number      : in Time_Number_Type;
		  Unit        : in Time_Unit_Type) is
      
   begin
      
      if Bar_Beat.Time_Unit + 1 > Unit then
	 Bar_Beat.Time_Unit := 1;
	 if Bar_Beat.Time_Number + 1 > Number then
	    Bar_Beat.Time_Number := 1;
	    if Bar_Beat.Bar < Bar then
	       Bar_Beat.Bar := Bar_Beat.Bar + 1;
	    else
	       Bar_Beat.Bar := 1;
	    end if;
	 else
	    Bar_Beat.Time_Number := Bar_Beat.Time_Number + 1;
	 end if;
      else
	 Bar_Beat.Time_Unit := Bar_Beat.Time_Unit + 1;
      end if;      
   end Next;
   
   
   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 Gmface_Plugin_Class(Null_Plugin);
	 when Step_Seq =>
	    Plugin := new Step_Seq_Plugin_Record;
	 when CC_List =>
	    Plugin := new Ctrl_Change_Plugin_Record;
	 when PC_List =>
	    Plugin := new Prgm_Change_Plugin_Record;
	 when others =>
	    null;
      end case;
      Gmface_Plugin_Class(Plugin.all).Initialize(Id, Device, Ch, Form, Cat);
      return Plugin;
   end Initialize;
   
   
   
   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 := Value_Type'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Sens := Value_Type'Value(Text_Io.Get_Line (File));
		     Step_Seq_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Length := Value_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 := Value_Type'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 =>
	       Ctrl_Change_Plugin_Record(Plugin.all).Bars_Max := Positive'Value(Text_Io.Get_Line (File));
	       --Put_Line("Bars max setted");
	       for Voice_Id in Ctrl_Change_Plugin_Record(Plugin.all).Sequencer'Range loop

		  begin
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Id := Positive'Value(Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Ctrl_Name := new String ' (Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Ctrl_num := Value_Type'Value(Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Ctrl_val := Value_Type'Value(Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Bar := Positive'Value(Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Number := Time_Number_Type'Value(Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Step := Time_Unit_Type'Value(Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Played := boolean'Value(Text_Io.Get_Line (File));
		     Ctrl_Change_Plugin_Record(Plugin.all).Sequencer(Voice_Id).Note := new String ' (Text_Io.Get_Line (File));
		     Ctrl_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 others =>
	       null;
	 end case;
      end if;

   end Read_Plugin;

   
   procedure Load_File (Work : in out Gmface_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);
      
      -- Gmface header :
      Put_Line(Get_Line(File));
      
      -------------
      -- 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.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 Gmface_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 Gmface_Work_Record;
		  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));
      
      -- Gmface Header :
      Put_Line(File, "GmFa");
      
      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, Gmface_Plugin_Class(Work.Plugins(Plugin_Id).all));
	    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;

end Gmface.Gm_Virtual.Gmface.Gmface_Work;