unit Unit4;

{$MODE Delphi}

interface

uses
  LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, densesolver, Ap, Buttons, StdCtrls, Grids, erg_base;

type
  TForm4 = class(TForm)
    Label1: TLabel;
    Edit1: TEdit;
    StringGrid1: TStringGrid;
    Button1: TButton;
    Label2: TLabel;
    BitBtn1: TBitBtn;
    BitBtn2: TBitBtn;
    CheckBox1: TCheckBox;
    Button2: TButton;
    procedure Button3Click(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure BitBtn2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  procedure InitStringGrid;

var
  Form4: TForm4;
  processNum: Integer;
  oldEquation: String;

implementation

uses Unit1;

{$R *.lfm}

procedure InitStringGrid;
var
  i: Integer;
begin
  Form4.StringGrid1.RowCount:=length(elements)+1;
  Form4.StringGrid1.Cells[1,0]:='consumed';
  Form4.StringGrid1.Cells[2,0]:='produced';
  Form4.StringGrid1.Cells[3,0]:='net production';
  for i:=0 to length(elements)-1 do
  begin
    Form4.StringGrid1.Cells[0,i+1]:=elements[i].name;
    Form4.StringGrid1.Cells[1,i+1]:=''; Form4.StringGrid1.Cells[2,i+1]:='';  Form4.StringGrid1.Cells[3,i+1]:='';
  end;
end;

procedure TForm4.Button3Click(Sender: TObject);
begin
end;

procedure TForm4.BitBtn1Click(Sender: TObject);
begin
  SetInputOutputEquation(oldEquation,processes[processNum]);
  Form4.Close;
end;

procedure TForm4.Button1Click(Sender: TObject);
var
  eval: Boolean; //whether the evaluation shall take place
  s: String;
  i: Integer;
begin
  DecimalSeparator:='.';
  eval:=true;
  if SetInputOutputEquation(Edit1.Text,processes[processNum])=false then
  begin
    eval:=false;
    if MessageDlg('An error occurs in the given equation. Click ignore to correct it manually or cancel to load the original equation',mtConfirmation,[mbIgnore,mbCancel],0)=mrCancel then
    begin
      Edit1.text:=oldEquation;
      SetInputOutputEquation(Edit1.Text,processes[processNum]);
      eval:=true;
    end;
  end;
  if eval then
  begin
    s:=GenerateIndexes;
    if s<>'' then
    begin
      ShowMessage(s);
      eval:=false;
    end;
  end;
  InitStringGrid;
  if eval then
  begin
    for i:=0 to length(elements)-1 do
    begin
      StringGrid1.Cells[1,i+1]:=FloatToStr(ElementCreatedByProcess_sink(i,processNum,CheckBox1.checked));
      StringGrid1.Cells[2,i+1]:=FloatToStr(ElementCreatedByProcess_source(i,processNum,CheckBox1.checked));
      StringGrid1.Cells[3,i+1]:=FloatToStr(ElementCreatedByProcess(i,processNum,CheckBox1.checked));
    end;
  end;
end;

procedure TForm4.Button2Click(Sender: TObject);
const
  epsilon = 0.0000000001;
var
  eval: Boolean; //whether the evaluation shall take place
  s: String;
  sleft, sright, sElements: TStringList;
  i, j, t: Integer;
  A: TReal2dArray;
  x, B: TReal1dArray;
  rep: DenseSolverLSReport;
  res: Integer;
  elemAmount: Real;
begin
  DecimalSeparator:='.';
  eval:=true;
  if SetInputOutputEquation(Edit1.Text,processes[processNum])=false then
  begin
    eval:=false;
    if MessageDlg('An error occurs in the given equation. Click ignore to correct it manually or cancel to load the original equation',mtConfirmation,[mbIgnore,mbCancel],0)=mrCancel then
    begin
      Edit1.text:=oldEquation;
      SetInputOutputEquation(Edit1.Text,processes[processNum]);
      eval:=true;
    end;
  end;
  if eval then
  begin
    s:=GenerateIndexes;
    if s<>'' then
    begin
      ShowMessage(s);
      eval:=false;
    end;
  end;
  if eval then
  begin
    for i:=0 to length(elements)-1 do
    begin
      StringGrid1.Cells[1,i+1]:=FloatToStr(ElementCreatedByProcess_sink(i,processNum,CheckBox1.checked));
      StringGrid1.Cells[2,i+1]:=FloatToStr(ElementCreatedByProcess_source(i,processNum,CheckBox1.checked));
      StringGrid1.Cells[3,i+1]:=FloatToStr(ElementCreatedByProcess(i,processNum,CheckBox1.checked));
    end;
    //define a matrix with rows=elements and columns = zero tracers
    setLength(A,length(elements),0);
    for i:=0 to length(processes[processNum].input)-1 do
      if processes[processNum].input[i].myAmount = 0 then
      begin
        setLength(A,length(elements),length(A[0])+1);
        t:=processes[processNum].input[i].myTracerNum;
        if tracers[t].isCombined=0 then
          for j:=0 to length(tracers[t].contents)-1 do
            A[tracers[t].contents[j].myElementNum,length(A[0])-1]:=tracers[t].contents[j].myAmount;
      end;
    for i:=0 to length(processes[processNum].output)-1 do
      if processes[processNum].output[i].myAmount = 0 then
      begin
        setLength(A,length(elements),length(A[0])+1);
        t:=processes[processNum].output[i].myTracerNum;
        if tracers[t].isCombined=0 then
          for j:=0 to length(tracers[t].contents)-1 do
            A[tracers[t].contents[j].myElementNum,length(A[0])-1]:=tracers[t].contents[j].myAmount;
      end;
    setLength(B,length(elements));
    for i:=0 to length(elements)-1 do
      B[i]:=-StrToFloat(StringGrid1.Cells[3,i+1]);
    setLength(x,length(A[0]));
    // Solve the equation Ax=b. As A can be rectangular, only the closest solution is obtained.
    densesolver.RMatrixSolveLs(A,length(A),length(A[0]),B,0,res,rep,x);
    if res=1 then  //the solver was successful
    begin
      selements:=TStringList.Create;
      //check if Ax=b by matrix multiplication
      for i:=0 to length(elements)-1 do
      begin
        elemAmount:=0;
        for j:=0 to length(x)-1 do
          elemAmount:=elemAmount+A[i,j]*x[j];
        elemAmount:=elemAmount-B[i];
        if abs(elemAmount)>epsilon then
          selements.Add(elements[i].name+' ('+elements[i].description+')'+chr(13));
      end;
      if sElements.Count>0 then
        showMessage('Could not balance the equation. The following elements are not balanced:'+chr(13)+selements.Text+chr(13)+'If you wish to conserve them, click cancel on the following suggestion and try to allow more tracers.');
      //create the output strings
      sleft:=TStringList.Create; sright:=TStringList.Create;
      j:=0;
      for i:=0 to length(processes[processNum].input)-1 do
        if processes[processNum].input[i].myAmount = 0 then
        begin
          t:=processes[processNum].input[i].myTracerNum;
          if tracers[t].isCombined=0 then
          begin
            if x[j]>0 then sright.add('+ '+FloatToStr(x[j])+'*'+tracers[t].name);
            if x[j]<0 then sleft.add('+ '+FloatToStr(-x[j])+'*'+tracers[t].name);
          end;
          j:=j+1;
        end;
      for i:=0 to length(processes[processNum].output)-1 do
        if processes[processNum].output[i].myAmount = 0 then
        begin
          t:=processes[processNum].output[i].myTracerNum;
          if tracers[t].isCombined=0 then
          begin
            if x[j]>0 then sright.add('+ '+FloatToStr(x[j])+'*'+tracers[t].name);
            if x[j]<0 then sleft.add('+ '+FloatToStr(-x[j])+'*'+tracers[t].name);
          end;
          j:=j+1;
        end;
      If MessageDlg('I will try to add to the left side:'+chr(13)+sleft.Text+chr(13)+'I will try to add to the right side:'+chr(13)+sright.Text,mtInformation,[mbYes,mbAbort],0)=mrYes then
      begin
        s:='';
        for i:=0 to sleft.Count-1 do
          s:=s+copy(sleft[i],2,length(sleft[i])) + ' + ';
        if copy(trim(Edit1.Text),1,2)='->' then s:=copy(s,1,length(s)-2);
        s:=s+Edit1.Text;
        if (copy(trim(s),length(trim(s))-1,2)<>'->') and (sright.Count>0) then s:=s+' + ';
        for i:=0 to sright.Count-1 do
          if i= sright.Count-1 then
            s:=s+copy(sright[i],2,length(sright[i]))
          else
            s:=s+copy(sright[i],2,length(sright[i])) + ' + ';
        Edit1.Text:=s;
        Button1click(self);
      end;
    end
    else
    begin
      if length(x)=0 then //no tracers with zero coefficients
        ShowMessage('Please add tracers with zero coefficients (e.g. + 0*h2o) to the equation to tell the solver which tracers might be added.')
      else
        ShowMessage('The solver could not solve the system of equations. Try to allow fewer tracers.');
    end;
  end;
end;

procedure TForm4.BitBtn2Click(Sender: TObject);
begin
  Button1click(self);
  SaveAllFiles;
  Form4.Close;
end;

end.
