unit ChannelMap;

interface


uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, BaseGrid, StdCtrls, ExtCtrls;

type
  PStringList = ^TStringList;

  PChannelRec = ^TChannelRec;
  TChannelRec = record
    fullTagname: string;
    shortModule: string;
    shortTagname: string;
    taglist: TStringList;
  end;

  function chmapUpdate: boolean;
  function chmapGetFullTagname(ShortModule, ShortTagname: string): string;
  function chmapFindByFullTagname(FullTagname: string): PChannelRec;
  function chmapGetPrettyChannelStr(fullTagname: string): string;

  function chmapGetModules: string;
  function chmapGetTagnamesByModule(shortModule: string): string;



implementation
uses
  HyperStr,
  DataClientBase,
  numbers,
  TagStorage,
  RpVisualGlobal;

var
    chmaps: TStringList;   // sorted
    channels: TStringList; // sorted, string = fullTagname, object = PChannelRec (owner)
    modules: TStringList;  // sorted, string = shortModule, object = tags<TStringList>:
                           // sorted, string = shortTagname, object = PChannelRec (not owner)




function createSortedStringList: TStringList;
begin
  result := TStringList.Create;
  result.Sorted := True;
  result.Duplicates := dupIgnore;
end;


procedure clearChannels;
var
  i: Integer;
begin
  for i:=0 to channels.Count - 1 do
    dispose(PChannelRec(channels.Objects[i]));
  channels.Clear;
end;


procedure clearModules;
var
  i: Integer;
begin
  for i:=0 to modules.Count - 1 do
    dispose(PStringList(modules.Objects[i]));
  modules.Clear;
end;


procedure updateChannels;
var
  idx: Integer;
  chmap: string;

  procedure getValues(var value1: string; var value2: string);
  var
    s: string;
    k: Integer;
  begin
    s := GetToken(chmap, idx);
    k := Pos(':', s);
    if k = 0 then begin
      value1 := s;
      value2 := s;
    end else begin
      value1 := Trim(LStr(s, k-1));
      value2 := Trim(IStr(s, k+1));
    end;
  end;

var
  i: Integer;
  moduleFull, moduleShort: string;
  tagnameFull, tagnameShort: string;
  p: PChannelRec;
begin
  clearChannels();

  SetDelimiter(' ');
  for i:=0 to chmaps.Count-1 do begin
    chmap := Trim(chmaps[i]);
    if chmap = '' then Continue;

    idx := 1;
    GetValues(moduleFull, moduleShort);

    while NextToken(chmap, idx) do begin
      getValues(tagnameFull, tagnameShort);
      if tagnameFull = '' then Continue;

      new(p);
      p.fullTagname := moduleFull + '.' + tagnameFull;
      p.shortModule := moduleShort;
      p.shortTagname := tagnameShort;
      p.taglist := nil;

      channels.AddObject( p.fullTagname, TObject(p) );
    end;
  end;
end;


procedure updateModules;
var
  i,j: Integer;
  p: PChannelRec;
  tags: TStringList;
begin
  clearModules();

  for i:=0 to channels.Count-1 do begin
    p := PChannelRec(channels.Objects[i]);
    if not modules.Find( p.shortModule, j) then begin
      tags := createSortedStringList;
      modules.AddObject( p.shortModule, tags);
    end else
      tags := TStringList( modules.Objects[j] );

    tags.AddObject( p.shortTagname, TObject(p) );
    p.taglist := tags;
  end;
end;


////////////////////////////////// public //////////////////////////////////////


function chmapUpdate: boolean;
var
  i,n: Integer;
  sl: TStringList;
begin
  sl := createSortedStringList;

  n := GetTagCount;
  for i:=0 to n-1 do begin
    if Pos('.CHANNELMAP.', GetTagName(i)) > 0 then
      sl.Add( GetTagValueString(i) );
  end;

  result := not sl.Equals( chmaps );
  if Result then
    chmaps.Assign( sl );

  sl.Free;

  if Result then begin
    updateChannels();
    updateModules();
  end;
end;


function chmapGetFullTagname(ShortModule, ShortTagname: string): string;
var
  i: Integer;
  tags: TStringList;
  p: PChannelRec;
begin
  result := '';
  if modules.Find( ShortModule, i) then begin
    tags := TStringList( modules.Objects[i] );
    if tags.Find( ShortTagname, i) then begin
      p := PChannelRec( tags.Objects[i] );
      result := p.fullTagname;
    end;
  end;
end;


function chmapFindByFullTagname(FullTagname: string): PChannelRec;
var
  i: Integer;
begin
  result := nil;
  if channels.Find(FullTagname, i) then
    result := PChannelRec( channels.Objects[i] );
end;


function chmapGetPrettyChannelStr(fullTagname: string): string;
var
  i: Integer;
  p: PChannelRec;
begin
  if channels.Find(fullTagname, i) then begin
    p := PChannelRec( channels.Objects[i] );
    result := p.shortModule + '-' + p.shortTagname;
  end else
    Result := fullTagname;
end;


function chmapGetModules: string;
begin
  result := modules.text;
end;



function chmapGetTagnamesByModule(shortModule: string): string;
var
  i: Integer;
begin
  result := '';
  if modules.Find( ShortModule, i) then
    result := TStringList( modules.Objects[i] ).Text;
end;


initialization
  chmaps := createSortedStringList;
  channels := createSortedStringList;
  modules := createSortedStringList;


finalization
  clearModules;
  clearChannels;

  chmaps.Free;
  channels.Free;
  modules.Free;

end.
