unit AddOnDbUtils;

interface

uses
	Windows, SysUtils, Classes, StdCtrls, M2AddOn, M2AddOnD, M2AddonImp, Ingeo_TLB;

type
	TFieldsType = (NoFields, NoSysFields, AllFields);
	TLayerTable = class
	public
		ID: TM2ID;
		Name,
		Caption: String;
		OneToOne: Boolean;
		Fields: array of record
      Caption: String;
      Name: String;
      DataType: TIngeoFieldDataType;
    end;

		constructor Create(anAddon: TM2CustomAddon; const aTableID: TM2ID; aFields: TFieldsType);
    procedure AssignFieldsToStrings(aFields: TStrings);
    procedure AssignFieldNamesToStrings(aFields: TStrings);

    procedure AddFieldsToStrings(aFields: TStrings);
	end;

	TLayerTableList = class(TList)
	private
		function GetTable(anIndex: Integer): TLayerTable;
	public
		constructor Create(anAddon: TM2CustomAddon; const aLayerID: TM2ID; aFields: TFieldsType);
		destructor Destroy; override;

		property Tables[anIndex: Integer]: TLayerTable read GetTable; default;
	end;

	TLayerTablesCache = class(TStringList)
	private
		FAddon: TM2CustomAddon;
	public
		constructor Create(anAddon: TM2CustomAddon);
		destructor Destroy; override;

		procedure Clear; override;
		function GetLayerTables(const aLayerID: TM2ID; aFields: TFieldsType): TLayerTableList;
	end;

// по умолчанию aDataTypes = [], такое же действие как и без aDataTypes
procedure InitFieldsCombos(anAddon: TM2CustomAddon; const aTableName: String;
	const aCombos: array of TComboBox; aDataTypes: array of TIngeoFieldDataType;
	aDebug: Boolean = false);
function GetComboTableID(aCombo: TComboBox; i: Integer): TM2ID;
function GetComboTableName(aCombo: TComboBox; i: Integer): String;
function GetComboIndexOfID(aCombo: TComboBox; const aTableID: TM2ID): Integer;
procedure SelectComboItem(aCombo: TComboBox; const aValue: String);
function GetIngeo(anAddon: TM2CustomAddon): IIngeoApplication;
procedure GetGisTables(anAddon: TM2CustomAddon; aSysTables: Boolean; aTables: TStrings);
function GetFieldDataType(anAddon: TM2CustomAddon; const aTableName, aFieldName: string): TIngeoFieldDataType;

implementation

uses
	AddOnUtils, InSysUtils;

{ TLayerTable }

function GetIngeo(anAddon: TM2CustomAddon): IIngeoApplication;
begin
	Result := anAddOn.AddonManager.OleObject as IIngeoApplication;
end;

constructor TLayerTable.Create(anAddon: TM2CustomAddon; const aTableID: TM2ID;
	aFields: TFieldsType);

var
	anIngeo: IIngeoApplication;
	anAttrs: TM2TableAttrs;

  aSemTable: IIngeoSemTable;
  aFieldInfos: IIngeoSemFieldInfos;
	aDbTable: IIngeoSemDbTable;
	aDbField: IIngeoSemDbField;
	i: Integer;
begin
	inherited Create;
	ID := aTableID;
	try
    SetLength(Fields, 0);

		anAddon.GISDatabase.GetTableAttrs(aTableID, anAttrs);
		Name := anAttrs.TableName;
		Caption := anAttrs.UserTableName;
		OneToOne := anAttrs.OneToOne;
		if aFields <> NoFields then begin
			anIngeo := GetIngeo(anAddon);
      aSemTable := anIngeo.ActiveDb.SemTableFromID(aTableID);

      aFieldInfos := aSemTable.FieldInfos;
			aDbTable := aSemTable.SemDbTable;
			for i := 0 to aDbTable.Fields.Count - 1 do begin
				aDbField := aDbTable.Fields[i];
				if (aFields = AllFields) or not IsIDOrSimID(aDbField.Name) then begin
          SetLength(Fields, Length(Fields) + 1);
          Fields[High(Fields)].Caption := aFieldInfos[aDbField.Name].Caption;
          Fields[High(Fields)].Name := aDbField.Name;
          Fields[High(Fields)].DataType := aDbField.DataType;
        end;
			end;
		end;
	except
	end;
end;

procedure TLayerTable.AssignFieldsToStrings(aFields: TStrings);
begin
  aFields.Clear;
  AddFieldsToStrings(aFields);
end;

procedure TLayerTable.AddFieldsToStrings(aFields: TStrings);
var
  i: Integer;
begin
  for i := 0 to Length(Fields) do
    aFields.AddObject(Fields[i].Caption, Pointer(i));
end;

procedure TLayerTable.AssignFieldNamesToStrings(aFields: TStrings);
var
  i: Integer;
begin
  aFields.Clear;
  for i := 0 to Length(Fields) do
    aFields.AddObject(Fields[i].Name, Pointer(i));
end;

{ TLayerTableList }

constructor TLayerTableList.Create(anAddon: TM2CustomAddon; const aLayerID: TM2ID;
	aFields: TFieldsType);
var
	aTables: TM2IDsList;
	aTable: TLayerTable;
	i: Integer;
begin
	inherited Create;
	aTables.OleObject := anAddon.GISDatabase.GetTableList(aLayerID);
	for i := 0 to aTables.Count - 1 do begin
		aTable := TLayerTable.Create(anAddon, aTables.Items(i), aFields);
		Add(aTable);
	end;
end;

destructor TLayerTableList.Destroy;
begin
	ClearObjectList(Self);
	inherited Destroy;
end;

function TLayerTableList.GetTable(anIndex: Integer): TLayerTable;
begin
	Result := TLayerTable(inherited Items[anIndex]);
end;

{ TLayerTablesCache }

constructor TLayerTablesCache.Create(anAddon: TM2CustomAddon);
begin
	inherited Create;
	Sorted := True;
	FAddon := anAddon;
end;

destructor TLayerTablesCache.Destroy;
begin
	Clear;
	inherited Destroy;
end;

function TLayerTablesCache.GetLayerTables(const aLayerID: TM2ID;
	aFields: TFieldsType): TLayerTableList;
var
	i: Integer;
begin
	if Find(aLayerID, i) then
		Result := TLayerTableList(Objects[i])
	else begin
		Result := TLayerTableList.Create(FAddon, aLayerID, aFields);
		AddObject(aLayerID, Result);
	end
end;

procedure TLayerTablesCache.Clear;
begin
	ClearStringsWithObjects(Self);
end;

procedure GetGisTables(anAddon: TM2CustomAddon; aSysTables: Boolean; aTables: TStrings);
var
	i: Integer;
	anIngeo: IIngeoApplication;
	aSemDbTables: IIngeoSemDbTables;
	aSemDbTable: IIngeoSemDbTable;
	aRefBook: IIngeoRefBook;
begin
	anIngeo := GetIngeo(anAddon);
	aSemDbTables := anIngeo.ActiveDb.SemDbTables;
	for i := 0 to aSemDbTables.Count - 1 do begin
		aSemDbTable := aSemDbTables[i];
		if aSysTables or (AnsiCompareText(Copy(aSemDbTable.TableName, 1, 6), 'INGEO_') <> 0) then
			aTables.Add(aSemDbTable.TableName);
	end;

	// заглушка, если функция aSemDbTable.Count вернула неверную информацию
	for i := 0 to anIngeo.ActiveDb.RefBooks.Count - 1 do begin
		aRefBook := anIngeo.ActiveDb.RefBooks[i];
		if aTables.IndexOf(aRefBook.SemDbTableName) = -1 then
			aTables.Add(aRefBook.SemDbTableName)
	end;
end;

procedure InitFieldsCombos(anAddon: TM2CustomAddon; const aTableName: String;
	const aCombos: array of TComboBox; aDataTypes: array of TIngeoFieldDataType; aDebug: Boolean);

	function FieldIsEnabled(aField: IIngeoSemDbField): Boolean;
	var
		i: Integer;
	begin
		Result := Length(aDataTypes) = 0;
		if not Result then begin
			for i := 0 to Length(aDataTypes) - 1 do begin
				if aField.DataType = aDataTypes[i] then begin
					Result := True;
					Exit;
				end;
			end;
		end;
	end;

	procedure WriteHint(const aMsg: string);
	var
		aCombo: TComboBox;
		i: Integer;
	begin
		if aDebug then begin
			for i := Low(aCombos) to High(aCombos) do begin
				aCombo := aCombos[i];
				aCombo.Hint := aMsg;
				aCombo.ShowHint := True;
			end;
		end;
	end;

var
	anIngeo: IIngeoApplication;
	aTable: IIngeoSemDbTable;
	aCombo: TComboBox;
	aField: IIngeoSemDbField;
	i, j, k: Integer;
begin
	anIngeo := GetIngeo(anAddon);
	try
		if Assigned(anIngeo.ActiveDb) and anIngeo.ActiveDb.SemDbTables.Exists(aTableName) then begin
			aTable := anIngeo.ActiveDb.SemDbTables[aTableName];
			k := 0;
			for i := Low(aCombos) to High(aCombos) do begin
				aCombo := aCombos[i];
				aCombo.Items.BeginUpdate;
				try
					aCombo.Clear;
					k := 0;
					for j := 0 to aTable.Fields.Count - 1 do begin
						aField := aTable.Fields[j];
						if FieldIsEnabled(aField) then begin
							aCombo.Items.Add(aField.Name);
							Inc(k);
						end;
					end
				finally
					aCombo.Items.EndUpdate;
				end;
			end;
			WriteHint(Format('Всего: %d из %d', [k, aTable.Fields.Count]));
		end
		else
			WriteHint(Format('Ошибка: Не найдена таблица "%s"', [aTableName]));
	except
		on E: Exception do begin
			for i := Low(aCombos) to High(aCombos) do
				aCombos[i].Items.Clear;

			WriteHint(Format('Ошибка("%s"): %s', [aTableName, E.Message]));
		end;
	end;
end;

function GetFieldDataType(anAddon: TM2CustomAddon; const aTableName, aFieldName: string): TIngeoFieldDataType;
var
	anIngeo: IIngeoApplication;
begin
	anIngeo := GetIngeo(anAddon);
	try
		Result := anIngeo.ActiveDb.SemDbTables[aTableName].Fields[aFieldName].DataType;
	except
		Result := inftUnknown;
	end;
end;

function GetComboTableID(aCombo: TComboBox; i: Integer): TM2ID;
begin
	if (i >= 0) and (i < aCombo.Items.Count) then
		Result := TLayerTable(aCombo.Items.Objects[i]).ID
	else
		Result := ''
end;

function GetComboTableName(aCombo: TComboBox; i: Integer): String;
begin
	if (i >= 0) and (i < aCombo.Items.Count) then
		Result := TLayerTable(aCombo.Items.Objects[i]).Name
	else
		Result := ''
end;

function GetComboIndexOfID(aCombo: TComboBox; const aTableID: TM2ID): Integer;
begin
	for Result := 0 to aCombo.Items.Count - 1 do
		if TLayerTable(aCombo.Items.Objects[Result]).ID = aTableID then
			Exit;
	Result := -1;
end;

procedure SelectComboItem(aCombo: TComboBox; const aValue: String);
begin
	aCombo.ItemIndex := aCombo.Items.IndexOf(aValue);
end;


initialization
finalization
end.

