unit unitCustomTags;

{$mode delphi}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  erg_types, erg_base, UnitExtraTags, LCLType;

type

  { TfrmCustomTags }

  SaveProcedure = procedure of object; //allows to call a method from unit1
  UpdateProcedure = procedure of object;

  TfrmCustomTags = class(TForm)
    btnAddTag: TButton;
    btnDelTag: TButton;
    btnSave: TButton;
    comboInstances: TComboBox;
    Label1: TLabel;
    lstValues: TListBox;
    lstExtraTags: TListBox;
    procedure btnAddTagClick(Sender: TObject);
    procedure btnDelTagClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure comboInstancesChange(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure InitComboInstances(SelectedRadioBtn: Integer; selectedIndex: Integer);
    procedure lstExtraTagsDblClick(Sender: TObject);
    procedure lstExtraTagsKeyPress(Sender: TObject; var Key: char);
    procedure lstExtraTagsSelectionChange(Sender: TObject; User: boolean);
    procedure lstValuesDblClick(Sender: TObject);
    procedure lstValuesKeyPress(Sender: TObject; var Key: char);
  private
    ExtraTagsOverview: TExtraTagsOverview;
    SelectedExtraTags: TExtraTags;
    WorkingOnRef: Array of ^TRecordWithExtraTags; //constants/tracers/etc
    procedure listParms;
    procedure updateListedValues;
    procedure updateExtraTags;
    procedure SaveEverything;
  public
    class var UnsavedChanges: boolean;
    SaveChanges: SaveProcedure; //method pointer assigned in Unit1
    UpdateMainForm: UpdateProcedure; //method pointer assigned in Unit1
  end;

var
  frmCustomTags: TfrmCustomTags;

implementation

const
  SAVED_CAPTION = 'Manage Custom Tags';
  UNSAVED_CAPTION = '*Manage Custom Tags';


{$R *.lfm}

{ TfrmCustomTags }

procedure TfrmCustomTags.SaveEverything;
var
  i_par: Integer;
  UpdatedTags: Array of TExtraTagsRecord;
  selected_par: ^TRecordWithExtraTags;
begin
  //retrieve updated copies of records
  UpdatedTags := ExtraTagsOverview.getUpdatedTagsRecords;

  for i_par := 0 to Length(UpdatedTags) -1 do
  begin
    selected_par := WorkingOnRef[i_par];
    (selected_par^ as TRecordWithExtraTags).setExtraTagsRecord(UpdatedTags[i_par]);
  end;

  //write changes to file
  SaveChanges;
  UpdateMainForm;
  //make some cosmetic changes to form
  UnsavedChanges := FALSE;
  frmCustomTags.Caption := SAVED_CAPTION;
end;

procedure TfrmCustomTags.updateListedValues;
var
  dummy: String;
  i_tag: Integer;
begin
  lstValues.Items.Clear;

  for i_tag := 0 to lstExtraTags.Count -1 do
  begin
    if not SelectedExtraTags.getTagValue(i_tag, dummy) then
      dummy := 'Error';
    lstValues.Items.Add(dummy);
  end;
end;

procedure TfrmCustomTags.updateExtraTags;
var
  i_tag: Integer;
  TagNames: TStringList;
begin
  lstExtraTags.Items.Clear;

  TagNames := ExtraTagsOverview.getTagNames;
  for i_tag := 0 to TagNames.Count -1 do
    lstExtraTags.Items.Add(TagNames[i_tag]);
end;

procedure TfrmCustomTags.listParms;
var
  i_par: Integer;
  ParmExtraTags: Array of TExtraTagsRecord;
  selected_par: ^TRecordWithExtraTags;
begin
  //Empty Combobox and enable it
  ComboInstances.Items.Clear;
  ComboInstances.Enabled := TRUE;

  if Assigned(constants) then
  begin
    //Fill combobox with names of constants/processes/etc.
    for i_par := 0 to length(WorkingOnRef) -1 do
    begin
      selected_par := WorkingOnRef[i_par];
      ComboInstances.Items.Add( (selected_par^ as TRecordWithExtraTags).name );
    end;

    //Initialize overview object that contains data of all constants
    SetLength(ParmExtraTags, Length(WorkingOnRef) );
    SetLength(WorkingOnRef, Length(WorkingOnRef));
    for i_par := 0 to length(WorkingOnRef) -1 do
    begin
      selected_par := WorkingOnRef[i_par];
      //ExtraTagsUnits only works with copies
      copyExtraTagsRecord( (selected_par^ as TRecordWithExtraTags).ExtraTagsRecord,
          ParmExtraTags[i_par]);;
    end;

    ExtraTagsOverview := TExtraTagsOverview.Create(ParmExtraTags);
  end;
end;


procedure TfrmCustomTags.InitComboInstances(SelectedRadioBtn: Integer; selectedIndex: Integer);
var
  i_par: integer;
  dummy: Array of TExtraTagsRecord;
begin

  if (SelectedRadioBtn = 1) and Assigned(constants) then
  begin
    SetLength(WorkingOnRef, Length(constants));
    for i_par := 0 to length(constants) -1 do
       WorkingOnRef[i_par] := @Constants[i_par];
    listParms;
  end
  else if (SelectedRadioBtn = 2) and Assigned(tracers) then
  begin
    SetLength(WorkingOnRef, Length(tracers));
    for i_par := 0 to length(tracers) -1 do
       WorkingOnRef[i_par] := @tracers[i_par];
    listParms;
  end
  else if (SelectedRadioBtn = 3) and Assigned(auxiliaries) then
  begin
    SetLength(WorkingOnRef, Length(auxiliaries));
    for i_par := 0 to length(auxiliaries) -1 do
       WorkingOnRef[i_par] := @auxiliaries[i_par];
    listParms;
  end
  else if (SelectedRadioBtn = 4) and Assigned(processes) then
  begin
    SetLength(WorkingOnRef, Length(processes));
    for i_par := 0 to length(processes) -1 do
       WorkingOnRef[i_par] := @processes[i_par];
    listParms;
  end
  else if (SelectedRadioBtn = 5) and Assigned(elements) then
  begin
    SetLength(WorkingOnRef, Length(elements));
    for i_par := 0 to length(elements) -1 do
       WorkingOnRef[i_par] := @elements[i_par];
    listParms;
  end
  else if (SelectedRadioBtn = 6) and Assigned(cElements) then
  begin
    SetLength(WorkingOnRef, Length(cElements));
    for i_par := 0 to length(cElements) -1 do
       WorkingOnRef[i_par] := @cElements[i_par];
    listParms;
  end else if (SelectedRadioBtn = 7) then  //Modelinfos
  begin
    ComboInstances.Enabled := FALSE;
    ComboInstances.Text := 'model infos';

    //next two lines make save button work
    SetLength(WorkingOnRef, 1);
    WorkingOnRef[0] := @ModelInfos;

    //create overview object
    SetLength(dummy, 1);
    copyExtraTagsRecord( ModelInfos.ExtraTagsRecord, dummy[0] );
    ExtraTagsOverview := TExtraTagsOverview.Create(dummy);

    //make sure it is not -1, but 0 (analogy to one parameter)
    SelectedIndex := 0;
  end;

  updateExtraTags;

  //select a tag
  //Write down correct text in combobox
  ComboInstances.ItemIndex := SelectedIndex;
  //Use the extra tags of that constant
  SelectedExtraTags := ExtraTagsOverview.ExtraTags[SelectedIndex];

  updateListedValues;
end;

procedure TfrmCustomTags.lstExtraTagsDblClick(Sender: TObject);
var
  EnteredValue, SelectedTagName: String;
  SelectedIndex: Integer;
begin
  EnteredValue := '';
  SelectedIndex := lstExtraTags.ItemIndex;
  if (SelectedIndex > -1) and
     (InputQuery('Change Tag Name', 'Insert new tag name:', EnteredValue)) and
     validTagName(EnteredValue) then
  begin
    SelectedTagName := lstExtraTags.Items[SelectedIndex];
    SelectedExtraTags.changeTagName(SelectedTagName, EnteredValue);
    updateExtraTags;
    updateListedValues;
    unsavedChanges := True;
    frmCustomTags.Caption := UNSAVED_CAPTION;
  end;
end;

procedure TfrmCustomTags.lstExtraTagsKeyPress(Sender: TObject; var Key: char);
begin
  case key of
    #13 : lstExtraTagsDblClick(Sender);
  end;
end;

procedure TfrmCustomTags.lstExtraTagsSelectionChange(Sender: TObject;
  User: boolean);
begin
  if lstExtraTags.SelCount > 0 then
  begin
    btnDelTag.Enabled := True;
    {if (lstValues.Items.Count > lstExtraTags.ItemIndex) then
      lstValues.ItemIndex := lstExtraTags.ItemIndex;}
  end
  else
    btnDelTag.Enabled := False;
end;

procedure TfrmCustomTags.lstValuesDblClick(Sender: TObject);
var
  EnteredValue, SelectedTagName: String;
  SelectedIndex: Integer;
begin
  EnteredValue := '';
  SelectedIndex := lstValues.ItemIndex;
  if (SelectedIndex > -1) and
     (InputQuery('Change value', 'Insert new value:', EnteredValue)) then
  begin
    SelectedTagName := lstExtraTags.Items[SelectedIndex];
    SelectedExtraTags.setTag(SelectedTagName, EnteredValue);
    updateListedValues;
    unsavedChanges := True;
    frmCustomTags.Caption := UNSAVED_CAPTION;
  end;
end;

procedure TfrmCustomTags.lstValuesKeyPress(Sender: TObject; var Key: char);
begin
  case key of
    #13 : lstValuesDblClick(Sender);
  end;
end;



procedure TfrmCustomTags.btnAddTagClick(Sender: TObject);
var
  NewTagName: String;
  TagAlreadyExists: Boolean;

begin
  NewTagName := '';

  if (InputQuery('New Tag', 'Please enter the name for the new tag:', NewTagName)) then
  begin
    if (NewTagName <> '') and validTagName(NewTagName) then
    begin
      TagAlreadyExists :=  (lstExtraTags.Items.IndexOf(NewTagName) > -1);

      if not TagAlreadyExists then
      begin
        //make change in the gui
        lstExtraTags.Items.Add(newTagName);
        unsavedChanges := True;
        frmCustomTags.Caption := UNSAVED_CAPTION;
        //add new name to data structure
        SelectedExtraTags.setTag(NewTagName, '');
        //update list of values
        updateListedValues;
      end;
    end;
  end;
end;

procedure TfrmCustomTags.btnDelTagClick(Sender: TObject);
begin
   //check if anything is selected
  if (lstExtraTags.ItemIndex > -1) and
     SelectedExtraTags.delTag(lstExtraTags.Items[lstExtraTags.ItemIndex]) then
  begin
    lstExtraTags.Items.Delete(lstExtraTags.ItemIndex);
    unsavedChanges := True;
    frmCustomTags.Caption := UNSAVED_CAPTION;
    updateListedValues;
  end;
end;

procedure TfrmCustomTags.btnSaveClick(Sender: TObject);
begin
  SaveEverything;
end;

procedure TfrmCustomTags.comboInstancesChange(Sender: TObject);
var
  i_par: Integer;
  selected_par: ^TRecordWithExtraTags;
begin
  for i_par := 0 to Length(WorkingOnRef) -1 do
  begin
    selected_par := WorkingOnRef[i_par];

    if ( selected_par^.name = comboInstances.Text) then
    begin
      SelectedExtraTags := ExtraTagsOverview.ExtraTags[i_par];
      updateListedValues;
    end;
  end;
end;



procedure TfrmCustomTags.FormClose(Sender: TObject;
  var CloseAction: TCloseAction);
var
      reply, BoxStyle: Integer;
begin
  if (UnsavedChanges) then
  begin
    BoxStyle := MB_ICONQUESTION + MB_YESNO;
    reply := Application.MessageBox('Do you want to save changes?',
                                        'Save Changes',
             BoxStyle);
    if (reply = IDYES) then
      SaveEverything;
  end;

end;

procedure TfrmCustomTags.FormCreate(Sender: TObject);
begin
  if lstExtraTags.SelCount > 0 then
    btnDelTag.Enabled := True
  else
    btnDelTag.Enabled := False;
end;

procedure TfrmCustomTags.FormShow(Sender: TObject);
begin
  if (Self.UnsavedChanges) then
    Self.Caption := UNSAVED_CAPTION
  else
    Self.Caption := SAVED_CAPTION;
end;

end.

