unit MetaEditor;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, VirtualTrees, _MetaManager, StdCtrls;

type
  TForm_Meta = class(TForm)
    VST: TVirtualStringTree;
    Button1: TButton;
    Label3: TLabel;
    combo_connection: TComboBox;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
    procedure Button1Click(Sender: TObject);
    procedure VSTInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
      var ChildCount: Cardinal);
    procedure VSTPaintText(Sender: TBaseVirtualTree;
      const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
      TextType: TVSTTextType);
  private
  public
    MetaManager: TMetaManager;
  end;

var
  Form_Meta: TForm_Meta;

implementation
uses
  Data, _DataTypes, _FileTypes, ConnectionManager, TypeDefs, StrUtils;
{$R *.dfm}

type
  PNodeData = ^TNodeData;

  TNodeData = record
    Field: TObject;
  end;

function AddVSTEntry(AVST: TCustomVirtualStringTree; ANode: PVirtualNode;
  ARecord: TNodeData): PVirtualNode;
var
  Data: PNodeData;
begin
  Result := AVST.AddChild(ANode);
  Data   := AVST.GetNodeData(Result);
  AVST.ValidateNode(Result, False);
  Data^ := ARecord;
end;



procedure TForm_Meta.VSTInitChildren(Sender: TBaseVirtualTree;
  Node: PVirtualNode; var ChildCount: Cardinal);
var
  data: PNodeData;
  newdata: TNodeData;
  newnode: PVirtualNode;
  i: Integer;
  id: Integer;
begin
  data := VST.GetNodeData(node);
  for i := 0 to MetaManager.FileById[TFile(data.Field).FileID].ChildCount - 1 do
  begin
    id := MetaManager.FileById[TFile(data.Field).FileID].LinkByIndex[i].DestID;
    MetaManager.InitFile(id);
    newdata.Field := MetaManager.FileById[id];
    newnode := AddVSTEntry(VST, Node, newdata);
    if MetaManager.FileById[id].ChildCount > 0 then
      VST.HasChildren[newnode] := True;
  end;
  ChildCount := MetaManager.FileById[TFile(data.Field).FileID].ChildCount;
end;


procedure TForm_Meta.Button1Click(Sender: TObject);
var
  name: String;
  conid: Integer;

  a,b,c: Int64;
  i: Integer;
  data: TNodeData;
  node: PVirtualNode;
begin
  if combo_connection.ItemIndex >= 0 then
  begin
    name := combo_connection.Items.Strings[combo_connection.ItemIndex];
    conid := StrToInt(MidStr(name, Pos('[', name) + 1, Pos(']', name) - Pos('[', name)  - 1));

    QueryPerformanceFrequency(c);
    QueryPerformanceCounter(a);
    MetaManager := TMetaManager.Create(conid);
    QueryPerformanceCounter(b);
    ShowMessage('Loading Done - ' + FloatToStr((b-a)/c) + 's');

    VST.Clear;
    VST.BeginUpdate;
    for i := 0 to MetaManager.FileCount - 1 do
    begin
      if Assigned(MetaManager.FileById[i]) then
      begin
        data.Field := MetaManager.FileById[i];
        node := AddVSTEntry(VST, nil, data);
        if MetaManager.FileById[i].ChildCount > 0 then
          VST.HasChildren[node] := True;
      end;
    end;
    VST.EndUpdate;
  end;
end;

procedure TForm_Meta.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MetaManager.Free;
  Action := caFree;
end;


procedure TForm_Meta.FormCreate(Sender: TObject);
var
  i: Integer;

  fn, datatype, boxstring: String;
  level: Integer;
begin
  combo_connection.ItemIndex := -1;
  combo_connection.Items.Clear;
  if ConManager.Count > 0 then
  begin
    for i := 0 to ConManager.Count - 1 do
    begin
      level := ConManager.ConnectionByIndex[i].LevelNumber;
      fn := ExtractFileName(ConManager.ConnectionByIndex[i].FileName);
      if ConManager.ConnectionByIndex[i].Backend = DB_ONI then
        datatype := 'ONI-.dat: '
      else if ConManager.ConnectionByIndex[i].Backend = DB_ADB then
        datatype := 'OUP-DB: '
      else
        datatype := 'Unknown: ';
      boxstring := datatype + fn + ' (Level: ' + IntToStr(level) + ') [' + IntToStr(ConManager.ConnectionByIndex[i].ConnectionID) + ']';
      combo_connection.Items.Add(boxstring);
    end;
    if combo_connection.ItemIndex = -1 then
    begin
      combo_connection.ItemIndex := 0;
    end;
  end;


  VST.NodeDataSize := SizeOf(TNodeData);
  VST.Font.Charset := AppSettings.CharSet;
  VST.Clear;
end;



procedure TForm_Meta.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var
  Data: PNodeData;
begin
  Data     := Sender.GetNodeData(Node);
  CellText := '';
  if TextType = ttNormal then
  begin
    case Column of
      0:
        begin
          if Data.Field is TFile then
          begin
            CellText := TFile(Data.Field).FileName;
            if CellText = '' then
              CellText := 'Unnamed';
          end;
        end;
      1:
        begin
          if Data.Field is TFile then
            CellText := TFile(Data.Field).FileExt;
        end;
      2:
        begin
          if Data.Field is TFile then
            CellText := IntToStr(TFile(Data.Field).FileID);
        end;
    end;
  end;
end;

procedure TForm_Meta.VSTPaintText(Sender: TBaseVirtualTree;
  const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType);
var
  Data: PNodeData;
begin
  Data     := Sender.GetNodeData(Node);
  if TextType = ttNormal then
  begin
    case Column of
      0:
        begin
          if Data.Field is TFile then
          begin
            if Length(TFile(Data.Field).FileName) = 0 then
              TargetCanvas.Font.Color := $C06060;
            if TFile(Data.Field).FileSize = 0 then
              TargetCanvas.Font.Color := $2020A0;
          end;
        end;
    end;
  end;
end;

{

procedure WriteStructureInfos;
var
  i, j:    Integer;
  pdata:   PNodeData;
  Data:    TNodeData;
  node:    PVirtualNode;
begin
  VST.BeginUpdate;
  if VST.RootNodeCount = 0 then
  begin
    structs := LoadStructureDefinition(ConID, fileid);
    if structs.Data then
    begin
      if Length(structs.Global) > 0 then
      begin
        for i := 0 to High(structs.Global) do
        begin
          Data.Caption  := structs.Global[i].Name;
          Data.Offset   := structs.Global[i].offset;
          Data.DataType := structs.Global[i].datatype;
          Data.Value    := GetValue(structs.Global[i].datatype, structs.Global[i].offset);
          Data.Description := structs.Global[i].description;
          AddVSTEntry(VST, nil, Data);
        end;
      end;
      if Length(structs.Subs) > 0 then
      begin
        for i := 0 to High(structs.Subs) do
        begin
          with structs.Subs[i] do
          begin
            if Length(Entries) > 0 then
            begin
              if Pos('#', SubName) > 0 then
              begin
                Data.Offset  := StrToInt('$'+MidStr(SubName, Pos('#', SubName) + 1, 8));
                Data.Value   := '$' +
                  MidStr(SubName, PosEx('#', SubName, Pos('#', SubName) + 1) + 1, 8);
                Data.Caption := MidStr(SubName, 1, Pos('#', SubName) - 1);
                Data.Description := SubDesc;
              end
              else
              begin
                Data.Caption := SubName;
                Data.Description := SubDesc;
                Data.Offset := 0;
                Data.Value := '';
              end;
              Data.DataType := 0;
              node := AddVSTEntry(VST, nil, Data);
              Data.Description := '';
              for j := 0 to High(Entries) do
              begin
                Data.Caption  := Entries[j].Name;
                Data.Offset   := Entries[j].offset;
                Data.DataType := Entries[j].datatype;
                Data.Value    := GetValue(Entries[j].datatype, Entries[j].offset);
                Data.Description := Entries[j].description;
                AddVSTEntry(VST, node, Data);
              end;
            end;
          end;
        end;
      end;
    end;
    if VST.RootNodeCount > 0 then
      VST.FocusedNode := VST.GetFirst;
  end
  else
  begin
    Node := VST.GetFirst;
    while Assigned(Node) do
    begin
      pdata := VST.GetNodeData(Node);
      if pdata.DataType > 0 then
        pdata.Value := GetValue(pdata.Datatype, pdata.Offset);
      Node := VST.GetNext(Node);
    end;
  end;
  VST.EndUpdate;
end;
}
end.
