unit UnitCalculateurFonction;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils,Symbolic,Math;

type
  tableauchaine=array of string;


  ECalculateurFonctionError = class(Exception);
  ECalculateurFonctionSyntaxError = class(ECalculateurFonctionError);
  ECalculateurFonctionListeVariablesError = class(ECalculateurFonctionError);

  TCalculateurFonction=class
    private
  _Expression:texpression;
  _ListeVariables:TStringList;
  _ListeValeursVariables:array of arbfloat;
  _Evaluator:TEvaluator;
  function CalcValue: float;
  function LitListeVariables:TStringList;
    function LitExpression:TExpression;
   public
  CONSTRUCTOR Create(Infix:String); overload;
  CONSTRUCTOR Create(Infix:String; ListeVariablesAutorisees:TStringList); overload;
  CONSTRUCTOR Create(Infix:String; ListeVariablesAutorisees:TableauChaine; NombreVariables:integer); overload;
 destructor Destroy;
  procedure SetVar(const VarName: string; const Value: float);
    function GetVariable(const VarName: string): arbfloat;
    property Variable[const VarName: string]: arbfloat read GetVariable write SetVar;
    published
    property Value: arbfloat read CalcValue stored false;
    property ListeVariables: tstringlist read LitListeVariables stored false;
    property Expression: texpression read LitExpression stored false;
   { property Expression: string read FExpression write SetExpression;}
  end;

implementation
  CONSTRUCTOR TCalculateurFonction.Create(Infix:String);
begin
if  _Evaluator<>nil then _Evaluator.Destroy;
if _expression<>nil then _expression.Destroy;
 SetLength(_ListeValeursVariables,0);
  try
    _Expression:=texpression.Create(infix);
  except
   raise   ECalculateurFonctionSyntaxError.Create('Syntaxe de fonction incorrecte');
   exit;
  end;
  _ListeVariables:=_Expression.SymbolicValueNames;
  SetLength(_ListeValeursVariables,_ListeVariables.Count);
 _Evaluator:=TEvaluator.Create(_ListeVariables,_Expression);
    end;


 CONSTRUCTOR TCalculateurFonction.Create(Infix:String; ListeVariablesAutorisees:TableauChaine; NombreVariables:integer); overload;
 var i:integer;  LVA:TStringlist;
 begin
 if  _Evaluator<>nil then _Evaluator.Destroy;
if _expression<>nil then _expression.Destroy;
 SetLength(_ListeValeursVariables,0);
  try
    _Expression:=texpression.Create(infix);
  except
   raise   ECalculateurFonctionSyntaxError.Create('Syntaxe de fonction incorrecte');
   exit;
  end;
  _ListeVariables:=_Expression.SymbolicValueNames;
  LVA:=TStringlist.Create;
  for i:=1 to NombreVariables do LVA.Add(ListeVariablesAutorisees[i-1]);
  for i:=1 to _ListeVariables.Count do
    if LVA.IndexOf(_ListeVariables[i-1])=-1 then begin
     LVA.Destroy;
     raise   ECalculateurFonctionListeVariablesError.Create('Variables non autorisées');
   exit;
  end;
  SetLength(_ListeValeursVariables,_ListeVariables.Count);
 _Evaluator:=TEvaluator.Create(_ListeVariables,_Expression);
  end;

  CONSTRUCTOR TCalculateurFonction.Create(Infix:String; ListeVariablesAutorisees:TStringList); overload;
   var i:integer;
     begin
    if  _Evaluator<>nil then _Evaluator.Destroy;
if _expression<>nil then _expression.Destroy;
 SetLength(_ListeValeursVariables,0);
   try
    _Expression:=texpression.Create(infix);
  except
   raise   ECalculateurFonctionSyntaxError.Create('Syntaxe de fonction incorrecte');
   exit;
  end;
  _ListeVariables:=_Expression.SymbolicValueNames;
   for i:=1 to _ListeVariables.Count do
    if ListeVariablesAutorisees.IndexOf(_ListeVariables[i-1])=-1 then begin
     raise   ECalculateurFonctionListeVariablesError.Create('Variables non autorisées');
   exit;
  end;
   SetLength(_ListeValeursVariables,_ListeVariables.Count);
   _Evaluator:=TEvaluator.Create(_ListeVariables,_Expression);
     end;


  destructor TCalculateurFonction.Destroy;
   begin
    if _Evaluator<>nil then _Evaluator.Destroy;
  if _Expression<>nil then _Expression.Destroy;
 inherited destroy;

   end;

  procedure TCalculateurFonction.SetVar(const VarName: string; const Value: float);
   var index:integer;
   begin

  index:=_ListeVariables.IndexOf(UpCase(VarName));
  if index<>-1 then  _ListeValeursVariables[index]:=Value;
    end;

 function TCalculateurFonction.GetVariable(const VarName: string): float;
  var index:integer;
   begin

  index:=_ListeVariables.IndexOf(UpCase(VarName));
  if index<>-1 then  result:=_ListeValeursVariables[index];
    end;


 function TCalculateurFonction.CalcValue: arbfloat;
 var resultat:arbfloat;
 begin
 try
 resultat:=_Evaluator.Evaluate(_ListeValeursVariables);
 except
  result:=NAN;
  exit;
 end;
  result:=resultat;
 end;

 function TCalculateurFonction.LitListeVariables:TStringList;
 begin
 result:=_ListeVariables;
 end;

 function TCalculateurFonction.LitExpression:TExpression;
 begin
 result:=_Expression;
 end;


end.

