unit ThSort;

{$I Definition.Inc}

interface

uses
  SysUtils, Classes,
  Windows, Messages, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls,
  PythonEngine;

type
  TThreadSortForm = class(TForm)
    StartBtn: TButton;
    BubbleSortBox: TPaintBox;
    SelectionSortBox: TPaintBox;
    QuickSortBox: TPaintBox;
    Label1: TLabel;
    Bevel1: TBevel;
    Bevel2: TBevel;
    Bevel3: TBevel;
    Label2: TLabel;
    Label3: TLabel;
    PythonMemo: TMemo;
    PythonEngine1: TPythonEngine;
    Start2Btn: TButton;
    LoadBtn: TButton;
    PythonDialog: TOpenDialog;
    SaveDialog: TSaveDialog;
    SaveBtn: TButton;
    SortModule: TPythonModule;
    procedure BubbleSortBoxPaint(Sender: TObject);
    procedure SelectionSortBoxPaint(Sender: TObject);
    procedure QuickSortBoxPaint(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure StartBtnClick(Sender: TObject);
    procedure Start2BtnClick(Sender: TObject);
    procedure LoadBtnClick(Sender: TObject);
    procedure SaveBtnClick(Sender: TObject);
    procedure SortModuleInitialization(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    OwnThreadState: PPyThreadState;
    ThreadsRunning: Integer;
    procedure RandomizeArrays;
    procedure ThreadDone(Sender: TObject);
    procedure InitThreads(ThreadExecMode: TThreadExecMode; script: TStrings);

    function SortModule_GetValue( pself, args : PPyObject ) : PPyObject; cdecl;
    function SortModule_Swap( pself, args : PPyObject ) : PPyObject; cdecl;
  public
    procedure PaintArray(Box: TPaintBox; const A: array of Integer);
  end;

var
  ThreadSortForm: TThreadSortForm;

implementation

uses SortThds;

{$R *.dfm}

type
  PSortArray = ^TSortArray;
  TSortArray =  array[0..176] of Integer;

var
  ArraysRandom: Boolean;
  BubbleSortArray, SelectionSortArray, QuickSortArray: TSortArray;

{ TThreadSortForm }

procedure TThreadSortForm.PaintArray(Box: TPaintBox; const A: array of Integer);
var
  I: Integer;
begin
  with Box do
  begin
    Canvas.Pen.Color := clRed;
    for I := Low(A) to High(A) do PaintLine(Canvas, I, A[I]);
  end;
end;

procedure TThreadSortForm.BubbleSortBoxPaint(Sender: TObject);
begin
  PaintArray(BubbleSortBox, BubbleSortArray);
end;

procedure TThreadSortForm.SelectionSortBoxPaint(Sender: TObject);
begin
  PaintArray(SelectionSortBox, SelectionSortArray);
end;

procedure TThreadSortForm.QuickSortBoxPaint(Sender: TObject);
begin
  PaintArray(QuickSortBox, QuickSortArray);
end;

procedure TThreadSortForm.FormCreate(Sender: TObject);
begin
  RandomizeArrays;
end;

procedure TThreadSortForm.InitThreads(ThreadExecMode: TThreadExecMode; script: TStrings);
begin
  RandomizeArrays;
  ThreadsRunning := 3;
  with GetPythonEngine do
  begin
    OwnThreadState := PyEval_SaveThread;

    with TSortThread.Create( ThreadExecMode, script, SortModule, 'SortFunc1',
                             BubbleSortBox, BubbleSortArray) do
      OnTerminate := ThreadDone;
    with TSortThread.Create( ThreadExecMode, script, SortModule, 'SortFunc2',
                                SelectionSortBox, SelectionSortArray) do
      OnTerminate := ThreadDone;
    with TSortThread.Create( ThreadExecMode, script, SortModule, 'SortFunc3',
                            QuickSortBox, QuickSortArray) do
      OnTerminate := ThreadDone;
  end;

  StartBtn.Enabled := False;
  Start2Btn.Enabled := False;
end;

procedure TThreadSortForm.Start2BtnClick(Sender: TObject);
begin
  with GetPythonEngine do
  begin
    ExecStrings(PythonMemo.Lines);
    self.InitThreads(emNewState,nil);
  end;
end;

procedure TThreadSortForm.StartBtnClick(Sender: TObject);
begin
  InitThreads(emNewInterpreter,PythonMemo.Lines);
//PythonEngine1.ExecStrings(PythonMemo.Lines);
end;

procedure TThreadSortForm.LoadBtnClick(Sender: TObject);
begin
  with PythonDialog do if Execute then
    PythonMemo.Lines.LoadFromFile(FileName);
end;

procedure TThreadSortForm.SaveBtnClick(Sender: TObject);
begin
  with SaveDialog do if Execute then
    PythonMemo.Lines.SaveToFile(FileName);
end;

procedure TThreadSortForm.RandomizeArrays;
var
  I: Integer;
begin
  if not ArraysRandom then
  begin
    Randomize;
    for I := Low(BubbleSortArray) to High(BubbleSortArray) do
      BubbleSortArray[I] := Random(170);
    SelectionSortArray := BubbleSortArray;
    QuickSortArray := BubbleSortArray;
    ArraysRandom := True;
    Repaint;
  end;
end;

procedure TThreadSortForm.ThreadDone(Sender: TObject);
begin
  Dec(ThreadsRunning);
  if ThreadsRunning = 0 then
  begin
    GetPythonEngine.PyEval_RestoreThread(OwnThreadState);
    StartBtn.Enabled := True;
    Start2Btn.Enabled := True;
    ArraysRandom := False;
  end;
end;

function TThreadSortForm.SortModule_GetValue( pself, args : PPyObject ) : PPyObject; cdecl;
var psort,index: integer;
begin
  with GetPythonEngine do
  begin
    if PyArg_ParseTuple( args, 'ii',@psort, @index) <> 0 then
    begin
      Result := PyInt_FromLong(TSortThread(psort)[index]);
    end else
      Result := nil;
  end;
end;

function TThreadSortForm.SortModule_Swap( pself, args : PPyObject ) : PPyObject; cdecl;
var psort,i,j: integer;
begin
  with GetPythonEngine do
  begin
    if PyArg_ParseTuple( args, 'iii',@psort, @i, @j) <> 0 then
    begin
      TSortThread(psort).VisualSwap(i,j);
      Result := ReturnNone;
    end else
      Result := nil;
  end;
end;

procedure TThreadSortForm.SortModuleInitialization(Sender: TObject);
begin
  with Sender as TPythonModule do
    begin
      AddDelphiMethod( 'getvalue',
                       SortModule_GetValue,
                       'GetValue(handle,index)' );
      AddDelphiMethod( 'swap',
                       SortModule_Swap,
                       'swap(handle,index1,index2)');
    end;
end;

procedure TThreadSortForm.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
  CanClose := ThreadsRunning = 0;
end;

end.
