-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--                                                                                                                                                                         --
--                                                                      ---------------------------                                                                        --
--                                                                      --       El-Sofware      --                                                                        --
--                                                                      ---------------------------                                                                        --
--                                                                                                                                                                         --
--                                                                                present                                                                                  --
--                                                                                                                                                                         --
--                                                                            ---------------                                                                              --
--                                                                            --  MidiSurf --                                                                              --
--                                                                            ---------------                                                                              --
--                                                                                                                                                                         --
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--                                                                                                                                                                         --
-- Auteur      : Manuel De Girardi                                                                                                                                         --
-- Date        : 25/11/2010                                                                                                                                                --
-- Description : Surface de contrĂ´le pour instrument MIDI                                                                                                                  --
--                                                                                                                                                                         --
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

with Glib;                              use Glib;
with Gtk.Widget;                        use Gtk.Widget;
with Gtk.Stock;                         use Gtk.Stock;

with Gtk.Handlers;
pragma Elaborate_All (Gtk.Handlers);


with Libsens.Midi_Messages;                  use Libsens.Midi_Messages;
with Midi_Implementation;               use Midi_Implementation;


with Text_Io;                           use Text_Io;
with PragmARC.REM_NN_Wrapper;
use PragmARC.REM_NN_Wrapper;
with Rem_Common;
use Rem_Common;
with Text_Io;
use Text_Io;
with Ada.Unchecked_Deallocation;
with Ada.Directories;                   use Ada.Directories;

package body Libsens.Intelligences is



   procedure Free_Chord is new Ada.Unchecked_Deallocation(T_Chord, Chord_Access);



   task body T_Intelligence_Driver is
      Suspended : Boolean := True;
      End_Of_Task : Boolean := False;
      Message : T_Message;
      Date  : Time := Clock;
      Tempo : T_Bpm := 120.0;
      Channel : T_Channel := 1;


      Current_Step : Positive := 1;
      Resolution : T_Figure := double;
      Last_Step : Positive := 32;
      Transpose : Integer := 0;

      Saved_Chord : Chord_Access;
      The_Chord : Chord_Access;

      Register : T_Register;
      Prob_File : Register_Io.File_Type;
      prob_Flt : access String;
      Network : access String;

   begin
      while not End_Of_Task loop
         select
            accept Start
              (Top : in Time;
               Bpm : in T_Bpm;
               Channel : in T_Channel;
               Chord   : in T_chord) do
               T_Intelligence_Driver.Channel := Channel;
               Put_Line("Stratting intelligence");
               Date := Top;
               Tempo := Bpm;
               Suspended := False;
               The_Chord := new T_Chord ' (Chord);
               Network := new String ' (Get_Text(Intelligence.Filename_Gentry));
               Prob_Flt := new String ' (Base_Name(Network.all) & ".pbm");
               Register := Chord_To_Register(The_Chord.all);
               Register_Io.Create(Prob_File, Register_Io.Out_File, Prob_Flt.all);
               Register_Io.write(Prob_File, Register);
               Register_Io.close(Prob_File);
               Current_Step := 1;
            end Start;
         or
            accept Halt do
               Suspended := True;
               End_Of_Task := True;
            end Halt;
         or

            accept Stop;
         or
            accept Reset do
               The_Chord := new T_Chord(Intelligence.Chord'range);
               for I in Intelligence.Chord'Range loop
                  if Intelligence.Chord(I).Set then
                     The_Chord(I).key := Intelligence.Chord(I).Key;
                     The_Chord(I).vel := Intelligence.Chord(I).sens;

                  else
                     The_Chord(I).key := 0;
                     The_Chord(I).vel := 0;

                  end if;
               end loop;
               Register := Chord_To_Register(The_Chord.all);
            end Reset;
         or
            accept Set_Last_Step
              (Last : in Positive) do
               Last_Step := Last;
            end Set_Last_Step;
         or
            accept Set_Transpose(Transpose : in Integer) do
               T_Intelligence_Driver.Transpose := Transpose;
            end Set_Transpose;
         end select;
         delay until Date;
         while not Suspended loop
            select
               accept Reset do
                  The_Chord := new T_Chord(Intelligence.Chord'range);
                  for I in Intelligence.Chord'Range loop
                     if Intelligence.Chord(I).Set then
                        The_Chord(I).key := Intelligence.Chord(I).Key;
                        The_Chord(I).vel := Intelligence.Chord(I).sens;

                     else
                        The_Chord(I).key := 0;
                        The_Chord(I).vel := 0;

                     end if;
                  end loop;
                  Register := Chord_To_Register(The_Chord.all);
               end Reset;
            or
               accept Set_Last_Step
                 (Last : in Positive) do
                  if Current_Step > Last then
                     Current_Step := Last;
                  end if;
                  Last_Step := Last;
               end Set_Last_Step;
            or
               accept Set_Transpose(Transpose : in Integer) do
                  T_Intelligence_Driver.Transpose := Transpose;
                  Message := All_Note_off(Channel);
                  Intelligence.Driver.Receive(Message);
               end Set_Transpose;
            or
               accept Stop do
                  Put_Line("Stopping intelligence");
                  Suspended := True;
               end Stop;
            or
               accept Halt do
                  Suspended := True;
                  End_Of_Task := True;
               end Halt;

            else
               if Date <= Clock then

                  if Intelligence.Step_Table(Current_Step).Set then
                     for I in The_Chord'range loop
                        if The_Chord(i).Key + Transpose > 0 and
                          The_Chord(i).Key + Transpose < 128 then
                           Message := Note_On(Channel, The_Chord(i).Key + transpose, The_Chord(i).vel);
                           Intelligence.Driver.Receive(Message);
                        end if;
                     end loop;
                     delay Bpm_To_Duration(tempo, triple);
                     for I in The_Chord'range loop
                        if The_Chord(i).Key + Transpose > 0 and
                          The_Chord(i).Key + Transpose < 128 then
                           Message := Note_Off(Channel, The_Chord(i).Key + transpose);
                           Intelligence.Driver.Receive(Message);
                        end if;
                     end loop;
                     if Network.all /= "no_network" then
                     Register := REM_NN_Expl(Network.all, Prob_Flt.all);
                  end if;
                  for I in Register'Range loop
                     if Register(I) <= 0.5 then
                        Register(I) := 0.0;
                     elsif Register(I) > 0.5 then
                        Register(I) := 1.0;
                     end if;
                  end loop;
                  Free_Chord(The_Chord);
                  The_chord := new T_Chord' (Register_To_Chord(Register));
                  --Register := Chord_To_Register(The_Chord.all);
                  Register_Io.Create(Prob_File, Register_Io.Out_File, Prob_Flt.all);
                  Register_Io.write(Prob_File, Register);
                  Register_Io.close(Prob_File);
                  end if;
                  Date := Date + Bpm_To_Duration(tempo, Resolution);
                  if Current_Step = Last_step then
                     Current_Step := 1;
                  else
                     Current_Step := Current_Step + 1;
                  end if;
               else
                  delay 0.001;
               end if;

            end select;
         end loop;
      end loop;
   end T_Intelligence_Driver;



   package Intelligence_Handlers is new Gtk.Handlers.User_Callback(Gtk_Widget_Record, Intelligence_access);



   procedure Reset_Intelligence(Widget : access Gtk_Widget_Record'class; Intelligence : Intelligence_access) is
   begin
      Intelligence.Intelligence_Driver.Reset;
   end Reset_Intelligence;


   procedure Set_Last_step(Widget : access Gtk_Widget_Record'class; Intelligence : Intelligence_access) is
    begin
       Intelligence.Last_step := T_value(Get_value(Intelligence.Last_Spin_Button));
       Intelligence.Intelligence_Driver.Set_Last_Step(Intelligence.Last_Step);
    end Set_Last_step;

    procedure Set_Transpose(Widget : access Gtk_Widget_Record'class; Intelligence : Intelligence_access) is
    begin
       Intelligence.Transpose := integer(Get_value(Intelligence.Transpose_Spin_Button));
       Intelligence.Intelligence_Driver.Set_Transpose(Intelligence.Transpose);
    end Set_Transpose;


    procedure Ok (Widget : access Gtk_Widget_Record'class; Intelligence : Intelligence_access) is
    begin
       Set_Text(Intelligence.Filename_Gentry, Get_Filename(Intelligence.File_Selection));
       Destroy(Intelligence.File_Selection);
    end Ok;

    procedure destroy (Widget : access Gtk_Widget_Record'class; Intelligence : Intelligence_access) is
    begin
       Destroy(Intelligence.File_Selection);
    end destroy;

    procedure Set_filename(Widget : access Gtk_Widget_Record'class; Intelligence : Intelligence_access) is

    begin
       Gtk_New(Intelligence.File_Selection, "Select network filename...");
       Intelligence_Handlers.Connect(Get_Ok_Button(Intelligence.File_Selection),
                                     "clicked",
                                     Intelligence_Handlers.To_Marshaller(ok'access),
                                     intelligence);

       intelligence_Handlers.Connect(Get_Ok_Button(Intelligence.File_Selection),
                                     "destroy",
                                     intelligence_Handlers.To_Marshaller(destroy'access),
                                     intelligence);
       intelligence_Handlers.Connect(Get_Cancel_Button(Intelligence.File_Selection),
                                     "clicked",
                                     intelligence_Handlers.To_Marshaller(destroy'access),
                                     intelligence);

       Show_All(Intelligence.File_Selection);
    end Set_Filename;


   procedure Initialize
     (Intelligence : in out Intelligence_Access;
      Driver       : in Output_Driver_Access) is

   begin
      Intelligence := new T_Intelligence(Driver);
      Gtk_New(Intelligence.Main_Frame, "Intelligence");
      Gtk_New_Vbox(Intelligence.Main_Vbox);
      Gtk_New_Hbox(Intelligence.Main_Hbox);
      Gtk_New_Vbox(Intelligence.parameters);
      Gtk_New_Hbox(Intelligence.Chord_Hbox);
      for I in Intelligence.chord'Range loop
         Initialize(intelligence.Chord(I));
         Pack_Start(Intelligence.Chord_Hbox, Intelligence.Chord(I).Note_Vbox, False, False, 0);
         Intelligence_Handlers.Connect(Intelligence.Chord(I).Key_Spin_button,
                                       "value_changed",
                                       Intelligence_handlers.To_Marshaller(Reset_Intelligence'access),
                                       intelligence);
         Intelligence_Handlers.Connect(Intelligence.Chord(I).Sens_Spin_button,
                                       "value_changed",
                                       Intelligence_handlers.To_Marshaller(Reset_Intelligence'access),
                                       intelligence);

         Intelligence_Handlers.Connect(Intelligence.Chord(I).Set_Check_Button,
                                       "toggled",
                                       Intelligence_handlers.To_Marshaller(Reset_Intelligence'access),
                                       intelligence);
      end loop;

      Gtk_New(Intelligence.Key_Label, "Key");
      Gtk_New(Intelligence.Sens_Label, "Sens");

      Gtk_New_Vbox(Intelligence.Label_Vbox);

      Pack_Start(Intelligence.Label_Vbox, Intelligence.Key_Label, False, False, 5);
      Pack_Start(Intelligence.Label_Vbox, Intelligence.Sens_Label, False, False, 5);


      Pack_Start(Intelligence.Main_Hbox, Intelligence.Label_Vbox, False, False, 0);
      Pack_Start(Intelligence.Main_Hbox, Intelligence.Chord_Hbox, False, False, 0);
      Pack_Start(Intelligence.Main_Hbox, Intelligence.parameters, False, False, 15);


      Gtk_New(Intelligence.Last_Label, "Last step :");
      Gtk_New(Intelligence.Last_Spin_Button, 1.0, 32.0, 1.0);
      Set_Value(Intelligence.Last_Spin_Button, 32.0);
      Gtk_New(Intelligence.Transpose_Label, "Transpose :");
      Gtk_New(Intelligence.Transpose_Spin_Button, -24.0, 24.0, 1.0);
      Set_Value(Intelligence.Transpose_Spin_Button, 0.0);
      Gtk_New_Hbox(Intelligence.Stepseq_Hbox);
      for I in Intelligence.Step_Table'Range loop
         Initialize(Intelligence.Step_Table(I), Integer'Image(I));
         Pack_Start(Intelligence.Stepseq_Hbox, Intelligence.Step_Table(I).Step_Vbox, False, False, 0);
      end loop;

      Gtk_New(Intelligence.Filename_Gentry);
      Gtk_New_From_stock(Intelligence.File_Selection_button, Stock_open);
      Gtk_New(Intelligence.Filename_Label, "Network filename : ");
      Gtk_New_Vbox(Intelligence.Step_Parameters);
      Gtk_New_Vbox(Intelligence.Network_Parameters);

      Pack_Start(Intelligence.Step_Parameters, Intelligence.Last_label, False, False, 0);
      Pack_Start(Intelligence.Step_Parameters, Intelligence.Last_Spin_Button, False, False, 0);
      Pack_Start(Intelligence.Step_Parameters, Intelligence.Transpose_Label, False, False, 0);
      Pack_Start(Intelligence.Step_Parameters, Intelligence.Transpose_Spin_Button, False, False, 0);

      Pack_Start(Intelligence.Network_Parameters, Intelligence.Filename_Label, False, False, 0);
      Pack_Start(Intelligence.Network_Parameters, Intelligence.Filename_gentry, False, False, 0);
      Pack_Start(Intelligence.Network_Parameters, Intelligence.File_Selection_button, False, False, 10);

      Pack_Start(Intelligence.Main_Hbox, Intelligence.Step_Parameters, False, False, 0);
      Pack_Start(Intelligence.Main_Hbox, Intelligence.Network_Parameters, False, False, 15);

      Pack_Start(Intelligence.Main_Vbox, Intelligence.Main_Hbox, False, False, 0);
      Pack_Start(Intelligence.Main_Vbox, Intelligence.Stepseq_Hbox, False, False, 0);

      Intelligence_Handlers.Connect(Intelligence.Last_Spin_Button,
                                    "value_changed",
                                    Intelligence_handlers.To_Marshaller(Set_Last_Step'access),
                                    Intelligence);

      Intelligence_Handlers.Connect(Intelligence.Transpose_Spin_Button,
                                    "value_changed",
                                    Intelligence_handlers.To_Marshaller(Set_Transpose'access),
                                    Intelligence);

      Intelligence_Handlers.Connect(Intelligence.File_Selection_Button,
                                    "clicked",
                                    Intelligence_handlers.To_Marshaller(Set_filename'access),
                                    Intelligence);



      Add(Intelligence.Main_Frame, Intelligence.Main_Vbox);
      Show_All(Intelligence.Main_Frame);

   end Initialize;


   procedure Set_To_Active(Widget : access Gtk_Widget_Record'class; Note : Note_access) is
   begin
      Note.Set := Get_Active(Note.Set_Check_Button);
   end Set_To_Active;

   procedure Set_Key(Widget : access Gtk_Widget_Record'class; Note : Note_access) is
   begin
         Note.key := T_value(Get_value(Note.Key_Spin_button));
   end Set_Key;

   procedure Set_Sens(Widget : access Gtk_Widget_Record'class; Note : Note_access) is
   begin
      Note.sens := T_value(Get_value(Note.sens_Spin_button));
   end Set_Sens;


   package Note_Handlers is new Gtk.Handlers.User_Callback(Gtk_Widget_Record, Note_access);


   procedure Initialize
     (Note : in out Note_Access) is
      begin

         note := new T_Note;
         Gtk_New_Vbox(Note.Note_Vbox);
         Gtk_New(Note.Set_Check_Button);
         Set_Active(Note.Set_Check_Button, true);
         Gtk_New(Note.Key_Spin_Button, 0.0, 127.0, 1.0);
         Set_Value(Note.Key_Spin_Button, 60.0);
         Gtk_New(Note.Sens_Spin_Button, 0.0, 127.0, 1.0);
         Set_Value(Note.sens_Spin_Button, 100.0);

         Pack_Start(Note.Note_Vbox, Note.Key_Spin_Button, False, False, 0);
         Pack_Start(Note.Note_Vbox, Note.Sens_Spin_Button, False, False, 0);

         Pack_Start(Note.Note_Vbox, Note.Set_check_Button, False, False, 0);


         Note_Handlers.Connect(Note.Set_Check_Button,
                               "toggled",
                               Note_handlers.To_Marshaller(Set_To_Active'access),
                               Note);

         Note_Handlers.Connect(Note.Key_Spin_Button,
                               "value_changed",
                               Note_handlers.To_Marshaller(Set_key'access),
                               Note);

         Note_Handlers.Connect(Note.sens_Spin_Button,
                               "value_changed",
                               Note_handlers.To_Marshaller(Set_sens'access),
                               Note);

   end Initialize;



   procedure Set_To_Active(Widget : access Gtk_Widget_Record'class; Step : step_access) is
    begin
       Step.Set := Get_Active(Step.Set_Check_Button);
    end Set_To_Active;

    package Step_Handlers is new Gtk.Handlers.User_Callback(Gtk_Widget_Record, Step_access);


    procedure Initialize
      (Step : in out Step_Access;
       Label : in string) is
    begin

       Step := new T_Step;
       Gtk_New_Vbox(Step.Step_Vbox);
       Gtk_New(Step.Step_Label, Label);
       Gtk_New(Step.Set_Check_Button);
       Set_Active(Step.Set_Check_Button, true);

       Pack_Start(Step.Step_Vbox, Step.Step_label, False, False, 0);

       Pack_Start(Step.Step_Vbox, Step.Set_check_Button, False, False, 0);

       Step_Handlers.Connect(Step.Set_Check_Button,
                             "toggled",
                             Step_handlers.To_Marshaller(Set_To_Active'access),
                             step);

    end Initialize;


end Libsens.Intelligences;