with DC_Keyb; use DC_Keyb;
with DC_Math; use DC_Math;
with DC_Type; use DC_Type;
with DC_Scrn;
with Text_IO; use Text_IO;

procedure FIST is
---------------------------------------------------------------------------
---------------------------------------------------------------------------
package Float_IO is new Text_IO.Float_IO ( float );
use Float_IO;
type Transmitter_Type is array ( positive range <> ) of float;
type Neuron_Type ( Neuron_Count: positive ) is
  record
    Trans : Transmitter_Type ( 1..Neuron_Count ) := ( others => 0.0 );
    Ch_Ex : Array_Float ( 1..Neuron_Count ) := ( others => 10.0 );
    Ch_Cl : Array_Float ( 1..Neuron_Count ) := ( others =>  1.0 );
    A_Na  : float := 0.5;
    A_K   : float := 0.5;
    P     : float := 0.0;
  end record;

function Inputs (
	   Time         : in float;
	   dTime        : in float;
	   Neuron_Count : in positive )
	   return Transmitter_Type is
---------------------------------------------------------------------------
  Temp : Transmitter_Type ( 1..Neuron_Count );
begin
  if ( Time >= dTime * 100.0 ) and ( Time < dTime * 100.0 + dTime ) then
    Temp := ( others => +1.0 );
--  elsif ( Time > 1.999 ) and ( Time < 2.001 ) then
--    Temp := ( others => -1.0 );
--  elsif ( Time > 2.999 ) and ( Time < 3.001 ) then
--    Temp := ( others => 0.01 );
  else
    Temp := ( others => 0.0 );
  end if;
--  Temp := ( others => 1.0 );
  return Temp;
end Inputs;

procedure Conductance_Change (
	    dCh_Ex :    out Array_Float;
	    dCh_Cl :    out Array_Float;
	    Ch_Ex  : in     Array_Float;
	    Ch_Cl  : in     Array_Float;
	    P      : in     float;
	    L      : in     float := 1.0;
	    M      : in     Transmitter_Type ) is
---------------------------------------------------------------------------
  Neuron_Count : constant positive := M'last;
begin
  for Synapse in M'range loop
    dCh_Ex ( Synapse ) := +P * M ( Synapse ) * Ch_Ex ( Synapse ) * L;
    dCh_Cl ( Synapse ) := -P * M ( Synapse ) * Ch_Cl ( Synapse ) * L;
  end loop;
end Conductance_Change;

procedure Phase_Change (
	    dP_dt        : in out float;
	    A_Na,
	    A_K          : in     float;
	    Ch_Ex        : in     Array_Float;
	    Ch_Cl        : in     Array_Float;
	    P            : in     float;
	    dTime        : in     float := 0.01;
	    M            : in     Transmitter_Type ) is
---------------------------------------------------------------------------
  G_Na: constant float :=   1.0;  -- conductivity of Sodium      (0.5e-6 S)
  G_K : constant float :=   1.0;  -- conductivity of Potassium    (10e-6 S)
  G_Ex: constant float :=   1.0;  -- conductivity of excitatory NT
  G_Cl: constant float :=   1.0;  -- conductivity of inhibitory NT Chloride
  E_Na: constant float :=  +1.0;  -- Nernst potential of Sodium    (+55 mV)
  E_K : constant float :=  -1.0;  -- Nernst potential of Potassium (-75 mV)
  E_Ex: constant float :=  E_Na;  -- Nernst potential of excitatory NT
  E_Cl: constant float :=   0.0;  -- Nernst potential, inhibitory Chloride
  Cm  : constant float :=   1.0;  -- membrane capacitance
  I_Ex,                           -- current of excitatory receptors
  I_Cl,                           -- current of inhibitory receptors
  I_Na,                           -- current of Sodium
  I_K  :          float :=  0.0;  -- current of Potassium
  T_Na : constant float :=  0.0;  -- rate of change threshold for Na
  T_K  : constant float :=  0.0;  -- rate of change threshold for K
begin
  for Synapse in M'range loop
    I_Ex := I_Ex + M ( Synapse ) * Ch_Ex ( Synapse ) * G_Ex * ( P - E_Ex );
    I_Cl := I_Cl + M ( Synapse ) * Ch_Cl ( Synapse ) * G_Cl * ( P - E_Cl );
  end loop;
--  I_Na := G_Na * ( 1.0 + A_Na ) ) * ( P - E_Na );
--  I_K  := G_K  * ( 1.0 + A_K  ) * ( P - E_K  );
  I_Na := G_Na * A_Na * ( P - E_Na );
  I_K  := G_K  * A_K  * ( P - E_K  );
  dP_dt := - ( I_Cl + I_Ex + I_Na + I_K ) / Cm;
--  Put ( "I_Ex: " ); Put ( I_Ex ); Put ( " " );
--  Put ( "I_In: " ); Put ( I_In ); Put ( " " );
--  Put ( "I_Na: " ); Put ( I_Na ); Put ( " " );
--  Put ( "I_K:  " ); Put ( I_K  ); Put ( " " );
  Put ( "dP_dt: " ); Put ( dP_dt, 2, 2, 3   ); Put ( " " );
end Phase_change;

procedure Transmitter_Change (
	    dTrans :    out Transmitter_Type;
	    Trans  : in     Transmitter_Type;
	    M      : in     Transmitter_Type;
	    Ch_Ex,
	    Ch_Cl  : in     Array_Float;
	    De_Tra : in     float ) is
---------------------------------------------------------------------------
begin
  for Synapse in Trans'range loop
    dTrans ( Synapse ) := - De_Tra * M ( Synapse )
      * ( Ch_Ex ( Synapse ) + Ch_Cl ( Synapse ) );
  end loop;
end Transmitter_Change;

Procedure Neuron_Update (
	    N       : in out Neuron_Type;
	    dt      : in     float;
	    L       : in     float;
	    Sl_Na,
	    Sl_K,
	    Act_Na,
	    Act_K,
	    Thr_Na,
	    Thr_K,
	    De_Tra,
	    Ini_Na,
	    Ini_K   : in     float ) is
---------------------------------------------------------------------------
  dP     : float := 0.0;
  dP_dt  : float := 0.0;
  dCh_Ex : Array_Float ( N.Ch_Ex'range );
  dCh_Cl : Array_Float ( N.Ch_Cl'range );
  dA_Na_dt,
  dA_K_dt : float := 0.0;
  M      : Transmitter_Type ( N.Trans'range ); -- permeability;
  dTrans : Transmitter_Type ( N.Trans'range );
begin
  for Synapse in N.Trans'range loop
    M ( Synapse ) := TanH ( N.Trans ( Synapse ) /
      ( N.Ch_Ex ( Synapse ) + N.Ch_Cl ( Synapse ) ) );
  end loop;
  Phase_Change ( dP_dt, N.A_Na, N.A_K, N.Ch_Ex, N.Ch_Cl, N.P, dt, M );
  dP := dP_dt * dt;
--  Put ( "dP: " ); Put ( dP, 2, 2, 3 ); Put ( "  " );
  N.P := N.P + dP;
--  dA_Na_dt := -N.A_Na * Sl_Na
--    + Act_Na * Sigmoid ( Slope * ( dP_dt - Thr_Na ) );
--  dA_K_dt  := -N.A_K  * Sl_K
--    + Act_K * Sigmoid ( Slope * ( dP_dt - Thr_K  ) );
  dA_Na_dt := Act_Na * Sigmoid ( Sl_Na * ( N.P - Thr_Na ) ) - N.A_Na;
  dA_K_dt  := Act_K  * Sigmoid ( Sl_K  * ( N.P - Thr_K  ) ) - N.A_K ;
  N.A_Na := N.A_Na + dt * dA_Na_dt;
  N.A_K  := N.A_K  + dt * dA_K_dt ;
  Put ( "A_Na:" ); Put ( N.A_Na - Ini_Na, 2, 4, 2 ); Put ( "  " );
  Put ( "A_K :" ); Put ( N.A_K  - Ini_K , 2, 4, 2 ); Put ( "  " );
  Conductance_Change ( dCh_Ex, dCh_Cl, N.Ch_Ex, N.Ch_Cl, N.P, L, M );
  for Synapse in N.Ch_Ex'range loop
    N.Ch_Ex ( Synapse ) := N.Ch_Ex ( Synapse ) + dt * dCh_Ex ( Synapse );
    N.Ch_Cl ( Synapse ) := N.Ch_Cl ( Synapse ) + dt * dCh_Cl ( Synapse );
  end loop;
  Transmitter_Change ( dTrans, N.Trans, M, N.Ch_Ex, N.Ch_Cl, De_Tra );
  for Synapse in N.Trans'range loop
    N.Trans ( Synapse ) := N.Trans ( Synapse ) + dt * dTrans ( Synapse );
    Put ( "Tr:" ); Put ( N.Trans ( Synapse ), 2, 1, 0 ); Put ( " " );
  end loop;
end Neuron_Update;

procedure Nonlinear_Get (
	    dTime, Mult, Sl_Na, Sl_K, Thr_Na, Thr_K, De_Tra
	      : in out float ) is
---------------------------------------------------------------------------
begin
  dTime  := Ask ( "dTime  ", dTime  );
  Mult   := Ask ( "Mult   ", Mult   );
  Sl_Na  := Ask ( "Sl_Na  ", Sl_Na  );
  Sl_K   := Ask ( "Sl_K   ", Sl_K   );
  Thr_Na := Ask ( "Thr_Na ", Thr_Na );
  Thr_K  := Ask ( "Thr_K  ", Thr_K  );
  De_Tra := Ask ( "De_Tra ", De_Tra );
end Nonlinear_Get;

procedure Start (
	    Neuron_Count : in positive := 1;
	    dTime, Sl_Na, Sl_K, Act_Na, Act_K, Thr_Na, Thr_K, De_Tra,
	    Ini_Na, Ini_K  : in float ) is
---------------------------------------------------------------------------
  type Net_Type is array ( 1..Neuron_Count )
    of Neuron_Type ( Neuron_Count );
  Net  :          Net_Type
    := ( others => (
      Neuron_Count => Neuron_Count,
      Trans => ( others =>  0.0 ),
      Ch_Ex => ( others => 10.0 ),
      Ch_Cl => ( others =>  1.0 ),
      A_Na  => Act_Na * Sigmoid ( Sl_Na * ( -Thr_Na ) ),
      A_K   => Act_K  * Sigmoid ( Sl_K  * ( -Thr_K  ) ),
      P     => 0.0 ) );
  Time :          float := 0.0;
  L    : constant float := 0.0;
begin
  loop
    Put ( "T:" ); Put ( Time, 1, 1, 2 ); Put ( " " );
    for Neuron in Net'range loop
      for Synapse in Net ( Neuron ).Trans'range loop
	Net ( Neuron ).Trans ( Synapse )
	  := Net ( Neuron ).Trans ( Synapse )
	    + Inputs ( Time, dTime, Neuron_Count ) ( Synapse );
      end loop;
      Neuron_Update ( Net ( Neuron ), dTime, L,
	Sl_Na, Sl_K, Act_Na, Act_K, Thr_Na, Thr_K, De_Tra,
	  Ini_Na, Ini_K  );
      Put ( "P" & positive'image ( Neuron ) & ": " );
      Put ( Net ( Neuron ).P, 2, 2, 0 ); Put ( " " );
    end loop;
    Put_Line ( "" );
    Time := dTime + Time;
--    exit when Time >= 0.01;
  end loop;
end Start;

procedure Start2 is
---------------------------------------------------------------------------
  dTime  : float := 1.0E-8;
  Mult   : float := 1.0;
  Sl_Na  : float := 100.0;
  Sl_K   : float :=  1.0;
  Thr_Na : float := +1.00;
  Thr_K  : float := +0.0;
  De_Tra : float := 10.0;
  Act_Na : float;
  Act_K  : float;
  Ini_Na : float;
  Ini_K  : float;
---------------------------------------------------------------------------
begin
  loop
    Nonlinear_Get ( dTimeime, Mult, Sl_Na, Sl_K, Thr_Na, Thr_K, De_Tra );
    Act_Na := Mult *
      ( Sigmoid ( Sl_K  * ( - Thr_K  ) ) ) /
      ( Sigmoid ( Sl_Na * ( - Thr_Na ) ) );
    Act_K  := Mult * 1.0;
    Ini_Na := Act_Na * ( Sigmoid ( Sl_Na * ( - Thr_Na ) ) );
    Ini_K  := Act_K  * ( Sigmoid ( Sl_K  * ( - Thr_K  ) ) );
    Start ( 1, dTimeime, Sl_Na, Sl_K, Act_Na, Act_K, Thr_Na, Thr_K, De_Tra,
      Ini_Na, Ini_K );
  end loop;
end Start2;

---------------------------------------------------------------------------
---------------------------------------------------------------------------
begin
  Start2;
end FIST;
