program json_test;

{$A8,B-,C+,E-,F-,G+,H+,I+,J-,K-,M-,N-,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Z1}
{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Windows, Classes,
  Json, ioUtils, mnLogs,
  mnUtils, prmClasses, mnConfigs, pmpUtils, pmpClasses,
  mnFields,
  mnDON, mnJSON;

var
  Application: TObject;
  FObjCount: Integer = 0;
  s: string = '';

function HookCode(const ACodeAddress, AHookAddress: Pointer): Boolean;
const
  SIZE_OF_JUMP = 5;
  JMP_RELATIVE = $E9;

var
  OldProtect: DWORD;
  P: PByte;
  Displacement: Integer;
begin
  Result := VirtualProtect(ACodeAddress, SIZE_OF_JUMP,
    PAGE_EXECUTE_READWRITE, OldProtect);

  if (Result) then
  begin
    P := ACodeAddress;
    P^ := JMP_RELATIVE;
    Inc(P);

    Displacement := UIntPtr(AHookAddress) -
      (UIntPtr(ACodeAddress) + SIZE_OF_JUMP);
    PInteger(P)^ := Displacement;

    VirtualProtect(ACodeAddress, SIZE_OF_JUMP, OldProtect, OldProtect);
  end;
end;

procedure HookedObjectFreeInstance(const Self: TObject);
begin
  Dec(FObjCount);

  Self.CleanupInstance;
  FreeMem(Pointer(Self));
end;

function HookedObjectNewInstance(const Self: TClass): TObject;
var
  Instance: Pointer;
begin
  GetMem(Instance, Self.InstanceSize);
  Result := Self.InitInstance(Instance);
  {$IFDEF AUTOREFCOUNT}
  TObjectOpener(Result).FRefCount := 1;
  {$ENDIF}

  Inc(FObjCount);

  System.TMonitor.Enter(Application);
  try
    s := s + #13 + Result.ClassName;
  finally
    System.TMonitor.Exit(Application);
  end;
end;

{$define DON}
  {$ifdef DON}
  {$else}
type
  { TMyJSONObject }

  TMyJSONObject = class(TPersistent)
  private
    FCaption: string;
    FName: string;
    FTag: Integer;
    FValue: string;
    procedure SetCaption(AValue: string);
    procedure SetName(AValue: string);
    procedure SetTag(AValue: Integer);
    procedure SetValue(AValue: string);
  published
    property Name: string read FName write SetName;
    property Value: string read FValue write SetValue;
    property Caption: string read FCaption write SetCaption;
    property Tag: Integer read FTag write SetTag;
  end;
  {$endif}

 {$ifdef DON}
 {$else}
{ TMyJSONObject }

procedure TMyJSONObject.SetCaption(AValue: string);
begin
  if FCaption =AValue then Exit;
  FCaption :=AValue;
end;

procedure TMyJSONObject.SetName(AValue: string);
begin
  if FName =AValue then Exit;
  FName :=AValue;
end;

procedure TMyJSONObject.SetTag(AValue: Integer);
begin
  if FTag =AValue then Exit;
  FTag :=AValue;
end;

procedure TMyJSONObject.SetValue(AValue: string);
begin
  if FValue =AValue then Exit;
  FValue :=AValue;
end;
{$endif}

procedure Run2;
begin
  var m := TMemoryStream.Create;
  var Serializer := TStreamSerializer.Create(m, True);
  var j := TDON_Object_Value.Create(nil);
  try
    j.AddPair('name', 'γΝγΟ');
    j.AddPair('code', '01025');

    Serializer.Options := [sroCompact];
    Serializer.Serialize(TJsonSerializeGernerator, j);
    //JSon4.Serialize(Writer, True, 0);

    var s:= TEncoding.Unicode.GetString(PByte(m.Memory), m.Size);
    Writeln(s);

  finally
    Serializer.Free;
    j.Free;
    m.Free;
  end;
end;

procedure Run;
var
  Lines: TStringList;
  FileName: string;
  {$ifdef DON}
  i: Integer;
  JSONRoot: TDON_Pair;
  Serializer: TStringsSerializer;
  Generator: TJsonSerializeGernerator;
  {$else}
  JSONRoot: TMyJSONObject;
  {$endif}
begin
  DebugMode := True;
  FileName := ExtractFilePath(ParamStr(0))+ 'data.json';// ParamStr(1);
  try
    Lines := TStringList.Create;
    try
      JsonLintFile(FileName);
      WriteLn('Loading: ' + FileName);
      Lines.LoadFromFile(FileName);
      var s : UTF8String := Lines.Text;

      LogBeginTick;
      var Json3 := JsonParseStringValue(s);
      LogEndTick('Test mnJSON');
      Json3.Free;

      LogBeginTick;
      var jjj := json.TJSONObject.ParseJSONValue(s);
      LogEndTick('Test Delphi Json');

      LogBeginTick;
      var ss := jjj.ToString;
      LogEndTick('Test Delphi ToString');

      LogBeginTick;
      var m := TMemoryStream.Create;
      jjj.SaveToStream(m, False);
      LogEndTick('Test Delphi save stream');
      m.SaveToFile('c:\temp\1.json');
      m.Free;
      jjj.Free;

      Exit;


      LogBeginTick;
      var d_json := json.TJSONObject.Create;
      for i :=0  to 1000000 do
        d_json.addpair('Test'+i.ToString,'Value'+i.ToString);
      LogEndTick('Test Add Delphi JSON');

      LogBeginTick;
      for i :=0  to 10000 do
        var j := d_json.FindValue('Test'+i.ToString);
      LogEndTick('Test get Delphi JSON');

      d_json.Free;

      LogBeginTick;
      var mn_json := TDON_Object_Value.Create(nil);
      for i :=0  to 1000000 do
        mn_json.AddPair('Test'+i.ToString,'Value'+i.ToString);
      LogEndTick('Test Add mnJSON');

      LogBeginTick;
      for i :=0  to 10000 do
        var j := mn_json['Test'+i.ToString];
      LogEndTick('Test get mnJSON');
      mn_json.Free;

      Lines.LoadFromFile('test.json');

      var json5 := json.TJSONObject.ParseJSONValue(Lines.Text, False, True);
      LogBeginTick;
      for i :=0 to 1000000 do
        var dd := json5.FindValue('Books.Book1.Title');
      LogEndTick('Delphi JSON get value');
{
      var v := Json3.AsString;
      var v := Json3['"books.zaher'].AsString;
      var v := Json3['books']['zaher'].AsString;
}
      var Json4 := JsonParseFileValue('test.json', []);

      LogBeginTick;
      for i :=0  to 1000000 do
        //var dd := Json4['Books']['Book1']['Title'];
        var dd := Json4[['Books','Book1','Title']];
      LogEndTick('mnJSON get value');

      Writeln(Json4['Books']['Library'].AsString);
      Writeln(Json4['Books']['Book1']['Title'].AsString);
      Writeln(Json4['Books']['Book1']['Pages'][2].AsString);
      Writeln(Json4.ByPath('Books.Book1.Title').AsString);

//      Writeln(Json4.ByPath('"Books"."Book1"."Title"').AsString); //TODO
      Writeln(Json4.ByPath('Books.Book1.Title').AsString);
      Writeln(Json4.ByPath('Books\Book1\Title', '\').AsString);
      Writeln(Json4.ByPath(['Books','Book1','Title']).AsString);

      Json4.ByPath(['Books']).AddObject('Book2');
      Json4.ByPath(['Books', 'Book2']).AddPair('Title', 'No one care');
      Json4.ByPath(['Books', 'Book2']).AddPair('ISPN', '545454610');
      Json4.ByPath(['Books']).AddObject('Book3');
//          Json4.ByPath(['Books', 'Book2']).Let('Pages', '10');
      //Json4.ByPath(['Books','Book1']).Add('Ventors', ['10']);

      Lines.Clear;

      Serializer := TStringsSerializer.Create(Lines);
      Serializer.Serialize(TJsonSerializeGernerator, Json4);
      //JSon4.Serialize(Writer, True, 0);
      Serializer.Free;
      for i := 0 to Lines.Count -1 do
        WriteLn(Lines[i]);

      Json4.Free;

      { rtti }
      {
      WriteLn('Name: ', JSONRoot.Name);
      WriteLn('Value: ', JSONRoot.Value);
      WriteLn('Caption: ', JSONRoot.Caption);
      WriteLn('Tag: ', JSONRoot.Tag);
      }

    finally
      FreeAndNil(Lines);
    end;
  finally
  end;
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  Application := TObject.Create;
  InstallConsoleLog;
  //HookCode(@TObject.NewInstance, @HookedObjectNewInstance);
  //HookCode(@TObject.FreeInstance, @HookedObjectFreeInstance);
  try
    try
      //Run2;
      Run;
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    WriteLn('Press Enter to exit');
    Readln;
  end;

  //TFile.Delete('object.txt');
  //TFile.AppendAllText('object.txt', S);
  Application.Free;
end.

