unit exsortmds;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, DB, RxDBGrid;

type
  TMemDataSetSortEngine = class(TExDBGridSortEngine)
  public
    procedure Sort(Field:TField; ADataSet:TDataSet; Asc:boolean);override;
  end;

implementation
uses memds;

type
  THackMDS = class(TMemDataSet)
  end;
  
procedure TMemDataSetSortEngine.Sort(Field:TField; ADataSet:TDataSet; Asc:boolean);
var
  MS:TMemoryStream;
  V, FRecSize, FRecCount, I, J:integer;
  BufOrign, BufTest:PChar;
  PI, PJ:PInteger;
  S1:string;
  R1:Double;
  I1:integer;
  B1:boolean;
  D1:TDateTime;


function DoExch:boolean;
begin
  Result:=false;
  ADataSet.RecNo:=J+1;
  if Asc then
  begin
    case Field.DataType of
      ftFixedChar,
      ftWideString,
      ftString:Result:=S1 > Field.AsString;

      ftBoolean:Result:=B1 > Field.AsBoolean;

      ftInteger,
      ftWord,
      ftSmallint,
      ftAutoInc,
      ftLargeint:
        begin
          Result:=I1 > Field.AsInteger;
//          writeln('I1=', I1, '    I2=',Field.AsInteger,'  Result=', Result, '   i=',i, '   j=',j);
        end;

      ftFloat,
      ftCurrency,
      ftBCD:Result:=R1 > Field.AsFloat;

      ftDate,
      ftTime,
      ftDateTime,
      ftTimeStamp:Result:=D1 > Field.AsFloat;
    else
      exit;
    end;
  end
  else
  begin
    case Field.DataType of
      ftFixedChar,
      ftWideString,
      ftString:Result:=S1 < Field.AsString;

      ftBoolean:Result:=B1 < Field.AsBoolean;

      ftInteger,
      ftWord,
      ftSmallint,
      ftAutoInc,
      ftLargeint:Result:=I1 < Field.AsInteger;

      ftFloat,
      ftCurrency,
      ftBCD:Result:=R1 < Field.AsFloat;

      ftDate,
      ftTime,
      ftDateTime,
      ftTimeStamp:Result:=D1 < Field.AsFloat;
    else
      exit;
    end;
  end;
{  if not Asc then
    Result:=not Result;
  Result:=true;}
end;

begin
  if Assigned(ADataSet) then
  begin
    ADataSet.DisableControls;
    MS:=TMemoryStream.Create;
    BufOrign:=THackMDS(ADataSet).AllocRecordBuffer;
    BufTest:=THackMDS(ADataSet).AllocRecordBuffer;
    PI:=@I;
    PJ:=@J;
    try
      THackMDS(ADataSet).SaveDataToStream(MS, true);
      MS.Seek(0, soFromBeginning);
      MS.Read(V, SizeOf(V)); // Marker
      MS.Read(V, SizeOf(V)); // Size
      FRecSize:=THackMDS(ADataSet).GetRecordSize;
      FRecCount:=V div FRecSize;
      for i:=0 to FRecCount-2 do
      begin
        MS.Seek(FRecSize*I + SizeOf(V)*2, soFromBeginning);
        MS.Read(BufOrign^, FRecSize);
        if i=0 then       //fix error
          ADataSet.First
        else
          ADataSet.RecNo:=I+1;

        case Field.DataType of
          ftFixedChar,
          ftWideString,
          ftString:S1:=Field.AsString;

          ftBoolean:B1:=Field.AsBoolean;

          ftInteger,
          ftWord,
          ftSmallint,
          ftAutoInc,
          ftLargeint:I1:=Field.AsInteger;

          ftFloat,
          ftCurrency,
          ftBCD:R1:=Field.AsFloat;

          ftDate,
          ftTime,
          ftDateTime,
          ftTimeStamp:D1:=Field.AsFloat;
{        else
          exit;}
        end;

        for j:=i+1 to FRecCount-1 do
        begin
          MS.Seek(FRecSize*j + SizeOf(V)*2, soFromBeginning);
          MS.Read(BufTest^, FRecSize);
          if DoExch then
          begin
            MS.Seek(FRecSize*j + SizeOf(V)*2, soFromBeginning);
            MS.Write(BufOrign^, FRecSize);
            Move(BufTest^, BufOrign^, FRecSize);
          end;
        end;
        THackMDS(ADataSet).SetBookmarkData(BufOrign, @PI);
        MS.Seek(FRecSize*I + SizeOf(V)*2, soFromBeginning);
        MS.Write(BufOrign^, FRecSize);
        MS.Seek(0, soFromBeginning);
       THackMDS(ADataSet).LoadDataFromStream(MS);
      end;
//    (ADataSet as TFBDataSet).SortOnField(Field.FieldName, Asc);}
      MS.Seek(0, soFromBeginning);
      THackMDS(ADataSet).LoadDataFromStream(MS);
    finally
      THackMDS(ADataSet).FreeRecordBuffer(BufOrign);
      THackMDS(ADataSet).FreeRecordBuffer(BufTest);
      MS.Free;
      ADataSet.EnableControls;
    end;
    THackMDS(ADataSet).First;
  end;
end;

initialization
  RegisterExDBGridSortEngine(TMemDataSetSortEngine, TMemDataset);
end.

