// https://cognaxon.com
// https://neuroclusterbrain.com
// "Greek and Latin Roots Finder" is free open-source cross-platform software made by Cognaxon for neuroclusterbrain.com.
// Last updated: 2025-11-15


unit greek_and_latin_basic_word_parts_unit;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  StdCtrls, Grids, IniFiles, Math, Clipbrd, Menus, ExtCtrls, LCLType,
  ArraySortingFunctions,

  {$IF Defined(UNIX)}
  dl, // shared library path
  BaseUnix,// shared library path
  {$ENDIF} // {$IF (Defined(UNIX)}

  {$IFDEF WINDOWS}
  Win32Proc,
  Windows, // causes compilation problem with function Rect(...), need to use "Classes.Rect(...)"
  Registry, //registry
  //  jwawinreg, //registry
  {$ENDIF}


  //  Displays file version info for
  //- Windows PE executables
  //- Linux ELF executables (compiled by Lazarus)
  //- macOS MACH-O executables (compiled by Lazarus)
  //  Runs on Windows, Linux, macOS
  {$IFDEF UNIX}
  RegExpr,
  dos, // needed for macOS "DosVersion" function
    // Do you have UseCThreads defined? (Usually in Project -> Project Options -> Compiler Options -> Custom Options -> Defines)
  {$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}//UseCThreads
  {$ENDIF}//UNIX

  // FPC 3.0 fileinfo reads exe resources as long as you register the appropriate units
  fileinfo,
  winpeimagereader, //need this for reading exe info
  elfreader, //needed for reading ELF executables
  machoreader, //needed for reading MACH-O executables
  process, Types; //needed for TProcess


type

  { TGreekAndLatinRootsMainForm }

  TGreekAndLatinRootsMainForm = class(TForm)
    AnalyseTextButton: TButton;
    AnswerStatisticsLabel: TLabel;
    MainMenu: TMainMenu;
    NextButton: TButton;
    ChooseAnswerGroupBox: TGroupBox;
    ChooseAnswerRadioButton1: TRadioButton;
    ChooseAnswerRadioButton2: TRadioButton;
    ChooseAnswerRadioButton3: TRadioButton;
    ChooseAnswerRadioButton4: TRadioButton;
    ChooseAnswerRadioButton5: TRadioButton;
    ChooseAnswerRadioButton6: TRadioButton;
    AboutMemo: TMemo;
    DebugStringGrid: TStringGrid;
    GoodAnswerMemo: TMemo;
    InvisibleRadioButton: TRadioButton;
    TestLabel: TLabel;
    OutputTextMemo2: TMemo;
    OpenButton: TButton;
    FullListCheckBox: TCheckBox;
    InputTextEdit: TEdit;
    OutputTextMemo: TMemo;
    ProgressBarLabel: TLabel;
    PasteButton: TButton;
    GreekAndLatinRootsPageControl: TPageControl;
    MenuTabSheet: TTabSheet;
    AboutTabSheet: TTabSheet;
    DebugTabSheet: TTabSheet;
    ProgressBar: TProgressBar;
    GreekAndLatinRootsTableStringGrid: TStringGrid;
    TestTabSheet: TTabSheet;
    TextTabSheet: TTabSheet;
    GreekAndLatinRootsTableSheet: TTabSheet;
    InputTextEditSetFocusTimer: TTimer;
    procedure AboutTabSheetEnter(Sender: TObject);
    procedure AnalyseTextButtonClick(Sender: TObject);
    procedure ChooseAnswerRadioButton1Click(Sender: TObject);
    procedure ChooseAnswerRadioButton2Click(Sender: TObject);
    procedure ChooseAnswerRadioButton3Click(Sender: TObject);
    procedure ChooseAnswerRadioButton4Click(Sender: TObject);
    procedure ChooseAnswerRadioButton5Click(Sender: TObject);
    procedure ChooseAnswerRadioButton6Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FullListCheckBoxChange(Sender: TObject);
    procedure GreekAndLatinRootsPageControlEnter(Sender: TObject);
    procedure GreekAndLatinRootsTableSheetEnter(Sender: TObject);
    procedure InputTextEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure InputTextEditSetFocusTimerTimer(Sender: TObject);
    procedure MenuTabSheetEnter(Sender: TObject);
    procedure MenuTabSheetShow(Sender: TObject);
    procedure NextButtonClick(Sender: TObject);
    procedure OpenButtonClick(Sender: TObject);
    procedure PasteButtonClick(Sender: TObject);
    procedure TestTabSheetEnter(Sender: TObject);
  private
    { private declarations }
    function IsWindows64: Boolean;
  public
    { public declarations }
    procedure InitializeGreekAndLatinRootsEngine();
    procedure AnalyseInputText();

    function MessageDlgEx(const AMsg: string; ADlgType: TMsgDlgType; AButtons: TMsgDlgButtons; AParent: TForm): TModalResult;


  end;

var
  GreekAndLatinRootsMainForm: TGreekAndLatinRootsMainForm;

  initialized_greek_and_latin_roots_engine :Integer;
  filename_of_Greek_and_Latin_roots_finder, ini_filename, ini_filepath, application_path, data_filename: TFileName;
  ProgramIniFile: TIniFile;

  input_text_string, input_text_string_lower_case, output_text_string: String;
  input_text_memo: TMemo;
  greek_and_latin_roots_table_memo: TMemo;
  open_dialog: TOpenDialog;

  root_stringlist, found_root_stringlist, reduced_found_root_stringlist, sorted_reduced_found_root_stringlist: TStringList;
  root_index_number, found_root_index_number, reduced_found_root_index_number, sorted_reduced_found_root_index_number, index_sorted_reduced_found_root_index_number: array of Integer;
  root_index_n: Integer;
  root_found_at_position: Integer;
  skip_root: Integer;

  temp_string, temp_string_1, temp_string_2: String;
  temp_pos: Integer;
  index_of_found_substring: Integer;
  random_i, old_random_i, good_index_i, previous_good_index_i, good_answer_i, chosen_answer_i: Integer;
  number_of_bad_answers, number_of_good_answers: Integer;
  percentage_of_good_answers: Double;

  html_string: String;

  current_tab_item, previous_tab_item: Integer;

  FileVerInfo: TFileVersionInfo;


const
  TAB_ITEM_NONE : Integer = 0;
  TAB_ITEM_MENU : Integer = 1;
  TAB_ITEM_ROOT_TABLE : Integer = 2;
  TAB_ITEM_TEST : Integer = 3;
  TAB_ITEM_ABOUT : Integer = 4;


implementation

{$R *.lfm}

{ TGreekAndLatinRootsMainForm }


function TGreekAndLatinRootsMainForm.MessageDlgEx(const AMsg: string; ADlgType: TMsgDlgType;
  AButtons: TMsgDlgButtons; AParent: TForm): TModalResult;
var
  MsgFrm: TForm;
begin
  MsgFrm := CreateMessageDialog(AMsg, ADlgType, AButtons);
  try
    MsgFrm.Position := poDefaultSizeOnly;
    MsgFrm.FormStyle := fsSystemStayOnTop;
    MsgFrm.Left := AParent.Left + (AParent.Width - MsgFrm.Width) div 2;
    MsgFrm.Top := AParent.Top + (AParent.Height - MsgFrm.Height) div 2;
    Result := MsgFrm.ShowModal;
  finally
    MsgFrm.Free
  end;
end;



procedure TGreekAndLatinRootsMainForm.FormCreate(Sender: TObject);
{$IFDEF DARWIN}
var
     AppMenu     : TMenuItem;
{$ENDIF}
begin



  {$IFDEF DARWIN}
  AppMenu := TMenuItem.Create(Self); // Application menu
  AppMenu.Caption := #$EF#$A3#$BF;   // Unicode Apple logo char
  MainMenu.Items.Insert(0, AppMenu);
  {$ENDIF}


  DebugTabSheet.TabVisible := false;
  TextTabSheet.TabVisible := false;
  OpenButton.Visible := false;

  current_tab_item := TAB_ITEM_MENU;
  previous_tab_item := TAB_ITEM_MENU;

  //FullListLabel.Text := 'Reduced list';
  ////FullListLabel.Text := 'Full list';

  InvisibleRadioButton.Checked := true; // fixes Lazarus bug, because in Lazarus one RadioButton must be checked

  ChooseAnswerGroupBox.Visible := false;
  GoodAnswerMemo.Visible := false;
  AnswerStatisticsLabel.Visible := false;
  NextButton.Caption := 'Start';

  initialized_greek_and_latin_roots_engine := 0;
  ProgressBar.Visible := false;
  ProgressBarLabel.Visible := false;

  TestLabel.Caption := '';
  GoodAnswerMemo.Lines.Clear();

  InputTextEdit.Text := 'Enter word';
  InputTextEdit.SelectAll();


  random_i := 0;
  old_random_i := 0;
  good_index_i := 0;
  previous_good_index_i := 0;

  number_of_bad_answers := 0;
  number_of_good_answers := 0;
  percentage_of_good_answers := 0.0;


  OutputTextMemo.WordWrap := true;
  GoodAnswerMemo.WordWrap := true;

  input_text_memo := TMemo.Create(nil);
  greek_and_latin_roots_table_memo := TMemo.Create(nil);


  open_dialog := TOpenDialog.Create(Self);

  open_dialog.Filter := 'Txt Filesor*.txt';
  open_dialog.FileName := '';
  open_dialog.FilterIndex := 1;

  root_stringlist := TStringList.Create();
  found_root_stringlist := TStringList.Create();
  reduced_found_root_stringlist := TStringList.Create();
  sorted_reduced_found_root_stringlist := TStringList.Create();

  root_index_n := 0;

    DebugStringGrid.ColCount := 5;
    GreekAndLatinRootsTableStringGrid.ColCount := 5;

    DebugStringGrid.RowCount := 3;
    GreekAndLatinRootsTableStringGrid.RowCount := 3;



    GreekAndLatinRootsTableStringGrid.ColWidths[0] := 200;
    GreekAndLatinRootsTableStringGrid.ColWidths[1]  := 200;
    GreekAndLatinRootsTableStringGrid.ColWidths[2]  := 100;
    GreekAndLatinRootsTableStringGrid.ColWidths[3]  := 200;
    GreekAndLatinRootsTableStringGrid.ColWidths[4]  := 2000;


  GreekAndLatinRootsTableStringGrid.Cells[0, 0] := 'Basic word part';
  GreekAndLatinRootsTableStringGrid.Cells[1, 0] := 'Meaning in English';
  GreekAndLatinRootsTableStringGrid.Cells[2, 0] := 'Origin language';
  GreekAndLatinRootsTableStringGrid.Cells[3, 0] := 'Etymology (basic word part origin)';
  GreekAndLatinRootsTableStringGrid.Cells[4, 0] := 'English examples';





  AboutMemo.WordWrap := true;
  AboutMemo.Lines.Clear();


  FileVerInfo := TFileVersionInfo.Create(nil);

  try
  FileVerInfo.ReadFileInfo;
  //AboutMemo.Lines.Add('Greek and Latin roots finder v. ' + FileVerInfo.VersionStrings.Values['FileVersion']);
  AboutMemo.Lines.Add('Greek and Latin roots finder. Version ' + FileVerInfo.VersionStrings.Values['ProductVersion']);
  finally
    FileVerInfo.Free;
  end;

  //AboutMemo.Lines.Add('Greek and Latin roots finder. Version 2.5');
  AboutMemo.Lines.Add('');
  AboutMemo.Lines.Add('"Greek and Latin roots finder" is free open-source cross-platform software made by Cognaxon');
  AboutMemo.Lines.Add('https://cognaxon.com');
  AboutMemo.Lines.Add('');
  AboutMemo.Lines.Add('You can increase your vocabulary without memorizing a lot of words.');
  AboutMemo.Lines.Add('Words are composed of word parts: prefixes, suffixes and roots.');
  AboutMemo.Lines.Add('A knowledge of these word parts and their meanings can help you to unlock the meaning of unfamiliar words.');
  AboutMemo.Lines.Add('Most modern English words are derived from Anglo-Saxon (Old English), Latin and Greek.');
  AboutMemo.Lines.Add('Build your vocabulary by mastering basic word parts.');
  AboutMemo.Lines.Add('Learning 30 key word parts can help you unlock the meaning of over 10,000 words.');
  AboutMemo.Lines.Add('Learning 50 key word parts can help you unlock the meaning of over 100,000 words.');
  AboutMemo.Lines.Add('');
  AboutMemo.Lines.Add('The source of data is:');
  AboutMemo.Lines.Add('https://en.wikipedia.org/wiki/List_of_Greek_and_Latin_roots_in_English');
  AboutMemo.Lines.Add('List of Greek and Latin roots in English');
  AboutMemo.Lines.Add('');
  AboutMemo.Lines.Add('Full description is available at the address:');
  AboutMemo.Lines.Add('https://neuroclusterbrain.com/greek_and_latin_roots_in_english_language.html');
  AboutMemo.Lines.Add('');
  AboutMemo.Lines.Add('Last updated: 2021-06-23');


//??  InputTextEdit.SetFocus();




    ini_filename := ChangeFileExt( ParamStr(0), '.ini' );
    ini_filepath := ExtractFilePath(ini_filename);

{$IF Defined(DARWIN)}
filename_of_Greek_and_Latin_roots_finder := ExtractFilePath(ExcludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)))) + 'Resources/Greek_and_Latin_basic_word_parts.txt';
//{$ELSEIF Defined(WINDOWS)}

//{$ELSEIF Defined(LINUX)}

{$ELSE}
filename_of_Greek_and_Latin_roots_finder := ExtractFilePath(ParamStr(0)) + 'Greek_and_Latin_basic_word_parts.txt';
{$IFEND}


//MessageDlgEx(PCHAR(filename_of_Greek_and_Latin_roots_finder), mtInformation, [mbOk], GreekAndLatinRootsMainForm);

//ShowMessage(filename_of_Greek_and_Latin_roots_finder);


  GreekAndLatinRootsPageControl.ActivePage := MenuTabSheet;




end;

procedure TGreekAndLatinRootsMainForm.FormResize(Sender: TObject);
begin


  OutputTextMemo.Left := 0;
  OutputTextMemo.Top := 117;

  OutputTextMemo.Width := GreekAndLatinRootsMainForm.Width - OutputTextMemo.Left - 20;
  OutputTextMemo.Height := GreekAndLatinRootsMainForm.Height - OutputTextMemo.Top - 70;


  GoodAnswerMemo.Left := 0;
  GoodAnswerMemo.Top := 117;

  GoodAnswerMemo.Width := GreekAndLatinRootsMainForm.Width - GoodAnswerMemo.Left - 20;
  GoodAnswerMemo.Height := GreekAndLatinRootsMainForm.Height - GoodAnswerMemo.Top - 70;


end;

procedure TGreekAndLatinRootsMainForm.FullListCheckBoxChange(Sender: TObject);
begin

  AnalyseTextButtonClick(Self);

end;

procedure TGreekAndLatinRootsMainForm.GreekAndLatinRootsPageControlEnter(
  Sender: TObject);
begin

if(initialized_greek_and_latin_roots_engine = 0) then
begin
GreekAndLatinRootsTableSheet.Enabled := false;
InitializeGreekAndLatinRootsEngine();
GreekAndLatinRootsTableSheet.Enabled := true;
end;

end;

procedure TGreekAndLatinRootsMainForm.GreekAndLatinRootsTableSheetEnter(
  Sender: TObject);
begin


previous_tab_item := current_tab_item;
current_tab_item := TAB_ITEM_ROOT_TABLE;

if(previous_tab_item = TAB_ITEM_ROOT_TABLE) then
begin
 exit;
end;

TestLabel.Caption := '';

if(initialized_greek_and_latin_roots_engine = 0) then
begin
GreekAndLatinRootsTableSheet.Enabled := false;
InitializeGreekAndLatinRootsEngine();
GreekAndLatinRootsTableSheet.Enabled := true;
end;

end;

procedure TGreekAndLatinRootsMainForm.InputTextEditKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin

if(Key = Word(#13)) then
begin
  AnalyseTextButtonClick(Self);
end

end;

procedure TGreekAndLatinRootsMainForm.InputTextEditSetFocusTimerTimer(
  Sender: TObject);
begin

InputTextEditSetFocusTimer.Enabled := false;
InputTextEdit.SetFocus();
//InputTextEdit.SelectAll();


end;

procedure TGreekAndLatinRootsMainForm.MenuTabSheetEnter(Sender: TObject);
begin


previous_tab_item := current_tab_item;
current_tab_item := TAB_ITEM_MENU;

if(previous_tab_item = TAB_ITEM_MENU) then
begin
 exit;
end;

TestLabel.Caption := '';
OutputTextMemo.Lines.Clear();

InputTextEdit.Text := 'Enter word';



end;

procedure TGreekAndLatinRootsMainForm.MenuTabSheetShow(Sender: TObject);
begin

InputTextEditSetFocusTimer.Enabled := true;

end;





procedure TGreekAndLatinRootsMainForm.NextButtonClick(Sender: TObject);
begin


  NextButton.Caption := 'Next';

  if(initialized_greek_and_latin_roots_engine = 0) then
  begin
  InitializeGreekAndLatinRootsEngine();
  end;

  ChooseAnswerGroupBox.Visible := true;
  GoodAnswerMemo.Visible := false;

  InvisibleRadioButton.Checked := true; // fixes Lazarus bug, because in Lazarus one RadioButton must be checked
  ChooseAnswerRadioButton1.Checked := false;
  ChooseAnswerRadioButton2.Checked := false;
  ChooseAnswerRadioButton3.Checked := false;
  ChooseAnswerRadioButton4.Checked := false;
  ChooseAnswerRadioButton5.Checked := false;
  ChooseAnswerRadioButton6.Checked := false;


  //i := root_stringlist.Count - 1; maximum value
  //int random(int num);
  //Random number generator.
  //random returns a random number between 0 and abs(num-1). random(num) is a macro defined in stdlib.h.
  //Both num and the random number returned are integers with a maximum value of LRAND_MAX.


  Randomize; // This way we generate a new sequence every time the program is run

  while(previous_good_index_i = good_index_i) do
  begin
   random_i := Random(root_stringlist.Count);
   good_index_i := random_i;
  end;

  previous_good_index_i := good_index_i;


  TestLabel.Caption := root_stringlist.Strings[random_i];

  //GoodAnswerLabel.Caption := '   Root: ' + GreekAndLatinRootsTableStringGrid.Cells[0, root_index_number[random_i]] + '\n   Meaning in English: ' + GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]] + '\n   Origin language: ' + GreekAndLatinRootsTableStringGrid.Cells[2, root_index_number[random_i]] + '\n   Etymology (root origin): ' + GreekAndLatinRootsTableStringGrid.Cells[3, root_index_number[random_i]] + '\n   English examples: ' + GreekAndLatinRootsTableStringGrid.Cells[4, root_index_number[random_i]];

  GoodAnswerMemo.Lines.Clear();
  GoodAnswerMemo.Lines.Add('Root: ');
  GoodAnswerMemo.Lines.Add(GreekAndLatinRootsTableStringGrid.Cells[0, root_index_number[random_i]]);
  GoodAnswerMemo.Lines.Add('');
  GoodAnswerMemo.Lines.Add('Meaning in English: ');
  GoodAnswerMemo.Lines.Add(GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]]);
  GoodAnswerMemo.Lines.Add('');
  GoodAnswerMemo.Lines.Add('Origin language: ');
  GoodAnswerMemo.Lines.Add(GreekAndLatinRootsTableStringGrid.Cells[2, root_index_number[random_i]]);
  GoodAnswerMemo.Lines.Add('');
  GoodAnswerMemo.Lines.Add('Etymology (root origin): ');
  GoodAnswerMemo.Lines.Add(GreekAndLatinRootsTableStringGrid.Cells[3, root_index_number[random_i]]);
  GoodAnswerMemo.Lines.Add('');
  GoodAnswerMemo.Lines.Add('English examples: ');
  GoodAnswerMemo.Lines.Add(GreekAndLatinRootsTableStringGrid.Cells[4, root_index_number[random_i]]);

  random_i := Random(root_stringlist.Count);
  ChooseAnswerRadioButton1.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]];
  random_i := Random(root_stringlist.Count);
  ChooseAnswerRadioButton2.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]];
  random_i := Random(root_stringlist.Count);
  ChooseAnswerRadioButton3.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]];
  random_i := Random(root_stringlist.Count);
  ChooseAnswerRadioButton4.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]];
  random_i := Random(root_stringlist.Count);
  ChooseAnswerRadioButton5.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]];
  random_i := Random(root_stringlist.Count);
  ChooseAnswerRadioButton6.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[random_i]];


  random_i := Random(6);
  if(random_i = 0) then
  begin

  ChooseAnswerRadioButton1.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[good_index_i]];
  good_answer_i := 0;
  end
  else if(random_i = 1) then
  begin

  ChooseAnswerRadioButton2.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[good_index_i]];
  good_answer_i := 1;
  end
  else if(random_i = 2) then
  begin

  ChooseAnswerRadioButton3.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[good_index_i]];
  good_answer_i := 2;
  end
  else if(random_i = 3) then
  begin

  ChooseAnswerRadioButton4.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[good_index_i]];
  good_answer_i := 3;
  end
  else if(random_i = 4) then
  begin

  ChooseAnswerRadioButton5.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[good_index_i]];
  good_answer_i := 4;
  end
  else if(random_i = 5) then
  begin

  ChooseAnswerRadioButton6.Caption := GreekAndLatinRootsTableStringGrid.Cells[1, root_index_number[good_index_i]];
  good_answer_i := 5;
  end;


  if (AnswerStatisticsLabel.Visible = false) then
  begin
  AnswerStatisticsLabel.Visible := true;
  end;


end;

procedure TGreekAndLatinRootsMainForm.OpenButtonClick(Sender: TObject);
begin

OpenButton.Enabled := false;
PasteButton.Enabled := false;
AnalyseTextButton.Enabled := false;
InputTextEdit.Enabled := false;


if ( open_dialog.Execute() ) then
begin
Cursor := crHourGlass;


if(initialized_greek_and_latin_roots_engine = 0) then
begin
InitializeGreekAndLatinRootsEngine();
end;


input_text_memo.Lines.Clear();
input_text_memo.Lines.LoadFromFile(open_dialog.FileName);
input_text_string := '';


//(open_dialog.FileName);
Cursor := crDefault;
end;//if ( open_dialog.Execute() )


OpenButton.Enabled := true;
PasteButton.Enabled := true;
AnalyseTextButton.Enabled := true;
InputTextEdit.Enabled := true;

end;

procedure TGreekAndLatinRootsMainForm.PasteButtonClick(Sender: TObject);
begin

OpenButton.Enabled := false;
PasteButton.Enabled := false;
AnalyseTextButton.Enabled := false;
InputTextEdit.Enabled := false;

InputTextEdit.text := Clipboard.AsText;

AnalyseTextButtonClick(Self);

OpenButton.Enabled := true;
PasteButton.Enabled := true;
AnalyseTextButton.Enabled := true;
InputTextEdit.Enabled := true;


end;

procedure TGreekAndLatinRootsMainForm.TestTabSheetEnter(Sender: TObject);
begin


previous_tab_item := current_tab_item;
current_tab_item := TAB_ITEM_TEST;

if(previous_tab_item = TAB_ITEM_TEST) then
begin
 exit;
end;


number_of_bad_answers := 0;
number_of_good_answers := 0;
percentage_of_good_answers := 0.0;

ChooseAnswerGroupBox.Visible := false;

GoodAnswerMemo.Lines.Clear();

GoodAnswerMemo.Lines.Clear();
GoodAnswerMemo.Visible := false; // sometimes does not work for unknown reason
AnswerStatisticsLabel.Visible := false;
NextButton.Caption := 'Start';



AnswerStatisticsLabel.Caption := 'Answer statistics: ' + IntToStr(number_of_bad_answers) + ' incorrect; ' + IntToStr(number_of_good_answers) + ' correct; ' + FloatToStr(percentage_of_good_answers) + ' % percentage of correct answers.';


end;





procedure TGreekAndLatinRootsMainForm.AnalyseTextButtonClick(Sender: TObject);
begin

OpenButton.Enabled := false;
PasteButton.Enabled := false;
AnalyseTextButton.Enabled := false;
InputTextEdit.Enabled := false;


if(initialized_greek_and_latin_roots_engine = 0) then
begin
InitializeGreekAndLatinRootsEngine();
end;

input_text_string := InputTextEdit.Text;


AnalyseInputText();

OpenButton.Enabled := true;
PasteButton.Enabled := true;
AnalyseTextButton.Enabled := true;
InputTextEdit.Enabled := true;

end;

procedure TGreekAndLatinRootsMainForm.AboutTabSheetEnter(Sender: TObject);
begin


previous_tab_item := current_tab_item;
current_tab_item := TAB_ITEM_ABOUT;

if(previous_tab_item = TAB_ITEM_ABOUT) then
begin
 exit;
end;

TestLabel.Caption := '';


end;

procedure TGreekAndLatinRootsMainForm.ChooseAnswerRadioButton1Click(
  Sender: TObject);
begin


chosen_answer_i := 0;

if(chosen_answer_i = good_answer_i) then
begin
ChooseAnswerGroupBox.Visible := false;
GoodAnswerMemo.Visible := true;
number_of_good_answers := number_of_good_answers + 1;
end
else
begin
number_of_bad_answers := number_of_bad_answers  + 1;;
end;

percentage_of_good_answers := RoundTo(100.0*number_of_good_answers /  (number_of_bad_answers + number_of_good_answers), 0);
AnswerStatisticsLabel.Caption := 'Answer statistics: ' + IntToStr(number_of_bad_answers) + ' incorrect; ' + IntToStr(number_of_good_answers) + ' correct; ' + FloatToStr(percentage_of_good_answers) + ' % percentage of correct answers.';


end;

procedure TGreekAndLatinRootsMainForm.ChooseAnswerRadioButton2Click(
  Sender: TObject);
begin


chosen_answer_i := 1;

if(chosen_answer_i = good_answer_i) then
begin
ChooseAnswerGroupBox.Visible := false;
GoodAnswerMemo.Visible := true;
number_of_good_answers := number_of_good_answers + 1;
end
else
begin
number_of_bad_answers := number_of_bad_answers  + 1;;
end;

percentage_of_good_answers := RoundTo(100.0*number_of_good_answers /  (number_of_bad_answers + number_of_good_answers), 0);
AnswerStatisticsLabel.Caption := 'Answer statistics: ' + IntToStr(number_of_bad_answers) + ' incorrect; ' + IntToStr(number_of_good_answers) + ' correct; ' + FloatToStr(percentage_of_good_answers) + ' % percentage of correct answers.';


end;

procedure TGreekAndLatinRootsMainForm.ChooseAnswerRadioButton3Click(
  Sender: TObject);
begin


chosen_answer_i := 2;

if(chosen_answer_i = good_answer_i) then
begin
ChooseAnswerGroupBox.Visible := false;
GoodAnswerMemo.Visible := true;
number_of_good_answers := number_of_good_answers + 1;
end
else
begin
number_of_bad_answers := number_of_bad_answers  + 1;;
end;

percentage_of_good_answers := RoundTo(100.0*number_of_good_answers /  (number_of_bad_answers + number_of_good_answers), 0);
AnswerStatisticsLabel.Caption := 'Answer statistics: ' + IntToStr(number_of_bad_answers) + ' incorrect; ' + IntToStr(number_of_good_answers) + ' correct; ' + FloatToStr(percentage_of_good_answers) + ' % percentage of correct answers.';


end;

procedure TGreekAndLatinRootsMainForm.ChooseAnswerRadioButton4Click(
  Sender: TObject);
begin



chosen_answer_i := 3;

if(chosen_answer_i = good_answer_i) then
begin
ChooseAnswerGroupBox.Visible := false;
GoodAnswerMemo.Visible := true;
number_of_good_answers := number_of_good_answers + 1;
end
else
begin
number_of_bad_answers := number_of_bad_answers  + 1;;
end;

percentage_of_good_answers := RoundTo(100.0*number_of_good_answers /  (number_of_bad_answers + number_of_good_answers), 0);
AnswerStatisticsLabel.Caption := 'Answer statistics: ' + IntToStr(number_of_bad_answers) + ' incorrect; ' + IntToStr(number_of_good_answers) + ' correct; ' + FloatToStr(percentage_of_good_answers) + ' % percentage of correct answers.';


end;

procedure TGreekAndLatinRootsMainForm.ChooseAnswerRadioButton5Click(
  Sender: TObject);
begin


chosen_answer_i := 4;

if(chosen_answer_i = good_answer_i) then
begin
ChooseAnswerGroupBox.Visible := false;
GoodAnswerMemo.Visible := true;
number_of_good_answers := number_of_good_answers + 1;
end
else
begin
number_of_bad_answers := number_of_bad_answers  + 1;;
end;

percentage_of_good_answers := RoundTo(100.0*number_of_good_answers /  (number_of_bad_answers + number_of_good_answers), 0);
AnswerStatisticsLabel.Caption := 'Answer statistics: ' + IntToStr(number_of_bad_answers) + ' incorrect; ' + IntToStr(number_of_good_answers) + ' correct; ' + FloatToStr(percentage_of_good_answers) + ' % percentage of correct answers.';


end;

procedure TGreekAndLatinRootsMainForm.ChooseAnswerRadioButton6Click(
  Sender: TObject);
begin


chosen_answer_i := 5;

if(chosen_answer_i = good_answer_i) then
begin
ChooseAnswerGroupBox.Visible := false;
GoodAnswerMemo.Visible := true;
number_of_good_answers := number_of_good_answers + 1;
end
else
begin
number_of_bad_answers := number_of_bad_answers  + 1;;
end;

percentage_of_good_answers := RoundTo(100.0*number_of_good_answers /  (number_of_bad_answers + number_of_good_answers), 0);
AnswerStatisticsLabel.Caption := 'Answer statistics: ' + IntToStr(number_of_bad_answers) + ' incorrect; ' + IntToStr(number_of_good_answers) + ' correct; ' + FloatToStr(percentage_of_good_answers) + ' % percentage of correct answers.';



end;

procedure TGreekAndLatinRootsMainForm.FormClose(Sender: TObject;
  var CloseAction: TCloseAction);
begin

//delete input_text_memo;

input_text_memo.Free();
//?? input_text_memo := nil;

//delete greek_and_latin_roots_table_memo;

greek_and_latin_roots_table_memo.Free();
//?? greek_and_latin_roots_table_memo := nil;

//delete open_dialog;

open_dialog.Free();
//?? open_dialog := nil;

//delete root_stringlist;

root_stringlist.Free();
//?? root_stringlist := nil;

//delete found_root_stringlist;

found_root_stringlist.Free();
//?? found_root_stringlist := nil;

//delete reduced_found_root_stringlist;

reduced_found_root_stringlist.Free();
//?? reduced_found_root_stringlist := nil;

//delete sorted_reduced_found_root_stringlist;

sorted_reduced_found_root_stringlist.Free();
//?? sorted_reduced_found_root_stringlist := nil;

//?? delete root_index_number;
//free(root_index_number);

//root_index_number.Free();
//root_index_number := nil;

//?? delete found_root_index_number;
//free(found_root_index_number);

//found_root_index_number.Free();
//found_root_index_number := nil;

//?? delete reduced_found_root_index_number;
//free(reduced_found_root_index_number);

//reduced_found_root_index_number.Free();
//reduced_found_root_index_number := nil;

//?? delete sorted_reduced_found_root_index_number;
//free(sorted_reduced_found_root_index_number);

//sorted_reduced_found_root_index_number.Free();
//sorted_reduced_found_root_index_number := nil;

//?? delete index_sorted_reduced_found_root_index_number;
//free(index_sorted_reduced_found_root_index_number);

//index_sorted_reduced_found_root_index_number.Free();
//index_sorted_reduced_found_root_index_number := nil;

end;

procedure TGreekAndLatinRootsMainForm.InitializeGreekAndLatinRootsEngine;
var
  i, i2, i3, i4, n_col : Integer;
  temp_char: CHAR;

  program_version_string: String;
  OS_version_string: String;
  compiled_for_OS: String;

  {$IF Defined (DARWIN)}
    ProfProcess: TProcess;
    path: string;
    ProfStringList: TStringList;
    Value: string;
    macOS_high_version, macOS_low_version: Integer;
  {$ELSEIF Defined (UNIX)}
  P: TProcess;
      Function ExecParam(Param: String): String;
      Begin
        P.Parameters[0]:= '-' + Param;
        P.Execute;
        SetLength(Result, 1000);
        SetLength(Result, P.Output.Read(Result[1], Length(Result)));
        While (Length(Result) > 0) And (Result[Length(Result)] In [#8..#13,#32]) Do
          SetLength(Result, Length(Result) - 1);
      End;
  {$ENDIF}

begin


  if (not FileExists(filename_of_Greek_and_Latin_roots_finder)) then
  begin
  ShowMessage('Error: database file' + #13#10 + filename_of_Greek_and_Latin_roots_finder + #13#10 + 'not found.');
  exit;
  end;


greek_and_latin_roots_table_memo.Lines.Clear();
greek_and_latin_roots_table_memo.Lines.LoadFromFile(filename_of_Greek_and_Latin_roots_finder);
GreekAndLatinRootsTableStringGrid.RowCount := greek_and_latin_roots_table_memo.Lines.Count;


SetLength(root_index_number, 2* greek_and_latin_roots_table_memo.Lines.Count);
SetLength(found_root_index_number, 2* greek_and_latin_roots_table_memo.Lines.Count);
SetLength(reduced_found_root_index_number, 2* greek_and_latin_roots_table_memo.Lines.Count);
SetLength(sorted_reduced_found_root_index_number, 2* greek_and_latin_roots_table_memo.Lines.Count);
SetLength(index_sorted_reduced_found_root_index_number, 2* greek_and_latin_roots_table_memo.Lines.Count);



ProgressBar.Position := 0;
ProgressBar.Visible := true;
ProgressBarLabel.Visible := true;
ProgressBarLabel.Caption := 'Initializing engine....';


for i := 1 to greek_and_latin_roots_table_memo.Lines.Count-1 do
begin

temp_string_1 := greek_and_latin_roots_table_memo.Lines.Strings[i];


for n_col := 0 to 4 do
begin

	temp_pos := Pos(CHR(9), temp_string_1); // Tab symbol // in mobile applications string indexes are different from desktop applications; in iOS string indexes are different from Windows

//	if (temp_pos <> -1) then //IndexOf returns -1 if not found
        if (temp_pos <> 0) then //Pos returns 0 if not found
	begin
          //0-based strings
	  //temp_string_2 := Copy(temp_string_1, 0, temp_pos);
	  //GreekAndLatinRootsTableStringGrid.Cells[n_col, i] := temp_string_2;
	  //temp_string_1 := Copy(temp_string_1, (temp_pos+1), Length(temp_string_1));

          //1-based strings
	  temp_string_2 := Copy(temp_string_1, 1, temp_pos-1);
	  GreekAndLatinRootsTableStringGrid.Cells[n_col, i] := temp_string_2;
	  temp_string_1 := Copy(temp_string_1, (temp_pos+1), Length(temp_string_1));

	end//	if (temp_pos <> 0)

        else //	else if (temp_pos = 0) then
	begin
        GreekAndLatinRootsTableStringGrid.Cells[n_col, i] := temp_string_1;

	//temp_pos := Length(temp_string_1);
	//temp_string_2 := Copy(temp_string_1, 1, temp_pos);
	//GreekAndLatinRootsTableStringGrid.Cells[n_col, i] := temp_string_2;
	//temp_string_1 := Copy(temp_string_1, (temp_pos+1), Length(temp_string_1));

	end;//else if (temp_pos = 0)




end;// for n_col := 0 to 4 do




ProgressBar.Position := i div greek_and_latin_roots_table_memo.Lines.Count * 50;
//Application.ProcessMessages(); //slows down incredibly MacOS




end;//for (int i := 0; i < greek_and_latin_roots_table_memo.Lines.Count; i++)


ProgressBar.Position := 50;



root_found_at_position := 0;

for i3 := 1 to greek_and_latin_roots_table_memo.Lines.Count-1 do
begin

temp_string_1 := GreekAndLatinRootsTableStringGrid.Cells[0, i3];
temp_string_2 := '';

for i4 := 1 to Length(temp_string_1) do
begin

//temp_char := CHAR((AnsiString(temp_string_1))[i4]);
temp_char := CHAR((temp_string_1)[i4]);

if((temp_char >= 'a') and (temp_char <= 'z')) then
begin
root_found_at_position := 1;
temp_string_2 := temp_string_2 + String(temp_char);
end//if((temp_char >:= 'a') & (temp_char >:= 'z'))
else
begin
  if( root_found_at_position = 1) then
  begin
   root_stringlist.Add(temp_string_2);
   root_index_number[root_index_n] := i3;
   root_index_n := root_index_n + 1;
  end;//if( root_found_at_position = 1)
   temp_string_2 := '';
   root_found_at_position := 0;
end;//else -. if((temp_char >:= 'a') & (temp_char >:= 'z'))


ProgressBar.Position := 50 + i div greek_and_latin_roots_table_memo.Lines.Count * 50;
//Application.ProcessMessages(); //slows down incredibly MacOS

end;//for (int i2 := 0; i2 < temp_string_1.Length; i2++)




end;//for (int i := 0; i < greek_and_latin_roots_table_memo.Lines.Count; i++)






  OS_version_string := 'Operating system: ';



  {$IF Defined (WINDOWS)}
  // https://fossies.org/linux/lazarus/lcl/interfaces/win32/win32proc.pp

  if WindowsVersion = wv95 then begin OS_version_string := OS_version_string + 'Windows 95' end
  else if WindowsVersion = wvNT4 then begin OS_version_string := OS_version_string + 'Windows NT v.4' end
  else if WindowsVersion = wv98 then begin OS_version_string := OS_version_string + 'Windows 98' end
  else if WindowsVersion = wvMe then begin OS_version_string := OS_version_string + 'Windows ME' end
  else if WindowsVersion = wv2000 then begin OS_version_string := OS_version_string + 'Windows 2000' end
  else if WindowsVersion = wvXP then begin OS_version_string := OS_version_string + 'Windows XP' end
  else if WindowsVersion = wvServer2003 then begin OS_version_string := OS_version_string + 'Windows Server 2003/Windows XP64' end
  else if WindowsVersion = wvVista then begin OS_version_string := OS_version_string + 'Windows Vista' end
  else if WindowsVersion = wv7 then begin OS_version_string := OS_version_string + 'Windows 7' end
  else if WindowsVersion = wv8 then begin OS_version_string := OS_version_string + 'Windows 8' end
  else if WindowsVersion = wv8_1 then begin OS_version_string := OS_version_string + 'Windows 8.1' end
  else if WindowsVersion = wv10 then begin OS_version_string := OS_version_string + 'Windows 10' end
  else if WindowsVersion = wv11 then begin OS_version_string := OS_version_string + 'Windows 11' end
  else if WindowsVersion = wvLater then begin OS_version_string := OS_version_string + 'Windows Later than 10' end
  else if WindowsVersion = wvUnknown then begin OS_version_string := OS_version_string + 'Windows Unknown Version' end
  else begin OS_version_string := OS_version_string + 'Windows Unknown Version' end;

  OS_version_string := OS_version_string + ' ' + Win32CSDVersion + ' (Version: '  +  IntToStr(Win32MajorVersion) + '.' + IntToStr(Win32MinorVersion) + ', Build: ' + IntToStr(Win32BuildNumber);

  try
    if IsWindows64 then
    begin
      OS_version_string := OS_version_string + ', 64-bit Edition)';
    end
    else
    begin
      OS_version_string := OS_version_string + ', 32-bit Edition)';
    end;
  except
    on E: exception do
    begin
      OS_version_string := OS_version_string + ', Could not determine bitness of operating system. Error details: ' + E.ClassName+'/'+E.Message + ')';
    end;
  end;

  {$ELSEIF Defined (DARWIN)}

  //   OS_version_string := 'Mac OS X 10.' + IntToStr(Lo(DosVersion) - 4) + '.' + IntToStr(Hi(DosVersion));

  path := 'sh -c "/usr/bin/sw_vers"';
  try
    ProfProcess := Tprocess.Create(nil);
    ProfProcess.CommandLine := path;
    ProfProcess.Options := ProfProcess.Options + [poUsePipes, poWaitOnExit];
    ProfProcess.Execute;
  except
    Exit;
  end;
  try
    ProfStringList := TStringList.Create;
    ProfStringList.LoadFromStream(ProfProcess.Output);
  except
    Exit;
  end;

  ProfProcess.Terminate(0);
  ProfStringList.NameValueSeparator:=':';


  macOS_low_version := Lo(DosVersion) - 4;
  macOS_high_version := Hi(DosVersion);

  if(macOS_low_version = 0) then
  OS_version_string := 'Mac OS X Cheetah (Version 10.0.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 1) then
  OS_version_string := 'Mac OS X Puma (Version 10.1.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 2) then
  OS_version_string := 'Mac OS X Jaguar (Version 10.2.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 3) then
  OS_version_string := 'Mac OS X Panther (Version 10.3.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 4) then
  OS_version_string := 'Mac OS X Tiger (Version 10.4.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 5) then
  OS_version_string := 'Mac OS X Leopard (Version 10.5.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 6) then
  OS_version_string := 'Mac OS X Snow Leopard (Version 10.6.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 7) then
  OS_version_string := 'OS X Lion (Version 10.7.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 8) then
  OS_version_string := 'OS X Mountain Lion (Version 10.8.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 9) then
  OS_version_string := 'OS X Mavericks (Version 10.9.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 10) then
  OS_version_string := 'OS X Yosemite (Version 10.10.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 11) then
  OS_version_string := 'OS X El Capitan (Version 10.11.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 12) then
  OS_version_string := 'macOS Sierra (Version 10.12.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 13) then
  OS_version_string := 'macOS High Sierra (Version 10.13.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 14) then
  OS_version_string := 'macOS Mojave (Version 10.14.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 15) then
  OS_version_string := 'macOS Catalina (Version 10.15.' + IntToStr(macOS_high_version) + ')'
  else if(macOS_low_version = 16) then
  OS_version_string := 'macOS Big Sur (Version 11.' + IntToStr(macOS_high_version-1) + ')'
  else
  OS_version_string := 'macOS';

  OS_version_string := OS_version_string + ' (' + Trim(ProfstringList.ValueFromIndex[2]) + ')';



  FreeAndNil(ProfProcess);
  FreeAndNil(ProfStringList);

  {$ELSEIF Defined (UNIX)}

  //OS_version_string := OS_version_string + 'Linux: ' + IntToStr(Lo(DosVersion) - 4) + '.' + IntToStr(Hi(DosVersion));

  P:= TProcess.Create(Nil);
  P.Options:= [poWaitOnExit, poUsePipes];
  P.Executable:= 'uname';
  P.Parameters.Add('');

  OS_version_string := OS_version_string + ExecParam('o');
  OS_version_string := OS_version_string + ', Architecture: ' + ExecParam('m');
  OS_version_string := OS_version_string + ', Kernel Name: ' + ExecParam('s');
  OS_version_string := OS_version_string + ', Kernel Release: ' + ExecParam('r');
  OS_version_string := OS_version_string + ', Kernel Version: ' + ExecParam('v');
  OS_version_string := OS_version_string + ', Network Node: ' + ExecParam('n');

  P.Free();

  {$ENDIF} //{$ELSEIF Defined (UNIX)}


  {$IF Defined (WIN32)}
  compiled_for_OS := 'Windows 32-bit';
  {$ELSEIF Defined (WIN64)}
  compiled_for_OS := 'Windows 64-bit';
  {$ELSEIF Defined (DARWIN)}
    {$IF Defined (CPU32)}
     compiled_for_OS := 'macOS 32-bit';
    {$ELSEIF Defined (CPU64)}
     compiled_for_OS := 'macOS 64-bit';
    {$ELSE}
     compiled_for_OS := 'macOS unknown';
    {$ENDIF}
  {$ELSEIF Defined (LINUX)}
    {$IF Defined (CPU32)}
    compiled_for_OS := 'Linux 32-bit';
    {$ELSEIF Defined (CPU64)}
      compiled_for_OS := 'Linux 64-bit';
    {$ELSE}
       compiled_for_OS := 'Linux unknown';
    {$ENDIF}
  {$ELSE}
  compiled_for_OS := 'Unknown OS';
  {$ENDIF}




AboutMemo.Lines.Clear();

FileVerInfo := TFileVersionInfo.Create(nil);

try
FileVerInfo.ReadFileInfo;
//AboutMemo.Lines.Add('Reaction Time Measurement v. ' + FileVerInfo.VersionStrings.Values['FileVersion']);
AboutMemo.Lines.Add('Greek and Latin roots finder. Version ' + FileVerInfo.VersionStrings.Values['ProductVersion']);
finally
  FileVerInfo.Free;
end;

//AboutMemo.Lines.Add('Greek and Latin roots finder. Version 2.5');
AboutMemo.Lines.Add('');
AboutMemo.Lines.Add('Basic word parts count = ' + IntToStr(root_stringlist.Count));
AboutMemo.Lines.Add('');
AboutMemo.Lines.Add('"Greek and Latin roots finder" is free open-source cross-platform software made by Cognaxon');
AboutMemo.Lines.Add('https://cognaxon.com');
AboutMemo.Lines.Add('');
AboutMemo.Lines.Add('You can increase your vocabulary without memorizing a lot of words.');
AboutMemo.Lines.Add('Words are composed of word parts: prefixes, suffixes and roots.');
AboutMemo.Lines.Add('A knowledge of these word parts and their meanings can help you to unlock the meaning of unfamiliar words.');
AboutMemo.Lines.Add('Most modern English words are derived from Anglo-Saxon (Old English), Latin and Greek.');
AboutMemo.Lines.Add('Build your vocabulary by mastering basic word parts.');
AboutMemo.Lines.Add('Learning 30 key word parts can help you unlock the meaning of over 10,000 words.');
AboutMemo.Lines.Add('Learning 50 key word parts can help you unlock the meaning of over 100,000 words.');
AboutMemo.Lines.Add('');
AboutMemo.Lines.Add('The source of data is:');
AboutMemo.Lines.Add('https://en.wikipedia.org/wiki/List_of_Greek_and_Latin_roots_in_English');
AboutMemo.Lines.Add('List of Greek and Latin roots in English');
AboutMemo.Lines.Add('');
AboutMemo.Lines.Add('Full description is available at the address:');
AboutMemo.Lines.Add('https://neuroclusterbrain.com/greek_and_latin_roots_in_english_language.html');
AboutMemo.Lines.Add('');
AboutMemo.Lines.Add('Greek and Latin roots finder compiled for ' + compiled_for_OS + ', compilation date: ' + {$include %date%} + ', time: ' + Format('%.*d',[2, {$include %timeHour%}]) + ':' + Format('%.*d',[2, {$include %timeMinute%}]) );

{
DebugStringGrid.RowCount := greek_and_latin_roots_table_memo.Lines.Count;

DebugStringGrid.RowCount := root_stringlist.Count;

for i := 0 to DebugStringGrid.RowCount - 1 do
begin
DebugStringGrid.Cells[0, i] := root_stringlist.Strings[i];
DebugStringGrid.Cells[1, i] := IntToStr(root_index_number[i]);
end;//for i := 0 to DebugStringGrid.RowCount - 1 do
}


//AboutMemo.Lines.Add('');
//AboutMemo.Lines.Add('Roots count := ' + IntToStr(greek_and_latin_roots_table_memo.Lines.Count));
//AboutMemo.Lines.Add('');
//AboutMemo.Lines.Add('Basic word parts count := ' + IntToStr(root_stringlist.Count));


ProgressBar.Position := 100;
ProgressBar.Visible := false;
ProgressBarLabel.Visible := false;

initialized_greek_and_latin_roots_engine := 1;


end;

procedure TGreekAndLatinRootsMainForm.AnalyseInputText;
var
 j, j2: Integer;
begin

OpenButton.Enabled := false;
PasteButton.Enabled := false;
AnalyseTextButton.Enabled := false;
InputTextEdit.Enabled := false;


//ShowMessage(IntToStr(Pos('b', 'abce')));   // == 2


//output_text_string := '<HTML><body><head><meta charset:=\'UTF-16\'></head>';

OutputTextMemo.Lines.Clear();
output_text_string := '';

input_text_string_lower_case := LowerCase(input_text_string);


found_root_stringlist.Clear();
reduced_found_root_stringlist.Clear();
sorted_reduced_found_root_stringlist.Clear();

//find all root in analysed word
for j := 0 to root_stringlist.Count - 1 do
begin
   index_of_found_substring := 0;
   index_of_found_substring := Pos((root_stringlist.Strings[j]), input_text_string_lower_case);


//   if (index_of_found_substring > -1) then // found //IndexOf returns -1 if not found
   if (index_of_found_substring > 0) then // found //Pos returns 0 if not found
   begin
   found_root_stringlist.Add(root_stringlist.Strings[j]);
   found_root_index_number[found_root_stringlist.Count-1] := root_index_number[j];

   if(((root_stringlist.Strings[j] = 'a') or (root_stringlist.Strings[j] = 'e')) and (index_of_found_substring > 1)) then
   begin
   found_root_stringlist.Delete(found_root_stringlist.Count-1);
   end

   end//if (index_of_found_substring > 0) // found
end;//for(int i := 0; i < ProductStringGrid.ColumnCount; i++)




//remove shorter version of roots, leave only longer version of root
for j := 0 to found_root_stringlist.Count - 1 do
begin

if(FullListCheckBox.Checked = false) then
begin

skip_root := 0;

for j2 := 0 to found_root_stringlist.Count - 1 do
begin

   index_of_found_substring := 0;
   index_of_found_substring := Pos(found_root_stringlist.Strings[j], found_root_stringlist.Strings[j2]);
//   index_of_found_substring := Pos(found_root_stringlist.Strings[j], found_root_stringlist.Strings[j2]);

//   ShowMessage(found_root_stringlist.Strings[j]);


if ((index_of_found_substring > 0) and (Length(found_root_stringlist.Strings[j]) <> Length(found_root_stringlist.Strings[j2]))) then // found //Pos returns 0 if not found
//   if ((index_of_found_substring > -1) and (Length(found_root_stringlist.Strings[j]) <> Length(found_root_stringlist.Strings[j2]))) then // found //IndexOf returns -1 if not found
   begin
	skip_root := 1;
   end;//if ((index_of_found_substring > 0) & (Length(found_root_stringlist.Strings[j]) <> Length(found_root_stringlist.Strings[j2]))) // found

   if(found_root_stringlist.Strings[j] = 'a') then
   begin
   skip_root := 0;
   end;

   if(found_root_stringlist.Strings[j] = 'e') then
   begin
   skip_root := 0;
   end;

   if(found_root_stringlist.Strings[j] = 'de') then
   begin
   skip_root := 0;
   end;

   if(found_root_stringlist.Strings[j] = 'in') then
   begin
   skip_root := 0;
   end;

   if(found_root_stringlist.Strings[j] = 'im') then
   begin
   skip_root := 0;
   end;

   if(found_root_stringlist.Strings[j] = 'il') then
   begin
   skip_root := 0;
   end;

   if(found_root_stringlist.Strings[j] = 'ir') then
   begin
   skip_root := 0;
   end;


end;//for(int j2 := 0; j2 < found_root_stringlist.Count; j2++)

end//if(FullListCheckBox.Checked = false)
else
begin
skip_root := 0;
end;


   if(skip_root = 0) then
   begin
   reduced_found_root_stringlist.Add(found_root_stringlist.Strings[j]);
   reduced_found_root_index_number[reduced_found_root_stringlist.Count-1] := found_root_index_number[j];
   end//   if(skip_root = 0)

end;//for(int i := 0; i < ProductStringGrid.ColumnCount; i++)




//find in which place the root is located in analysed word
for j := 0 to reduced_found_root_stringlist.Count - 1 do
begin

   index_of_found_substring := 0;
   index_of_found_substring := Pos(reduced_found_root_stringlist.Strings[j], input_text_string_lower_case);
//ShowMessage(IntToStr(index_of_found_substring));
   sorted_reduced_found_root_index_number[j] := index_of_found_substring;

   index_sorted_reduced_found_root_index_number[j] := j;

end;//for(int j := 0; j < reduced_found_root_stringlist.Count; j++)

//sort found roots in the same way as they appear in the analysed word
//InSortInteger(sorted_reduced_found_root_index_number, reduced_found_root_stringlist.Count, index_sorted_reduced_found_root_index_number);
SedgeSortInteger(sorted_reduced_found_root_index_number, reduced_found_root_stringlist.Count, index_sorted_reduced_found_root_index_number);


//show final result of found roots
for j := 0 to reduced_found_root_stringlist.Count - 1 do
begin

   j2 := index_sorted_reduced_found_root_index_number[j];
//   ShowMessage(IntToStr(j2));
   root_index_n := reduced_found_root_index_number[j2];

   OutputTextMemo.Lines.Add('Root: ' + reduced_found_root_stringlist.Strings[j2]);
   OutputTextMemo.Lines.Add('Meaning in English: ' + GreekAndLatinRootsTableStringGrid.Cells[1, root_index_n]);
   OutputTextMemo.Lines.Add('Origin language: ' + GreekAndLatinRootsTableStringGrid.Cells[2, root_index_n]);
   OutputTextMemo.Lines.Add('Etymology (root origin): ' + GreekAndLatinRootsTableStringGrid.Cells[3, root_index_n]);
   OutputTextMemo.Lines.Add('English examples: ' + GreekAndLatinRootsTableStringGrid.Cells[4, root_index_n]);

   OutputTextMemo.Lines.Add('');
   OutputTextMemo.Lines.Add('');
end;//for(int i := 0; i < ProductStringGrid.ColumnCount; i++)


//output_text_string := output_text_string + '</body></HTML>';

//OutputTextWebBrowser.LoadFromStrings(output_text_string, '');
/////  OutputTextWebBrowser.LoadFromStrings('<HTML><body>Hello</body></HTML>', '');

//ShowMessage('Analysis completed.');


{$IF Defined(WINDOWS)}
if (OutputTextMemo.Lines.Count = 0) then // empty
{$ELSEIF Defined(DARWIN)}
if (OutputTextMemo.Lines.Count = 1) then // empty
{$ELSEIF Defined(LINUX)}
if (OutputTextMemo.Lines.Count = 0) then // empty
{$IFEND}
begin
 OutputTextMemo.Lines.Add('Greek and Latin roots are not found in this text.');
end;



OutputTextMemo.SelStart := 0;
OutputTextMemo.SetFocus(); // needed to invoke scrolling to the top


OpenButton.Enabled := true;
PasteButton.Enabled := true;
AnalyseTextButton.Enabled := true;
InputTextEdit.Enabled := true;

InputTextEdit.SetFocus();


end;





function TGreekAndLatinRootsMainForm.IsWindows64: boolean;
{
Detect if we are running on 64 bit Windows or 32 bit Windows,
independently of bitness of this program.
Original source:
http://www.delphipraxis.net/118485-ermitteln-ob-32-bit-oder-64-bit-betriebssystem.html
modified for FreePascal in German Lazarus forum:
http://www.lazarusforum.de/viewtopic.php?f=55&t=5287
}
{$IF Defined (WIN32)}  //Modified KpjComp for 64bit compile mode


type
  TIsWow64Process = function( // Type of IsWow64Process API fn
      Handle: Windows.THandle; var Res: Windows.BOOL): Windows.BOOL; stdcall;
var
  IsWow64Result: Windows.BOOL; // Result from IsWow64Process
  IsWow64Process: TIsWow64Process; // IsWow64Process fn reference


begin

  // Try to load required function from kernel32
  IsWow64Process := TIsWow64Process(Windows.GetProcAddress(Windows.GetModuleHandle('kernel32'), 'IsWow64Process'));
  if Assigned(IsWow64Process) then
  begin
    // Function is implemented: call it
    if not IsWow64Process(Windows.GetCurrentProcess, IsWow64Result) then
      raise SysUtils.Exception.Create('IsWindows64: bad process handle');
    // Return Result of function
    Result := IsWow64Result;
  end
  else
  begin
    // Function not implemented: can't be running on Wow64
    Result := False;
  end; //mantas


end;
{$ELSEIF Defined (WIN64)}  //if were running 64bit code, OS must be 64bit :)
begin
 Result := True;
end;
{$ELSE}
begin
 Result := True;
end;
{$ENDIF}





end.

