unit StandardBillsDm;

interface

uses
  SysUtils, Classes, ADODB, DB, DBClient, Provider, sdIDTree,
  UtilMethods, sdDB, sdProvider;

type
  TStandardBillsData = class(TDataModule)
    sdpStdBills: TsdADOProvider;
    sddStdBills: TsdDataSet;
    sdvStdBills: TsdDataView;
  private
    FBillsTree: TsdIDTree;

    procedure CreateBillsTree;
    procedure OpenConnetion(AConnection: TADOConnection);
    procedure ExpandFirstNode;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure Open(AConnection: TADOConnection);
    procedure CalcCacheData(ANode:TsdIDTreeNode; AOrder: Integer; AParentPath: String);

    procedure RecursiveExportBillsJson(const AFileName: string);

    property BillsTree: TsdIDTree read FBillsTree;
  end;

implementation

{$R *.dfm}

{ TStandardBillsData }

procedure TStandardBillsData.CalcCacheData(ANode: TsdIDTreeNode;
  AOrder: Integer; AParentPath: String);
var
  sNodePath: string;
begin
  if not Assigned(ANode) then Exit;

  ANode.Rec.ValueByName('BillsLevel').AsInteger := ANode.Level + 1;
  ANode.Rec.ValueByName('BillsOrder').AsInteger := AOrder;
  if AParentPath = '' then
    sNodePath := IntToStr(ANode.ID)
  else
    sNodePath := AParentPath + '.' + IntToStr(ANode.ID);
  ANode.Rec.ValueByName('FullPath').AsString := sNodePath;
  ANode.Rec.ValueByName('IsLeaf').AsBoolean := not ANode.HasChildren;

  CalcCacheData(ANode.FirstChild, 1, sNodePath);
  CalcCacheData(ANode.NextSibling, AOrder + 1, AParentPath);
end;

constructor TStandardBillsData.Create(AOwner: TComponent);
begin
  inherited;
  CreateBillsTree;
end;

procedure TStandardBillsData.CreateBillsTree;
begin
  FBillsTree := TsdIDTree.Create;
  FBillsTree.KeyFieldName := 'ID';
  FBillsTree.ParentFieldName := 'ParentID';
  FBillsTree.NextSiblingFieldName := 'NextID';
  FBillsTree.AutoExpand := False;
end;

destructor TStandardBillsData.Destroy;
begin
  FBillsTree.Free;
  inherited;
end;

procedure TStandardBillsData.ExpandFirstNode;
begin
  if FBillsTree.FirstNode <> nil then
    FBillsTree.FirstNode.Expand;
end;

procedure TStandardBillsData.Open(AConnection: TADOConnection);
begin
  OpenConnetion(AConnection);
  FBillsTree.DataView := sdvStdBills;
  ExpandFirstNode;
end;

procedure TStandardBillsData.OpenConnetion(AConnection: TADOConnection);
begin
  sdpStdBills.Connection := AConnection;
  sdpStdBills.TableName := 'BillsTree';
  sddStdBills.Open;
  sdvStdBills.Open;
  sddStdBills.AddIndex('idxID', 'ID');
  sddStdBills.AddIndex('sdxCode', 'Code');
  sddStdBills.AddIndex('sddBCode', 'B_Code');
end;

procedure TStandardBillsData.RecursiveExportBillsJson(
  const AFileName: string);
var
  sgs: TStrings;

  function GetNodeData(ANode: TsdIDTreeNode; AOrder: Integer; AFullPath: string): string;
  const
    sBillsJson = '"id": %d, "pid": %d, "order": %d, "full_path": "%s", "level": %d, "is_leaf" : %d, ' +
                 '"code": "%s", "b_code": "%s", "name": "%s", "unit": "%s"';
  begin
    Result := Format(sBillsJson, [ANode.ID, ANode.Rec.ValueByName('ParentID').AsInteger, AOrder, AFullPath,
         ANode.Rec.ValueByName('BillsLevel').AsInteger, Integer(not ANode.HasChildren),
         ANode.Rec.ValueByName('Code').AsString, ANode.Rec.ValueByName('B_Code').AsString,
         ANode.Rec.ValueByName('Name').AsString, ANode.Rec.ValueByName('Unit').AsString]);
  end;

  procedure ExportNode(ANode: TsdIDTreeNode; AOrder: Integer; AParentPath: string);
  var
    sNodePath: string;
  begin
    if not Assigned(ANode) then Exit;

    if AParentPath = '' then
      sNodePath := IntToStr(ANode.ID)
    else
      sNodePath := AParentPath + '.' + IntToStr(ANode.ID);

    sgs.Strings[sgs.Count - 1] := sgs.Strings[sgs.Count - 1] + '{';
    sgs.Add(Format('  %s', [AnsiToUtf8(GetNodeData(ANode, AOrder, sNodePath))]));
    sgs.Add('}');
    if Assigned(ANode.NextNode) then
      sgs.Strings[sgs.Count - 1] := sgs.Strings[sgs.Count - 1] + ',';

    ExportNode(ANode.FirstChild, 1, sNodePath);
    ExportNode(ANode.NextSibling, AOrder + 1, AParentPath);
  end;

begin
  sgs := TStringList.Create;
  try
    sgs.Add('[');
    ExportNode(FBillsTree.FirstNode, 1, '');
    sgs.Strings[sgs.Count - 1] := sgs.Strings[sgs.Count - 1] + ']';
    sgs.SaveToFile(AFileName);
  finally
    sgs.Free;
  end;
end;

end.
