// DEPRECATED
unit djson5;

interface

uses
  dobjects,
  dtypes,
  dstream;

type
PJson = ^TJson;

TJsonType = (JSON_NULL, JSON_INT, JSON_FLOAT, JSON_STRING, JSON_BOOLEAN,
             JSON_ARRAY, JSON_OBJECT);

PJsonPair = ^TJsonPair;
TJsonPair = record
  Name: TString;
  S: TString;
case _Type: TJsonType of
  JSON_INT: (I: Integer);
  JSON_FLOAT: (F: Extended);
  JSON_STRING: ();
  JSON_BOOLEAN: (B: Boolean);
  JSON_ARRAY: (A: PJson);
  JSON_OBJECT: (O: PJson);
end;

TJson = object(TObject)
private
  FArray: Boolean;
  FValues: array of TJsonPair;
public
  constructor InitObject;
  constructor InitArray;
  destructor Done; virtual;
  // As json object
  function Add(const Name: TString; _Type: TJsonType): PJsonPair; overload;
  procedure AddNull(const Name: TString); overload;
  procedure Add(const Name: TString; Value: TInt); overload;
  procedure Add(const Name: TString; Value: TDouble); overload;
  procedure Add(const Name: TString; Value: TString); overload;
  procedure Add(const Name: TString; Value: Boolean); overload;
  procedure Add(const Name: TString; Value: PJson); overload;
  function Find(Name: TString): PJsonPair;
  function IsNull(const Name: TString): Boolean; overload;
  function Get(const Name: TString; out Value: TInt): Boolean; overload;
  function Get(const Name: TString; out Value: TDouble): Boolean; overload;
  function Get(const Name: TString; out Value: TString): Boolean; overload;
  function Get(const Name: TString; out Value: Boolean): Boolean; overload;
  function Get(const Name: TString; out Value: PJson): Boolean; overload;
  function Def(const Name: TString; Value: TInt): TInt; overload;
  function Def(const Name: TString; Value: TDouble): TDouble; overload;
  function Def(const Name: TString; Value: TString): TString; overload;
  function Def(const Name: TString; Value: Boolean): Boolean; overload;
  function Def(const Name: TString; Value: PJson): PJson; overload;
  // As json array
  function Add(const _Type: TJsonType): PJsonPair; overload;
  procedure AddNull(); overload;
  procedure Add(Value: TInt); overload;
  procedure Add(Value: TDouble); overload;
  procedure Add(Value: TString); overload;
  procedure Add(Value: Boolean); overload;
  procedure Add(Value: PJson); overload;
  function Length: TInt;
  function IsNull(Index: TInt): Boolean; overload;
  function Get(Index: TInt; out Value: TInt): Boolean; overload;
  function Get(Index: TInt; out Value: TDouble): Boolean; overload;
  function Get(Index: TInt; out Value: TString): Boolean; overload;
  function Get(Index: TInt; out Value: Boolean): Boolean; overload;
  function Get(Index: TInt; out Value: PJson): Boolean; overload;
  function Def(Index: TInt; const Value: TInt): TInt; overload;
  function Def(Index: TInt; const Value: TDouble): TDouble; overload;
  function Def(Index: TInt; const Value: TString): TString; overload;
  function Def(Index: TInt; const Value: Boolean): Boolean; overload;
  function Def(Index: TInt; const Value: PJson): PJson; overload;
end;

function ParseJson(const Data: TData): TJson;

implementation

constructor TJson.InitObject;
begin
  FArray := False;
end;

constructor TJson.InitArray;
begin
  FArray := True;
end;

destructor TJson.Done;
var
  I: TInt;
begin
  for I := 0 to High(FValues) do
    with FValues[I] do
      if (_Type = JSON_OBJECT) or (_Type = JSON_ARRAY) then
        FValues[I].O.Free;
  SetLength(FValues, 0);
end;

function TJson.Add(const Name: TString; _Type: TJsonType): PJsonPair;
begin
  SetLength(FValues, System.Length(FValues) + 1);
  FValues[High(FValues)].Name := Name;
  FValues[High(FValues)]._Type := _Type;
end;

procedure TJson.AddNull(const Name: TString);
begin
  Add(Name, JSON_NULL);
end;

procedure TJson.Add(const Name: TString; Value: TInt);
begin
  with Add(Name, JSON_INT)^ do
    I := Value;
end;

procedure TJson.Add(const Name: TString; Value: TDouble);
begin
  with Add(Name, JSON_FLOAT)^ do
    F := Value;
end;

procedure TJson.Add(const Name: TString; Value: TString);
begin
  with Add(Name, JSON_STRING)^ do
    S := Value;
end;

procedure TJson.Add(const Name: TString; Value: Boolean);
begin
  with Add(Name, JSON_BOOLEAN)^ do
    B := Value;
end;

procedure TJson.Add(const Name: TString; Value: PJson);
begin
  if Value^.FArray then
    with Add(Name, JSON_ARRAY)^  do A := Value
  else
    with Add(Name, JSON_OBJECT)^ do O := Value;
end;

function TJson.Find(Name: TString): PJsonPair;
var
  I: LongInt;
begin
  for I := 0 to High(FValues) do
    if FValues[I].Name = Name then
      Exit(@FValues[I]);
  Exit(nil);
end;

function TJson.IsNull(const Name: TString): Boolean;
var
  P: PJsonPair;
begin
  P := Find(Name);
  Exit((P <> nil) and (P^._Type = JSON_NULL));
end;

function TJson.Get(const Name: TString; out Value: TInt): Boolean;
var
  P: PJsonPair;
begin
  P := Find(Name);
  Result := (P <> nil) and (P^._Type = JSON_INT);
  if Result then
    Value := P^.I;
end;

function TJson.Get(const Name: TString; out Value: TDouble): Boolean;
var
  P: PJsonPair;
begin
  P := Find(Name);
  Result := (P <> nil) and (P^._Type = JSON_FLOAT);
  if Result then
    Value := P^.F;
end;

function TJson.Get(const Name: TString; out Value: TString): Boolean;
var
  P: PJsonPair;
begin
  P := Find(Name);
  Result := (P <> nil) and (P^._Type = JSON_STRING);
  if Result then
    Value := P^.S;
end;

function TJson.Get(const Name: TString; out Value: Boolean): Boolean;
var
  P: PJsonPair;
begin
  P := Find(Name);
  Result := (P <> nil) and (P^._Type = JSON_BOOLEAN);
  if Result then
    Value := P^.B;
end;

function TJson.Get(const Name: TString; out Value: PJson): Boolean;
var
  P: PJsonPair;
begin
  P := Find(Name);
  Result := (P <> nil) and ((P^._Type = JSON_OBJECT) or (P^._Type = JSON_ARRAY));
  if Result then
    Value := P^.O;
end;

function TJson.Def(const Name: TString; Value: TInt): TInt;
begin
  if not Get(Name, Result) then
    Result := Value;
end;

function TJson.Def(const Name: TString; Value: TDouble): TDouble;
begin
  if not Get(Name, Result) then
    Result := Value;
end;

function TJson.Def(const Name: TString; Value: TString): TString;
begin
  if not Get(Name, Result) then
    Result := Value;
end;

function TJson.Def(const Name: TString; Value: Boolean): Boolean;
begin
  if not Get(Name, Result) then
    Result := Value;
end;

function TJson.Def(const Name: TString; Value: PJson): PJson;
begin
  if not Get(Name, Result) then
    Result := Value;
end;

function TJson.Add(const _Type: TJsonType): PJsonPair;
begin
  SetLength(FValues, System.Length(FValues) + 1);
  Result := @FValues[High(FValues)];
  Result^.Name := ''; // IntToStr here?
  Result^._Type := _Type;
end;

procedure TJson.AddNull();
begin
  Add(JSON_NULL);
end;

procedure TJson.Add(Value: TInt);
begin
  with Add(JSON_INT)^ do
    I := Value;
end;

procedure TJson.Add(Value: TDouble);
begin
  with Add(JSON_FLOAT)^ do
    F := Value;
end;

procedure TJson.Add(Value: TString);
begin
  with Add(JSON_STRING)^ do
    S := Value;
end;

procedure TJson.Add(Value: Boolean);
begin
  with Add(JSON_BOOLEAN)^ do
    B := Value;
end;

procedure TJson.Add(Value: PJson);
begin
  if Value^.FArray then
    with Add(JSON_ARRAY)^  do A := Value
  else
    with Add(JSON_OBJECT)^ do O := Value;
end;

function TJson.Length: TInt;
begin
  Result := System.Length(FValues);
end;

function TJson.IsNull(Index: TInt): Boolean;
begin
  Result := FValues[Index]._Type = JSON_NULL;
end;

function TJson.Get(Index: TInt; out Value: TInt): Boolean;
begin
  with FValues[Index] do begin
    Result := _Type = JSON_INT;
    if Result then
      Value := I;
  end;
end;

function TJson.Get(Index: TInt; out Value: TDouble): Boolean;
begin
  with FValues[Index] do begin
    Result := _Type = JSON_FLOAT;
    if Result then
      Value := F;
  end;
end;

function TJson.Get(Index: TInt; out Value: TString): Boolean;
begin
  with FValues[Index] do begin
    Result := _Type = JSON_STRING;
    if Result then
      Value := S;
  end;
end;

function TJson.Get(Index: TInt; out Value: Boolean): Boolean;
begin
  with FValues[Index] do begin
    Result := _Type = JSON_BOOLEAN;
    if Result then
      Value := B;
  end;
end;

function TJson.Get(Index: TInt; out Value: PJson): Boolean;
begin
  with FValues[Index] do begin
    Result := (_Type = JSON_OBJECT) or (_Type = JSON_ARRAY);
    if Result then
      Value := O;
  end;
end;

function TJson.Def(Index: TInt; const Value: TInt): TInt;
begin
  if not Get(Index, Result) then
    Result := Value;
end;

function TJson.Def(Index: TInt; const Value: TDouble): TDouble;
begin
  if not Get(Index, Result) then
    Result := Value;
end;

function TJson.Def(Index: TInt; const Value: TString): TString;
begin
  if not Get(Index, Result) then
    Result := Value;
end;

function TJson.Def(Index: TInt; const Value: Boolean): Boolean;
begin
  if not Get(Index, Result) then
    Result := Value;
end;

function TJson.Def(Index: TInt; const Value: PJson): PJson;
begin
  if not Get(Index, Result) then
    Result := Value;
end;

function ParseJson(const Data: TData): TJson;
begin
  Data.Done;
end;

end.
