unit fPtDemoEdit;
//kt Added this entire unit for demographics editing at runtime.

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls, ExtCtrls, DKLang, Grids, SortStringGrid;

type
  BoolUC = (bucFalse, bucTrue, bucUnchanged);

  tFileEntry = record
    Field     : string;
    FileNum   : string;
    FieldName : String;
    IENS      : string;
    oldValue,newValue : string;
  end;

  TGridInfo = class;  //forward declaration
  TGridDataLoader = procedure (GridInfo: TGridInfo) of object;
  TGridInfo = class (TObject)
  public
    Grid      : TSortStringGrid;  //doesn't own object
    FileNum   : string;
    IENS      : string;
    BasicMode : Boolean;
    Data      : TStringList;  //doesn't own object
    Message   : string;  //optional text.
    DataLoadProc : TGridDataLoader;
    ApplyBtn  : TButton;
    RevertBtn : TButton;
  end;

  TPatientInfo = class(TObject)
  public
    LName: String;
    FName: String;
    MName: String;
    CombinedName: String;
    Prefix: String;
    Suffix: String;
    Degree: String;
    DOB: String;
    Sex: String;
    SSNum: String;
    EMail: String;
    AliasInfo : TStringList;  //format: s=IEN#, Object is ^tAlias
    AddressLine1: String;
    AddressLine2: String;
    AddressLine3: String;
    City: String;
    State: String;
    Zip4: String;
    BadAddress: BoolUC;
    PhoneNumResidence: String;
    PhoneNumWork: String;
    PhoneNumCell: String;
    PhoneNumTemp: String;

    TempAddressLine1: String;
    TempAddressLine2: String;
    TempAddressLine3: String;
    TempCity: String;
    TempState: String;
    TempZip4: String;
    TempStartingDate : String;
    TempEndingDate : String;
    TempAddressActive: BoolUC;
      
    ConfidentalAddressLine1: String;
    ConfidentalAddressLine2: String;
    ConfidentalAddressLine3: String;
    ConfidentalCity: String;
    ConfidentalState: String;
    ConfidentalZip: String;
    ConfidentalStartingDate : String;
    ConfidentalEndingDate : String;
    ConfAddressActive : BoolUC;

    Modified : boolean;

    constructor Create;
    destructor Destroy; override;
    procedure ClearAliasInfo;
    procedure Clear;
    procedure Assign(Source : TPatientInfo);
    procedure RemoveUnchanged(OldInfo : TPatientInfo);
  end;

  TfrmPtDemoEdit = class(TForm)
    OKBtn: TButton;
    CancelBtn: TButton;
    ApplyBtn: TButton;
    PageControl: TPageControl;
    DemoTabSheet: TTabSheet;
    LNameLabel: TLabel;
    FNameLabel: TLabel;
    MNameLabel: TLabel;
    CombinedNameLabel: TLabel;
    PrefixLabel: TLabel;
    SuffixLabel: TLabel;
    DOBLabel: TLabel;
    SSNumLabel: TLabel;
    CombinedNameEdit: TEdit;
    LNameEdit: TEdit;
    FNameEdit: TEdit;
    MNameEdit: TEdit;
    PrefixEdit: TEdit;
    SuffixEdit: TEdit;
    DOBEdit: TEdit;
    SSNumEdit: TEdit;
    AliasGroupBox: TGroupBox;
    AliasComboBox: TComboBox;
    AliasNameLabel: TLabel;
    AliasSSNumLabel: TLabel;
    AliasNameEdit: TEdit;
    AliasSSNEdit: TEdit;
    AddressGroupBox: TGroupBox;
    AddressRGrp: TRadioGroup;
    AddressLine1Edit: TEdit;
    AddressLine2Edit: TEdit;
    AddressLine3Edit: TEdit;
    CityLabel: TLabel;
    CityEdit: TEdit;
    StateComboBox: TComboBox;
    Zip4Edit: TEdit;
    Zip4Label: TLabel;
    BadAddressCB: TCheckBox;
    TempActiveCB: TCheckBox;
    SexLabel: TLabel;
    SexComboBox: TComboBox;
    DelAliasBtn: TButton;
    StartingDateEdit: TEdit;
    StartingDateLabel: TLabel;
    EndingDateLabel: TLabel;
    EndingDateEdit: TEdit;
    ConfActiveCB: TCheckBox;
    DegreeEdit: TEdit;
    DegreeLabel: TLabel;
    AddAliasBtn: TButton;
    GroupBox1: TGroupBox;
    PhoneNumGrp: TRadioGroup;
    PhoneNumEdit: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    DKLanguageController1: TDKLanguageController;
    EMailEdit: TEdit;
    Advanced: TTabSheet;
    gridPatientDemo: TSortStringGrid;
    procedure AliasComboBoxChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure AddressRGrpClick(Sender: TObject);
    procedure PhoneNumGrpClick(Sender: TObject);
    procedure DelAliasBtnClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure CombinedNameEditChange(Sender: TObject);
    procedure LNameEditChange(Sender: TObject);
    procedure FNameEditChange(Sender: TObject);
    procedure MNameEditChange(Sender: TObject);
    procedure PrefixEditChange(Sender: TObject);
    procedure SuffixEditChange(Sender: TObject);
    procedure SexComboBoxChange(Sender: TObject);
    procedure EMailEditChange(Sender: TObject);
    procedure AddressLine1EditChange(Sender: TObject);
    procedure AddressLine2EditChange(Sender: TObject);
    procedure AddressLine3EditChange(Sender: TObject);
    procedure CityEditChange(Sender: TObject);
    procedure Zip4EditChange(Sender: TObject);
    procedure StateComboBoxChange(Sender: TObject);
    procedure TempActiveCBClick(Sender: TObject);
    procedure ConfActiveCBClick(Sender: TObject);
    procedure BadAddressCBClick(Sender: TObject);
    procedure DegreeEditChange(Sender: TObject);
    procedure PhoneNumEditChange(Sender: TObject);
    procedure StartingDateEditChange(Sender: TObject);
    procedure EndingDateEditChange(Sender: TObject);
    procedure AliasNameEditChange(Sender: TObject);
    procedure AliasSSNEditChange(Sender: TObject);
    procedure ApplyBtnClick(Sender: TObject);
    procedure AddAliasBtnClick(Sender: TObject);
    procedure OKBtnClick(Sender: TObject);
    procedure CancelBtnClick(Sender: TObject);
    procedure DOBEditChange(Sender: TObject);
    procedure SSNumEditChange(Sender: TObject);
    procedure PageControlChange(Sender: TObject);
    procedure gridPatientDemoSelectCell(Sender: TObject; ACol,
      ARow: Integer; var CanSelect: Boolean);
    procedure gridPatientDemoSetEditText(Sender: TObject; ACol,
      ARow: Integer; const Value: String);
    procedure PageControlChanging(Sender: TObject;
      var AllowChange: Boolean);
  private
    { Private declarations }
    FCurPatientInfo : TPatientInfo;
    FServerPatientInfo : TPatientInfo;
    FCurAliasEdit : integer;
    CurrentAnyFileData : TStringList;
    ProgAliasChangeOccuring : boolean;
    CurrentPatientData : TStringList;
    ProgNameChangeOccuring : boolean;
    ProgPhoneChangeOccuring : boolean;
    FLastSelectedRow,FLastSelectedCol : integer;
    ProgAddressChangeOccuring : boolean;
    DataForGrid : TStringList;
    MaxAliasIEN : integer;
    Data : TStringList;
    ChangesMade : boolean;
    BasicTemplate : TStringList;
    FLoadingGrid: boolean;
    CachedWPField : TStringList;
    procedure GetPtInfo(PatientInfo : TPatientInfo);
    procedure PostChangedInfo(PatientInfo : TPatientInfo);
    procedure ShowAliasInfo(Patient : TPatientInfo);
    procedure GetPatientInfo(GridInfo: TGridInfo);
    procedure ShowPtInfo(Patient : TPatientInfo);
    function CombinedName : string;
    procedure AddGridInfo(Grid: TSortStringGrid;
                                  Data : TStringList;
                                  BasicMode : boolean;
                                  DataLoader : TGridDataLoader;
                                  FileNum : string);
    procedure NameParts(CombinedName: string; var LName, FName, MName : string);
    function ExtractNum (S : String; StartPos : integer) : string;
    procedure SetModified(value : boolean);
    procedure SetAliasEnabled(value : boolean);
    function PostChanges(Grid : TSortStringGrid) : TModalResult;
    procedure CompileChanges(Grid : TSortStringGrid; CurrentUserData,Changes : TStringList);
    procedure RegisterGridInfo(GridInfo : TGridInfo);
  public
    { Public declarations }
    function GetInfoForGrid(Grid : TSortStringGrid) : TGridInfo;
    procedure LoadAnyGrid(Grid : TSortStringGrid; BasicMode: boolean; FileNum : string;
                                  IENS : string;
                                  CurrentData : TStringList);
    procedure LoadAnyGridFromInfo(GridInfo : TGridInfo);
    function IsWPField(FileNum,FieldNum : string) : boolean;
    function IsSubFile(FieldDef: string ; var SubFileNum : string) : boolean;
    function GetInfoIndexForGrid(Grid : TSortStringGrid) : integer;
    function PostVisibleGrid: TModalResult;
    function GetLineInfo(Grid : TSortStringGrid; CurrentUserData : TStringList; ARow: integer) : tFileEntry;
    procedure GetOneRecord(FileNum, IENS : string; Data, BlankFileInfo: TStringList);
    //procedure GridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
    function GetUserLine(CurrentUserData : TStringList; Grid : TSortStringGrid; ARow: integer) : integer;
    function FindInStrings(fieldNum : string; Strings : TStringList; var fileNum : string) : integer;
  end;

var
  frmPtDemoEdit: TfrmPtDemoEdit;

Const
  DEF_GRID_ROW_HEIGHT = 17;  
  CLICK_FOR_SUBS = '<CLICK for Sub-Entries>';
  COMPUTED_FIELD = '<Computed Field --> CAN''T EDIT>';
  CLICK_TO_EDIT = '<CLICK to Edit Text>';
  HIDDEN_FIELD = '<Hidden>';

implementation

{$R *.dfm}

uses
  IniFiles,Trpcb,ORNet,uCore, mfunstr, subfilesU, strutils, LookupU, SetSelU,
  SelDateTimeU, PostU, EditTextU, FMErrorU;

const
  ADD_NEW_ALIAS = '<Add New Alias>';

type
  tAlias= class
    Name : string;
    SSN : string;
    procedure Assign(Source: tAlias);
  end;

procedure tAlias.Assign(Source : tAlias);
begin
  Name := Source.Name;
  SSN := Source.SSN;
end;  

//=========================================================
//=========================================================
//=========================================================
  
constructor TPatientInfo.Create;
begin
  AliasInfo := TStringList.Create;
  
  Clear;
end;

destructor TPatientInfo.Destroy;
begin
  ClearAliasInfo;  
  AliasInfo.Free;
  inherited Destroy;
End;

procedure TPatientInfo.ClearAliasInfo;
var i : integer;
    pAlias : tAlias;
begin
  for i := 0 to AliasInfo.Count-1 do begin
    pAlias := tAlias(AliasInfo.Objects[i]);
    pAlias.Free;
  end;
  AliasInfo.Clear
End;

procedure TPatientInfo.Clear;
begin
  LName:= '';
  FName:= '';
  MName:= '';
  CombinedName:= '';
  Prefix:= '';
  Suffix:= '';
  Degree:= '';
  DOB:= '';
  SSNum:= '';
  EMail:= '';
  ClearAliasInfo;  
  AddressLine1:= '';
  AddressLine2:= '';
  AddressLine3:= '';
  City:= '';
  State:= '';
  Zip4:= '';
  TempAddressLine1:= '';
  TempAddressLine2:= '';
  TempAddressLine3:= '';
  TempCity:= '';
  TempState:= '';
  TempZip4:= '';
  TempStartingDate := '';
  TempEndingDate := '';
  ConfidentalAddressLine1:= '';
  ConfidentalAddressLine2:= '';
  ConfidentalAddressLine3:= '';
  ConfidentalCity:= '';
  ConfidentalState:= '';
  ConfidentalZip:= '';
  ConfidentalStartingDate := '';
  ConfidentalEndingDate := '';
  BadAddress:= bucFalse;
  TempAddressActive:= bucFalse;
  ConfAddressActive := bucFalse;
  Modified := false;
  
  PhoneNumResidence:= '';
  PhoneNumWork:= '';
  PhoneNumCell:= '';
  PhoneNumTemp:= '';
  Sex:= '';
end;


procedure TPatientInfo.Assign(Source : TPatientInfo);
var i : integer;
    pAlias : tAlias;
    OtherpAlias : tAlias;
begin
  LName:=Source.LName;
  FName:=Source.FName;
  MName:=Source.MName;
  CombinedName:=Source.CombinedName;
  Prefix:=Source.Prefix;
  Suffix:=Source.Suffix;
  Degree:=Source.Degree;
  DOB:=Source.DOB;
  SSNum:=Source.SSNum;
  EMail:=Source.EMail;
  
  ClearAliasInfo;
  //Copy pointed to tAlias entries, don't simply copy references
  for i := 0 to Source.AliasInfo.Count-1 do begin
    AliasInfo.Add(Source.AliasInfo.Strings[i]);
    OtherpAlias := tAlias(Source.AliasInfo.Objects[i]);
    if OtherpAlias<>nil then begin
      pAlias := tAlias.Create;
      pAlias.Name := OtherpAlias.Name;
      pAlias.SSN := OtherpAlias.SSN;
      AliasInfo.Objects[i]:=pAlias;    
    end;
  end;
  AddressLine1:=Source.AddressLine1;
  AddressLine2:=Source.AddressLine2;
  AddressLine3:=Source.AddressLine3;
  City:=Source.City;
  State:=Source.State;
  Zip4:=Source.Zip4;
  TempAddressLine1:=Source.TempAddressLine1;
  TempAddressLine2:=Source.TempAddressLine2;
  TempAddressLine3:=Source.TempAddressLine3;
  TempCity:=Source.TempCity;
  TempState:=Source.TempState;
  TempZip4:=Source.TempZip4;
  TempStartingDate :=Source.TempStartingDate ;
  TempEndingDate :=Source.TempEndingDate ;
  ConfidentalAddressLine1:=Source.ConfidentalAddressLine1;
  ConfidentalAddressLine2:=Source.ConfidentalAddressLine2;
  ConfidentalAddressLine3:=Source.ConfidentalAddressLine3;
  ConfidentalCity:=Source.ConfidentalCity;
  ConfidentalState:=Source.ConfidentalState;
  ConfidentalZip:=Source.ConfidentalZip;
  ConfidentalStartingDate :=Source.ConfidentalStartingDate ;
  ConfidentalEndingDate :=Source.ConfidentalEndingDate ;
  BadAddress:= Source.BadAddress;
  TempAddressActive:= Source.TempAddressActive;
  ConfAddressActive := Source.ConfAddressActive;
  PhoneNumResidence:=Source.PhoneNumResidence;
  PhoneNumWork:=Source.PhoneNumWork;
  PhoneNumCell:=Source.PhoneNumCell;
  PhoneNumTemp:=Source.PhoneNumTemp;
  Sex:=Source.Sex;
  EMail := Source.EMail;
end;


procedure TPatientInfo.RemoveUnchanged(OldInfo : TPatientInfo);
//Will remove entries that are unchanged from OldInfo
//ALSO, will change AliasInfo entries:
//     Other code adds "IEN" numbers that don't have any corresponding
//     true IEN on the server.  This will convert these to +1,+2 etc.
//     And, if there is an alias entry in the OldInfo that is not
//     in this info, then a matching @ entry for that IEN will be generated.

  procedure CompStrs(var newS, oldS : string);
  begin
    if newS = oldS then begin
      newS := '';  //no change, 
    end else begin
      if (newS = '') and (oldS <> '') then newS := '@' //delete symbol
    end;
  end;

  procedure CompBoolUC(var newBN, oldBN : BoolUC);
  begin
    if newBN=oldBN then begin
      newBN := bucUnchanged;  //Mark unchanged
    end;  
  end;

  const
    BOOL_STR : array[false..true] of string =('TRUE','FALSE');
    NO_CHANGE = 1;
    NEW_RECORD = 2;
    DELETED_RECORD = 3;
    CHANGED_RECORD = 4;

  function CompAliasRec(curAlias,oldAlias : tAlias) : integer;
  //Returns: NO_CHANGE = 1; NEW_RECORD = 2; DELETED_RECORD = 3; CHANGED_RECORD = 4;
  begin
    Result := NO_CHANGE;
    if (curAlias <> nil) and (oldAlias <> nil) then begin
      if curAlias.Name = '' then begin 
        if oldAlias.Name <> '' then Result := DELETED_RECORD;
      end else if curAlias.Name <> oldAlias.Name then begin
        Result := CHANGED_RECORD;
      end;
      if Result = NO_CHANGE then begin
        if curAlias.SSN <> oldAlias.SSN then Result := CHANGED_RECORD;
      end;
    end;  
  end;
  
  function CompAlias(IEN : string; pAlias : tAlias; OldInfo : TPatientInfo) : integer;
  //format: s=IEN#, Object is ^tAlias  
  //Returns: NO_CHANGE = 1; NEW_RECORD = 2; DELETED_RECORD = 3; CHANGED_RECORD = 4;
  var i : integer;
      oldPAlias : tAlias;
  begin
    Result := NEW_RECORD;
    for i := 0 to OldInfo.AliasInfo.Count-1 do begin
      if OldInfo.AliasInfo.Strings[i] = IEN then begin
        oldPAlias := tAlias(OldInfo.AliasInfo.Objects[i]);
        Result :=  CompAliasRec(pAlias,oldPAlias);
        break;
      end;
    end;
  end;

  var i,j,AddCt : integer;  
      pAlias, tempPAlias : tAlias;
 
begin
  {if OldInfo = This Info, then remove entries}
  CompStrs(LName, OldInfo.LName);
  CompStrs(FName, OldInfo.FName);
  CompStrs(MName, OldInfo.MName);
  CompStrs(CombinedName, OldInfo.CombinedName);
  CompStrs(Prefix, OldInfo.Prefix);
  CompStrs(Suffix, OldInfo.Suffix);
  CompStrs(Degree, OldInfo.Degree);
  CompStrs(DOB, OldInfo.DOB);
  CompStrs(SSNum, OldInfo.SSNum);
  CompStrs(EMail, OldInfo.EMail);
  
  CompStrs(AddressLine1, OldInfo.AddressLine1);
  CompStrs(AddressLine2, OldInfo.AddressLine2);
  CompStrs(AddressLine3, OldInfo.AddressLine3);
  CompStrs(City, OldInfo.City);
  CompStrs(State, OldInfo.State);
  CompStrs(Zip4, OldInfo.Zip4);
  CompStrs(TempAddressLine1, OldInfo.TempAddressLine1);
  CompStrs(TempAddressLine2, OldInfo.TempAddressLine2);
  CompStrs(TempAddressLine3, OldInfo.TempAddressLine3);
  CompStrs(TempCity, OldInfo.TempCity);
  CompStrs(TempState, OldInfo.TempState);
  CompStrs(TempZip4, OldInfo.TempZip4);
  CompStrs(TempStartingDate , OldInfo.TempStartingDate );
  CompStrs(TempEndingDate , OldInfo.TempEndingDate );
  CompStrs(ConfidentalAddressLine1, OldInfo.ConfidentalAddressLine1);
  CompStrs(ConfidentalAddressLine2, OldInfo.ConfidentalAddressLine2);
  CompStrs(ConfidentalAddressLine3, OldInfo.ConfidentalAddressLine3);
  CompStrs(ConfidentalCity, OldInfo.ConfidentalCity);
  CompStrs(ConfidentalState, OldInfo.ConfidentalState);
  CompStrs(ConfidentalZip, OldInfo.ConfidentalZip);
  CompStrs(ConfidentalStartingDate , OldInfo.ConfidentalStartingDate );
  CompStrs(ConfidentalEndingDate , OldInfo.ConfidentalEndingDate );

  CompBoolUC(BadAddress, OldInfo.BadAddress);
  CompBoolUC(TempAddressActive, OldInfo.TempAddressActive);
  CompBoolUC(ConfAddressActive, OldInfo.ConfAddressActive);
  
  CompStrs(PhoneNumResidence, OldInfo.PhoneNumResidence);
  CompStrs(PhoneNumWork, OldInfo.PhoneNumWork);
  CompStrs(PhoneNumCell, OldInfo.PhoneNumCell);
  CompStrs(PhoneNumTemp, OldInfo.PhoneNumTemp);
  CompStrs(Sex, OldInfo.Sex);

  //Compare Aliases
  //format: s=IEN#, Object is ^tAlias  

  //first, see which entries in OldInfo are deleted in CurInfo.
  for i := 0 to OldInfo.AliasInfo.Count-1 do begin
    pAlias := tAlias(OldInfo.AliasInfo.Objects[i]);
    if CompAlias(OldInfo.AliasInfo.Strings[i], pAlias, self) = NEW_RECORD then begin
      //here we have an entry in OldInfo, not in CurInfo, so must represent a Delete
      //This needs to be posted to server with old IEN and @ symbol
      tempPAlias := tAlias.Create;
      tempPAlias.Name := '@';
      AliasInfo.AddObject(OldInfo.AliasInfo.Strings[i],tempPAlias);          
    end; 
  end;  
  
  AddCt := 0;
  //First, see which entries in New PatientInfo are new, or unchanged.
  for i := 0 to AliasInfo.Count-1 do begin
    pAlias := tAlias(AliasInfo.Objects[i]);
    if (pAlias=nil) then continue;
    if pAlias.Name= '@' then continue;   //skip those marked as deleted from OldInfo
    case CompAlias(AliasInfo.Strings[i], pAlias, OldInfo) of
      NO_CHANGE      : begin  //delete unchanged data (no need to repost to server)
                         pAlias.Destroy;
                         AliasInfo.Strings[i] :='<@>';  //mark for deletion below
                       end;
      NEW_RECORD :     begin  //mark as +1, +2 etc IEN
                         AddCt := AddCt + 1;
                         AliasInfo.Strings[i] := '+' + IntToStr(AddCt);
                       end;
     CHANGED_RECORD :  begin end;  // do nothing, leave changes in place
    end; {case}  
  end;

  for i := AliasInfo.Count-1 downto 0 do begin
    if AliasInfo.Strings[i] = '<@>' then AliasInfo.Delete(i);
  end;
  
  
end;


//=========================================================
//=========================================================
//=========================================================

procedure TfrmPtDemoEdit.GetPtInfo;
var  tempINI : TMemINIFile;  //I do this to make dealing with hash table read easier
     i,index : integer;
     IEN, Key,Value,s : string;
     pAlias : tAlias;
     
begin
  FServerPatientInfo.Clear;  
  tempINI := TMemINIFile.Create('xxx.ini');
  
  RPCBrokerV.remoteprocedure := 'TMG GET PATIENT DEMOGRAPHICS';
  RPCBrokerV.param[0].value := Patient.DFN;   RPCBrokerV.param[0].ptype := literal;
  //RPCBrokerV.Call;
  CallBroker;

  with FServerPatientInfo do begin
    //Store results in a hash table for easier random access
    //Don't store Alias info in hash table, put directly into AliasInfo stringlist
    for i := 0 to RPCBrokerV.Results.Count-1 do begin
      s := RPCBrokerV.Results.Strings[i];
      if Pos('ALIAS',s)=0 then begin
        Key := piece(s,'=',1);
        Value := piece(s,'=',2);
        tempINI.WriteString('DATA',Key,Value);
      end else begin
        IEN := piece(s,' ',2);
        if StrToInt(IEN)>MaxAliasIEN then MaxAliasIEN := StrToInt(IEN);
        index := AliasInfo.IndexOf(IEN);
        if index <0 then begin
          pAlias := tAlias.Create;  //AliasInfo will own these.
          AliasInfo.AddObject(IEN,pAlias);
        end else begin
          pAlias := tAlias(AliasInfo.Objects[index]);
        end;
        if Pos('NAME=',s)>0 then begin
          pAlias.Name := piece(s,'=',2);
        end else if Pos('SSN=',s)>0 then begin
          pAlias.SSN := piece(s,'=',2);
        end;  
      end;
    end;
    LName:=tempINI.ReadString('DATA','LNAME','');
    FName:=tempINI.ReadString('DATA','FNAME','');
    MName:=tempINI.ReadString('DATA','MNAME','');
    CombinedName:=tempINI.ReadString('DATA','COMBINED_NAME','');
    Prefix:=tempINI.ReadString('DATA','PREFIX','');
    Suffix:=tempINI.ReadString('DATA','SUFFIX','');
    Degree:=tempINI.ReadString('DATA','DEGREE','');
    DOB:= tempINI.ReadString('DATA','DOB','');
    Sex:= tempINI.ReadString('DATA','SEX','');
    SSNum:= tempINI.ReadString('DATA','SS_NUM','');
    EMail:= tempINI.ReadString('DATA','EMAIL','');
    AddressLine1:= tempINI.ReadString('DATA','ADDRESS_LINE_1','');
    AddressLine2:= tempINI.ReadString('DATA','ADDRESS_LINE_2','');
    AddressLine3:= tempINI.ReadString('DATA','ADDRESS_LINE_3','');
    City:= tempINI.ReadString('DATA','CITY','');
    State:= tempINI.ReadString('DATA','STATE','');
    Zip4:= tempINI.ReadString('DATA','ZIP4','');
    BadAddress:= BoolUC(tempINI.ReadString('DATA','BAD_ADDRESS','')<>'');
    TempAddressLine1:= tempINI.ReadString('DATA','TEMP_ADDRESS_LINE_1','');
    TempAddressLine2:= tempINI.ReadString('DATA','TEMP_ADDRESS_LINE_2','');
    TempAddressLine3:= tempINI.ReadString('DATA','TEMP_ADDRESS_LINE_3','');
    TempCity:= tempINI.ReadString('DATA','TEMP_CITY','');
    TempState:=tempINI.ReadString('DATA','TEMP_STATE','');
    TempZip4:= tempINI.ReadString('DATA','TEMP_ZIP4','');
    TempStartingDate :=tempINI.ReadString('DATA','TEMP_STARTING_DATE','');
    TempEndingDate := tempINI.ReadString('DATA','TEMP_ENDING_DATE','');
    TempAddressActive:= BoolUC(tempINI.ReadString('DATA','TEMP_ADDRESS_ACTIVE','')='YES');
    ConfidentalAddressLine1:= tempINI.ReadString('DATA','CONF_ADDRESS_LINE_1','');
    ConfidentalAddressLine2:= tempINI.ReadString('DATA','CONF_ADDRESS_LINE_2','');
    ConfidentalAddressLine3:= tempINI.ReadString('DATA','CONF_ADDRESS_LINE_3','');
    ConfidentalCity:= tempINI.ReadString('DATA','CONF_CITY','');
    ConfidentalState:= tempINI.ReadString('DATA','CONF_STATE','');
    ConfidentalZip:= tempINI.ReadString('DATA','CONF_ZIP','');
    ConfidentalStartingDate := tempINI.ReadString('DATA','CONG_STARTING_DATE','');
    ConfidentalEndingDate := tempINI.ReadString('DATA','CONF_ENDING_DATE','');
    ConfAddressActive:= BoolUC(tempINI.ReadString('DATA','CONF_ADDRESS_ACTIVE','')='YES');
    PhoneNumResidence:= tempINI.ReadString('DATA','PHONE_RESIDENCE','');
    PhoneNumWork:= tempINI.ReadString('DATA','PHONE_WORK','');
    PhoneNumCell:= tempINI.ReadString('DATA','PHONE_CELL','');
    PhoneNumTemp:= tempINI.ReadString('DATA','PHONE_TEMP','');
  end;
  FCurPatientInfo.Assign(FServerPatientInfo);
  tempINI.Free;  //I don't write out, so should never end up on disk.
end;

procedure TfrmPtDemoEdit.PostChangedInfo(PatientInfo : TPatientInfo);

  procedure CheckBUCPost(Title : string; Value : BoolUC);
  begin 
    if Value <> bucUnchanged then begin
      if Value = bucTrue then RPCBrokerV.Param[1].Mult['"'+Title+'"'] := 'YES';
      if Value = bucFalse then RPCBrokerV.Param[1].Mult['"'+Title+'"'] := 'NO';
    end;  
  end;

  procedure CheckPost(Title, Value : string);
  begin 
    if Value <> '' then RPCBrokerV.Param[1].Mult['"'+Title+'"'] := Value;
  end;
  
  var i : integer;
      pAlias : tAlias;
begin
  RPCBrokerV.remoteprocedure := 'TMG SET PATIENT DEMOGRAPHICS';
  RPCBrokerV.param[0].value := Patient.DFN;   RPCBrokerV.param[0].ptype := literal;

  RPCBrokerV.Param[1].PType := list;
  with PatientInfo do begin
    CheckPost('COMBINED_NAME',CombinedName);
    //CheckPost('LNAME', LName);    //Don't send because data is in COMBINED NAME
    //CheckPost('FNAME',FName);
    //CheckPost('MNAME',MName);
    //CheckPost('PREFIX',Prefix);
    //CheckPost('SUFFIX',Suffix);
    //CheckPost('DEGREE',Degree);
    CheckPost('DOB',DOB);
    CheckPost('SEX',Sex);
    CheckPost('SS_NUM',SSNum);
    CheckPost('EMAIL',EMail);
    CheckPost('ADDRESS_LINE_1',AddressLine1);
    CheckPost('ADDRESS_LINE_2',AddressLine2);
    CheckPost('ADDRESS_LINE_3',AddressLine3);
    CheckPost('CITY',City);
    CheckPost('STATE',State);
    CheckPost('ZIP4',Zip4);

    CheckPost('TEMP_ADDRESS_LINE_1',TempAddressLine1);
    CheckPost('TEMP_ADDRESS_LINE_2',TempAddressLine2);
    CheckPost('TEMP_ADDRESS_LINE_3',TempAddressLine3);
    CheckPost('TEMP_CITY',TempCity);
    CheckPost('TEMP_STATE',TempState);
    CheckPost('TEMP_ZIP4',TempZip4);
    CheckPost('TEMP_STARTING_DATE',TempStartingDate );
    CheckPost('TEMP_ENDING_DATE',TempEndingDate );
    CheckPost('CONF_ADDRESS_LINE_1',ConfidentalAddressLine1);
    CheckPost('CONF_ADDRESS_LINE_2',ConfidentalAddressLine2);
    CheckPost('CONF_ADDRESS_LINE_3',ConfidentalAddressLine3);
    CheckPost('CONF_CITY',ConfidentalCity);
    CheckPost('CONF_STATE',ConfidentalState);
    CheckPost('CONF_ZIP',ConfidentalZip);
    CheckPost('CONG_STARTING_DATE',ConfidentalStartingDate );
    CheckPost('CONF_ENDING_DATE',ConfidentalEndingDate );
    CheckPost('PHONE_RESIDENCE',PhoneNumResidence);
    CheckPost('PHONE_WORK',PhoneNumWork);
    CheckPost('PHONE_CELL',PhoneNumCell);
    CheckPost('PHONE_TEMP',PhoneNumTemp);

    case BadAddress of
      bucTrue:  RPCBrokerV.Param[1].Mult['"BAD_ADDRESS"'] := 'UNDELIVERABLE';
      bucFalse: RPCBrokerV.Param[1].Mult['"BAD_ADDRESS"'] := '@';
    end; {case}
    CheckBUCPost('TEMP_ADDRESS_ACTIVE', TempAddressActive);
    CheckBUCPost('CONF_ADDRESS_ACTIVE', ConfAddressActive);

    for i := 0 to AliasInfo.Count-1 do begin
      pAlias := tAlias(AliasInfo.Objects[i]);
      if (pAlias=nil) then continue;
      RPCBrokerV.Param[1].Mult['"ALIAS ' + AliasInfo.Strings[i] +  ' NAME"'] := pAlias.Name;
      if pAlias.Name <> '@' then begin
        RPCBrokerV.Param[1].Mult['"ALIAS ' + AliasInfo.Strings[i] +  ' SSN"'] := pAlias.SSN;
      end;
    end;

    //RPCBrokerV.Call;
    CallBroker;
    if RPCBrokerV.Results.Strings[0]<>'1' then begin
      MessageDlg(RPCBrokerV.Results.Strings[0],mtError,[mbOK],0);
    end else begin
      ChangesMade := true;
    end;
  end;  
end;


procedure TfrmPtDemoEdit.ShowPtInfo(Patient : TPatientInfo);
var i : integer;
    pAlias : tAlias;
begin
  ProgNameChangeOccuring := true;
  With Patient do begin
    LNameEdit.Text := LName;
    FNameEdit.Text := FName;
    MNameEdit.Text := MName;
    CombinedNameEdit.Text := CombinedName;
    PrefixEdit.Text := Prefix;
    SuffixEdit.Text := Suffix;
    DegreeEdit.Text := Degree;
    DOBEdit.Text := DOB;
    SSNumEdit.Text := SSNum;
    EMailEdit.Text := EMail;
    if Sex='MALE' then SexComboBox.ItemIndex := 0 else SexComboBox.ItemIndex := 1;
    AliasComboBox.Items.Clear;
    for i := 0 to AliasInfo.Count-1 do begin
      pAlias := tAlias(AliasInfo.Objects[i]);
      if pAlias<>nil then begin
        AliasComboBox.Items.AddObject(pAlias.Name,pAlias);
      end;
    end;
    if AliasComboBox.Items.count>0 then begin
      AliasComboBox.ItemIndex := 0;
      SetAliasEnabled(true);
    end;
    ShowAliasInfo(Patient);
    
    PhoneNumGrp.ItemIndex := 0;
    PhoneNumGrpClick(self);
  end;  

  BadAddressCB.Visible := false;
  TempActiveCB.Visible := false;
  ProgNameChangeOccuring := false;
end;

procedure TfrmPtDemoEdit.ShowAliasInfo(Patient : TPatientInfo);
var i : integer;
    pAlias : tAlias;
begin
  i := AliasComboBox.ItemIndex;
  if i > -1 then begin
    if i < Patient.AliasInfo.Count then begin
      pAlias := tAlias(Patient.AliasInfo.Objects[i]);
    end else pAlias := nil;  
    ProgAliasChangeOccuring := true;
    if pAlias<>nil then begin
      AliasNameEdit.Text := pAlias.Name;
      AliasSSNEdit.Text := pAlias.SSN;    
    end else begin
      AliasNameEdit.Text := '';
      AliasSSNEdit.Text := '';    
    end;
    ProgAliasChangeOccuring := false;
  end;  
end;


procedure TfrmPtDemoEdit.AliasComboBoxChange(Sender: TObject);
var s : string;
    i : integer;
begin
  if ProgAliasChangeOccuring=false then begin
    i := AliasCombobox.ItemIndex;
    if i>-1 then begin
      s := AliasCombobox.Items.Strings[i];
      SetAliasEnabled(true);
    end else begin
      SetAliasEnabled(false);
    end;  
    ShowAliasInfo(FCurPatientInfo);
  end;
end;

procedure TfrmPtDemoEdit.FormCreate(Sender: TObject);
begin
  FCurAliasEdit := -1;
  FCurPatientInfo := TPatientInfo.Create;
  FServerPatientInfo := TPatientInfo.Create;
  DataForGrid := TStringList.Create;  //will own GridInfo objects.
  ProgAliasChangeOccuring  := false;
  ProgNameChangeOccuring := false;
  ProgPhoneChangeOccuring := false;
  ProgAddressChangeOccuring := false;
  MaxAliasIEN := 0;
  ChangesMade := false;
  CurrentPatientData := TStringList.Create;
  AddGridInfo(GridPatientDemo,CurrentPatientData,false,GetPatientInfo,'2');

end;

procedure TfrmPtDemoEdit.FormDestroy(Sender: TObject);
begin
  DataForGrid.Free;
  FCurPatientInfo.Destroy;
  FServerPatientInfo.Destroy;
  CurrentPatientData.Free;
end;


procedure TfrmPtDemoEdit.AddressRGrpClick(Sender: TObject);
begin
  {fill in data for newly selected fields}
  ProgAddressChangeOccuring := true;
  TempActiveCB.Visible := false;
  BadAddressCB.Visible := false;
  ConfActiveCB.Visible := false;
  StartingDateLabel.Visible := false;
  StartingDateEdit.Visible := false;
  EndingDateLabel.Visible := false;
  EndingDateEdit.Visible := false;
  case AddressRGrp.ItemIndex of
    0 : begin //Permanant
          AddressLine1Edit.Text := FCurPatientInfo.AddressLine1;
          AddressLine2Edit.Text := FCurPatientInfo.AddressLine2;
          AddressLine3Edit.text := FCurPatientInfo.AddressLine3;
          CityEdit.text := FCurPatientInfo.City;
          StateComboBox.text := FCurPatientInfo.State;
          Zip4Edit.text := FCurPatientInfo.Zip4;
          BadAddressCB.Visible := true;
          BadAddressCB.Checked := (FCurPatientInfo.BadAddress=bucTrue);
        end;
    1 : begin //temp
          AddressLine1Edit.Text := FCurPatientInfo.TempAddressLine1;
          AddressLine2Edit.Text := FCurPatientInfo.TempAddressLine2;
          AddressLine3Edit.Text := FCurPatientInfo.TempAddressLine3;
          CityEdit.Text := FCurPatientInfo.TempCity;
          StateComboBox.Text := FCurPatientInfo.TempState;
          Zip4Edit.Text := FCurPatientInfo.TempZip4;
          StartingDateEdit.Text := FCurPatientInfo.TempStartingDate ;
          EndingDateEdit.Text := FCurPatientInfo.TempEndingDate ;
          StartingDateLabel.Visible := true;
          StartingDateEdit.Visible := true;
          EndingDateLabel.Visible := true;
          EndingDateEdit.Visible := true;
          TempActiveCB.Visible := true;
          TempActiveCB.Checked := (FCurPatientInfo.TempAddressActive=bucTrue);
        end;
    2 : begin //confidental
          AddressLine1Edit.Text := FCurPatientInfo.ConfidentalAddressLine1;
          AddressLine2Edit.Text := FCurPatientInfo.ConfidentalAddressLine2;
          AddressLine3Edit.Text := FCurPatientInfo.ConfidentalAddressLine3;
          CityEdit.Text := FCurPatientInfo.ConfidentalCity;
          StateComboBox.Text := FCurPatientInfo.ConfidentalState;
          Zip4Edit.Text := FCurPatientInfo.ConfidentalZip;
          StartingDateEdit.Text := FCurPatientInfo.ConfidentalStartingDate ;
          EndingDateEdit.Text := FCurPatientInfo.ConfidentalEndingDate ;
          StartingDateLabel.Visible := true;
          StartingDateEdit.Visible := true;
          EndingDateLabel.Visible := true;
          EndingDateEdit.Visible := true;
          ConfActiveCB.Visible := true;
          ConfActiveCB.Checked := (FCurPatientInfo.ConfAddressActive=bucTrue);
        end;
  end; {case}
  ProgAddressChangeOccuring := false;
end;

procedure TfrmPtDemoEdit.PhoneNumGrpClick(Sender: TObject);
begin
  ProgPhoneChangeOccuring := true;
  case PhoneNumGrp.ItemIndex of
    0 : begin //Residence
          PhoneNumEdit.Text := FCurPatientInfo.PhoneNumResidence;
        end;
    1 : begin //work
          PhoneNumEdit.Text := FCurPatientInfo.PhoneNumWork;
        end;
    2 : begin //cell
          PhoneNumEdit.Text := FCurPatientInfo.PhoneNumCell;
        end;
    3 : begin //temp
          PhoneNumEdit.Text := FCurPatientInfo.PhoneNumTemp;
        end;
   else begin
          PhoneNumEdit.Text := '';
        end;    
  end; {case}
  ProgPhoneChangeOccuring := false;
end;

procedure TfrmPtDemoEdit.DelAliasBtnClick(Sender: TObject);
var i, j : integer;
    pAlias : tAlias;
begin
  i := AliasComboBox.ItemIndex;
  if i > -1 then begin
    pAlias := tAlias(AliasComboBox.Items.Objects[i]);
    if pAlias<>nil then begin
      for j := 0 to FCurPatientInfo.AliasInfo.Count-1 do begin
        if FCurPatientInfo.AliasInfo.Objects[j] = pAlias then begin
          FCurPatientInfo.AliasInfo.Delete(j);
          SetModified(true);
          pAlias.Free;
          AliasComboBox.Items.Delete(i);
          //AliasComboBox.ItemIndex := 0;
          //ShowAliasInfo(FCurPatientInfo);
          ProgAliasChangeOccuring:= true;
          AliasNameEdit.Text:='';
          AliasSSNEdit.Text:='';
          ProgAliasChangeOccuring:= false;
          break;
        end;
      end;
    end;
  end;
  if AliasCombobox.Items.Count=0 then begin
    AliasNameEdit.Text:='';
    AliasSSNEdit.Text:='';          
    SetAliasEnabled(false);
    AliasCombobox.Text := '';
  end;
end;

procedure TfrmPtDemoEdit.FormShow(Sender: TObject);
begin
  PageControl.ActivePageIndex := 0;
  GetPtInfo(FServerPatientInfo);
  FCurPatientInfo.Assign(FServerPatientInfo);
  ShowPtInfo(FCurPatientInfo);
end;

procedure TfrmPtDemoEdit.CombinedNameEditChange(Sender: TObject);
var LName,FName,MName : string;
begin 
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.CombinedName := CombinedNameEdit.Text; 
    SetModified(true);
    if CombinedNameEdit.Text <> CombinedName then begin
      ProgNameChangeOccuring := true;
      NameParts(CombinedNameEdit.Text, LName, FName, MName);
      LNameEdit.Text := LName;
      FNameEdit.Text := FName;
      MNameEdit.Text := MName;
      ProgNameChangeOccuring := false;
    end;
  end;    
end;

procedure TfrmPtDemoEdit.LNameEditChange(Sender: TObject);
begin 
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.LName := LNameEdit.Text; 
    SetModified(true);
    CombinedNameEdit.Text := CombinedName;
  end;
end;

procedure TfrmPtDemoEdit.FNameEditChange(Sender: TObject);
begin 
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.FName := FNameEdit.Text; 
    SetModified(true);
    CombinedNameEdit.Text := CombinedName;
  end  
end;

procedure TfrmPtDemoEdit.MNameEditChange(Sender: TObject);
begin 
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.MName := MNameEdit.Text;
    SetModified(true);
    CombinedNameEdit.Text := CombinedName;
  end;
end;

procedure TfrmPtDemoEdit.PrefixEditChange(Sender: TObject);
begin
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.Prefix := PrefixEdit.Text;
    SetModified(true);
  end;
end;

procedure TfrmPtDemoEdit.SuffixEditChange(Sender: TObject);
begin
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.Suffix := SuffixEdit.Text;
    SetModified(true);
    CombinedNameEdit.Text := CombinedName;
  end;
end;

procedure TfrmPtDemoEdit.DOBEditChange(Sender: TObject);
begin
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.DOB := DOBEdit.Text;
    SetModified(true);
  end;
end;

procedure TfrmPtDemoEdit.SSNumEditChange(Sender: TObject);
begin
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.SSNum := SSNumEdit.Text;
    SetModified(true);
  end;
end;

procedure TfrmPtDemoEdit.EMailEditChange(Sender: TObject);
begin
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.EMail := EMailEdit.Text;
    SetModified(true);
  end;
end;

procedure TfrmPtDemoEdit.SexComboBoxChange(Sender: TObject);
begin
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.Sex := SexComboBox.Text;
    SetModified(true);
  end;
end;

procedure TfrmPtDemoEdit.DegreeEditChange(Sender: TObject);
begin  
  if ProgNameChangeOccuring = false then begin
    FCurPatientInfo.Degree := DegreeEdit.Text;
    SetModified(true);
  end;  
end;

procedure TfrmPtDemoEdit.AddressLine1EditChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    0 : FCurPatientInfo.AddressLine1 := AddressLine1Edit.Text;
    1 : FCurPatientInfo.TempAddressLine1 := AddressLine1Edit.Text;
    2 : FCurPatientInfo.ConfidentalAddressLine1 := AddressLine1Edit.Text;
  end;  {case}
end;

procedure TfrmPtDemoEdit.AddressLine2EditChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    0 : FCurPatientInfo.AddressLine2 := AddressLine2Edit.Text;
    1 : FCurPatientInfo.TempAddressLine2 := AddressLine2Edit.Text;
    2 : FCurPatientInfo.ConfidentalAddressLine2 := AddressLine2Edit.Text;
  end;  {case}
end;

procedure TfrmPtDemoEdit.AddressLine3EditChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    0 : FCurPatientInfo.AddressLine3 := AddressLine3Edit.Text;
    1 : FCurPatientInfo.TempAddressLine3 := AddressLine3Edit.Text;
    2 : FCurPatientInfo.ConfidentalAddressLine3 := AddressLine3Edit.Text;
  end;  {case}
end;

procedure TfrmPtDemoEdit.CityEditChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    0 : FCurPatientInfo.City  := CityEdit.Text;
    1 : FCurPatientInfo.TempCity := CityEdit.Text;
    2 : FCurPatientInfo.ConfidentalCity := CityEdit.Text;
  end;  {case}
end;

procedure TfrmPtDemoEdit.Zip4EditChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    0 : FCurPatientInfo.Zip4   := Zip4Edit.Text;
    1 : FCurPatientInfo.TempZip4 := Zip4Edit.Text;
    2 : FCurPatientInfo.ConfidentalZip := leftstr(Zip4Edit.Text,5);
  end;  {case}
end;

procedure TfrmPtDemoEdit.StateComboBoxChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    0 : FCurPatientInfo.State := StateComboBox.Text;
    1 : FCurPatientInfo.TempState := StateComboBox.Text;
    2 : FCurPatientInfo.ConfidentalState := StateComboBox.Text;
  end;  {case}
end;

procedure TfrmPtDemoEdit.TempActiveCBClick(Sender: TObject);
begin 
  FCurPatientInfo.TempAddressActive := BoolUC(TempActiveCB.Checked); 
  if ProgAddressChangeOccuring = false then SetModified(true);
end;

procedure TfrmPtDemoEdit.ConfActiveCBClick(Sender: TObject);
begin 
  FCurPatientInfo.ConfAddressActive := BoolUC(ConfActiveCB.Checked); 
  if ProgAddressChangeOccuring = false then SetModified(true);
end;

procedure TfrmPtDemoEdit.BadAddressCBClick(Sender: TObject);
begin 
  FCurPatientInfo.BadAddress := BoolUC(BadAddressCB.Checked); 
  if ProgAddressChangeOccuring = false then SetModified(true);
end;

procedure TfrmPtDemoEdit.PhoneNumEditChange(Sender: TObject);
begin
  if ProgPhoneChangeOccuring = false then SetModified(true);
  Case PhoneNumGrp.ItemIndex of
    0 : FCurPatientInfo.PhoneNumResidence  := PhoneNumEdit.Text;
    1 : FCurPatientInfo.PhoneNumWork := PhoneNumEdit.Text;
    2 : FCurPatientInfo.PhoneNumCell := PhoneNumEdit.Text;
    3 : FCurPatientInfo.PhoneNumTemp := PhoneNumEdit.Text;
  end;  {case}

end;

procedure TfrmPtDemoEdit.StartingDateEditChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    1 : FCurPatientInfo.TempStartingDate := StartingDateEdit.Text;
    2 : FCurPatientInfo.ConfidentalStartingDate := StartingDateEdit.Text;
  end;  {case}
end;

procedure TfrmPtDemoEdit.EndingDateEditChange(Sender: TObject);
begin
  if ProgAddressChangeOccuring = false then SetModified(true);
  Case AddressRGrp.ItemIndex of
    1 : FCurPatientInfo.TempEndingDate := EndingDateEdit.Text;
    2 : FCurPatientInfo.ConfidentalEndingDate := EndingDateEdit.Text;
  end;  {case}
end;

procedure TfrmPtDemoEdit.AliasNameEditChange(Sender: TObject);
var i : integer;
    pAlias : tAlias;
    tempB : boolean;
begin
  if ProgAliasChangeOccuring=false then begin
    i := AliasComboBox.ItemIndex;
    if i > -1 then begin
      pAlias := tAlias(AliasComboBox.Items.Objects[i]);
      if pAlias<>nil then begin
        pAlias.Name := AliasNameEdit.Text;
        AliasComboBox.Items.Strings[i]:= AliasNameEdit.Text;
        AliasComboBox.Text := AliasNameEdit.Text;
        tempB := ProgAliasChangeOccuring;
        ProgAliasChangeOccuring:=true;
        AliasComboBox.ItemIndex := i;
        ProgAliasChangeOccuring:=tempB;
        SetModified(true);
      end;
    end;
  end;  
end;


procedure TfrmPtDemoEdit.AliasSSNEditChange(Sender: TObject);
var i : integer;
    pAlias : tAlias;
begin
  if ProgAliasChangeOccuring=false then begin
    i := AliasComboBox.ItemIndex;
    if i > -1 then begin
      pAlias := tAlias(AliasComboBox.Items.Objects[i]);
      if pAlias<>nil then begin
        pAlias.SSN := AliasSSNEdit.Text;      
        SetModified(true);
      end;
    end;
  end;  
end;

procedure TfrmPtDemoEdit.SetAliasEnabled(value : boolean);
begin
  AliasNameEdit.Enabled := value;
  AliasSSNEdit.Enabled := value;
  if value=true then begin
    AliasNameEdit.Color := clWindow;
    AliasSSNEdit.Color := clWindow;
  end else begin
    AliasNameEdit.Color := clInactiveBorder;
    AliasSSNEdit.Color := clInactiveBorder;
  end;
end;


function TfrmPtDemoEdit.CombinedName : string;
begin
  Result := '';
  Result := FNameEdit.Text;
  if MNameEdit.Text <> '' then Result := Result + ' ' + MNameEdit.Text;
  if SuffixEdit.Text <> '' then Result := Result + ' ' + SuffixEdit.Text;
  if Result <> '' then Result := ',' + Result;
  Result := LNameEdit.Text + Result;
end;

procedure TfrmPtDemoEdit.NameParts(CombinedName: string; var LName, FName, MName : string);
var tempS : string;
begin
  LName := piece(CombinedName,',',1);
  tempS := piece(CombinedName,',',2);
  FName := piece(tempS,' ',1);
  MName := piece(tempS,' ',2,16);
end;


procedure TfrmPtDemoEdit.ApplyBtnClick(Sender: TObject);
var TempPatientInfo : tPatientInfo;
begin
if pagecontrol.ActivePageIndex = 0 then begin
  TempPatientInfo := tPatientInfo.Create;
  TempPatientInfo.Assign(FCurPatientInfo);
  TempPatientInfo.RemoveUnchanged(FServerPatientInfo);
  PostChangedInfo(TempPatientInfo);
  TempPatientInfo.Destroy;
  SetModified(false);
end else begin
  PostVisibleGrid;
  SetModified(false);
end;
end;
function TfrmPtDemoEdit.PostVisibleGrid: TModalResult;
  begin
    result := PostChanges(gridPatientDemo);
  end;

function TfrmPtDemoEdit.PostChanges(Grid : TSortStringGrid) : TModalResult;
  //Results:  mrNone -- no post done (not needed)
  //          mrCancel -- user pressed cancel on confirmation screen.
  //          mrNo -- signals posting error.
  var Changes : TStringList;
      PostResult : TModalResult;
      CurrentData : TStringList;
      GridInfo : TGridInfo;
      IENS : string;  
  begin
    Result := mrNone;  //default to No changes
    GridInfo := GetInfoForGrid(Grid);
    if GridInfo=nil then exit;
    CurrentData := GridInfo.Data;
    if CurrentData=nil then exit;
    if CurrentData.Count = 0 then exit;
    IENS := Patient.DFN;
    if IENS='' then exit;
    Changes := TStringList.Create;
    CompileChanges(Grid,CurrentData,Changes);
    if Changes.Count>0 then begin
      PostForm.PrepForm(Changes);
      PostResult := PostForm.ShowModal;
      if PostResult = mrOK then begin
        //if DisuserChanged(Changes) then begin  //looks for change in file 200, field 4
        //  InitializeUsersTreeView;
        //end else begin
          if Pos('+',IENS)>0 then begin
            GridInfo.IENS := PostForm.GetNewIENS(IENS);
          end;
          if assigned(GridInfo.DataLoadProc) then begin
            GridInfo.DataLoadProc(GridInfo);
          end;
          {
          if CurrentData = CurrentUserData then begin
            LoadUserData(IENS,CurrentData);  //reload record from server.
          end else if CurrentData = CurrentSettingsData then begin
            GetSettingsInfo(GridInfo.FileNum, GridInfo.IENS, CurrentData);
          end else if CurrentData = CurrentPatientData then begin
            GetPatientInfo(GridInfo.IENS, CurrentData);            
          end else if CurrentData = CurrentAnyFileData then begin
            GetAnyFileInfo(GridInfo.FileNum, GridInfo.IENS, CurrentData);
          end;  
          }
        //end;  
      end else if PostResult = mrNo then begin  //mrNo is signal of post Error
        // show error...
      end;
      Result := PostResult;
    end else begin
      Result := mrNone;  
    end;
    Changes.Free;
  end;

  procedure TfrmPtDemoEdit.CompileChanges(Grid : TSortStringGrid; CurrentUserData,Changes : TStringList);
  //Output format:
  // FileNum^IENS^FieldNum^FieldName^newValue^oldValue

  var row : integer;
      Entry : tFileEntry;
      oneEntry : string;
  begin
    for row := 1 to Grid.RowCount-1 do begin
      Entry := GetLineInfo(Grid,CurrentUserData, row);
      if Entry.oldValue <> Entry.newValue then begin
        if (Entry.newValue <> CLICK_FOR_SUBS) and
          (Entry.newValue <> COMPUTED_FIELD) and
          (Entry.newValue <> CLICK_TO_EDIT) then begin   
          oneEntry := Entry.FileNum + '^' + Entry.IENS + '^' + Entry.Field + '^' + Entry.FieldName;
          oneEntry := oneEntry + '^' + Entry.newValue + '^' + Entry.oldValue;
          Changes.Add(oneEntry);
        end;  
      end;
    end;
  end;

procedure TfrmPtDemoEdit.SetModified(value : boolean);
begin
  FCurPatientInfo.Modified := value;
  ApplyBtn.Enabled := FCurPatientInfo.Modified;
end;

procedure TfrmPtDemoEdit.AddAliasBtnClick(Sender: TObject);
var pAlias : tAlias;
    IEN : string;
begin
    pAlias := tAlias.Create;
    if FCurPatientInfo.AliasInfo.count>0 then begin
      IEN := FCurPatientInfo.AliasInfo.Strings[FCurPatientInfo.AliasInfo.count-1];
    end else begin
      IEN := IntToStr(MaxAliasIEN);
    end;  
    MaxAliasIEN := StrToInt(IEN)+1;
    IEN := IntToStr(MaxAliasIEN);
    FCurPatientInfo.AliasInfo.AddObject(IEN,pAlias);
    SetModified(true);
    AliasCombobox.Items.AddObject('<Edit New Alias>',pAlias);
    //pAlias.Name := '<Edit New Alias>';
    //AliasCombobox.Items.Add(ADD_NEW_ALIAS);
    AliasCombobox.ItemIndex := AliasCombobox.Items.Count-1;    
    SetAliasEnabled(true);
    ShowAliasInfo(FCurPatientInfo);
end;

procedure TfrmPtDemoEdit.OKBtnClick(Sender: TObject);
begin
  if FCurPatientInfo.Modified = true then begin
    case MessageDlg('Apply Changes?',mtConfirmation,mbYesNoCancel,0) of
      mrYes : begin
                ApplyBtnClick(Sender);
                frmPtDemoEdit.ModalResult := mrOK;  //closes form
              end;
      mrNo : begin
               if ChangesMade = false then frmPtDemoEdit.ModalResult := mrCancel // closes form, signal no need for refresh
               else frmPtDemoEdit.ModalResult := mrOK; // closes form.
             end;  
      mrCancel :  frmPtDemoEdit.ModalResult := mrNone; //do nothing
    end; {case}  
  end else begin
    if ChangesMade = false then frmPtDemoEdit.ModalResult := mrCancel // closes form, signal no need for refresh
    else frmPtDemoEdit.ModalResult := mrOK; // closes form.
  end;  
end;

procedure TfrmPtDemoEdit.CancelBtnClick(Sender: TObject);
begin
  if FCurPatientInfo.Modified = true then begin
    case MessageDlg('Cancel Changes?',mtConfirmation,mbYesNoCancel,0) of
      mrYes : frmPtDemoEdit.ModalResult := mrCancel;  //closes form                                        
      mrNo : frmPtDemoEdit.ModalResult := mrNone;  //do nothing
      mrCancel :  frmPtDemoEdit.ModalResult := mrNone; //do nothing
    end; {case}  
  end else begin
    frmPtDemoEdit.ModalResult := mrCancel; // closes form.
  end;  

end;


procedure TfrmPtDemoEdit.PageControlChange(Sender: TObject);
var
   GridInfo : TGridInfo;
   IEN : longInt;
   ModalResult : TModalResult;

begin
    if pagecontrol.ActivePageIndex = 0 then begin
       GetPtInfo(FServerPatientInfo);
       FCurPatientInfo.Assign(FServerPatientInfo);
       ShowPtInfo(FCurPatientInfo);
    end else begin
       IEN := strtoint(patient.dfn);  //get info from selected patient
       if IEN = 0 then exit;
       GridInfo := GetInfoForGrid(gridPatientDemo);
       if GridInfo = nil then exit;
       GridInfo.IENS := IntToStr(IEN)+',';
       GetPatientInfo(GridInfo);
    end;

end;

procedure TfrmPtDemoEdit.GetPatientInfo(GridInfo: TGridInfo);

var cmd,RPCResult : string;
    IENS : String;
    grid : TSortStringGrid;
begin
//    IENS := Patient.DFN;
    IENS := GridInfo.IENS;
//    Data := GridInfo.Data;
    grid := GridInfo.Grid;
    grid.Cells[0,1] := '';
    grid.Cells[1,1] := '';
    grid.Cells[2,1] := '';
    grid.RowCount :=2;
    grid.Cursor := crHourGlass;
    if IENS <> '0,' then begin
      RPCBrokerV.remoteprocedure := 'TMG CHANNEL';
      RPCBrokerV.param[0].ptype := list;
      cmd := 'GET ONE RECORD^2^' + IENS;
      RPCBrokerV.Param[0].Mult['"REQUEST"'] := cmd;
      //RPCBrokerV.Call;
      CallBroker;
      RPCResult := RPCBrokerV.Results[0];    //returns:  error: -1;  success=1
      //Results[1]='FileNum^IENS^FieldNum^ExtValue^FieldName^DDInfo...
      //Results[2]='FileNum^IENS^FieldNum^ExtValue^FieldName^DDInfo...
      if piece(RPCResult,'^',1)='-1' then begin
        messagedlg(RPCBrokerV.Results[1],mtError,mbOKCancel,0);
        //FMErrorForm.Memo.Lines.Assign(RPCBrokerV.Results);
      end else begin
        GridInfo.Data.Assign(RPCBrokerV.results);
        //LoadAnyGrid(grid,false,'2',IENS,Data);
        LoadAnyGridFromInfo(GridInfo);
      end;
    end;
  gridPatientDemo.Cursor := crDefault;
end;

procedure TfrmPtDemoEdit.LoadAnyGrid(Grid : TSortStringGrid;  //the TSortStringGrid to load
                                     BasicMode: boolean;
                                     FileNum : string;
                                     IENS : string;
                                     CurrentData : TStringList);
  var
    GridInfo : TGridInfo;
  begin
    GridInfo := TGridInfo.Create;
    //This stores load information into a GridInfo
    GridInfo.Grid := Grid;
    GridInfo.BasicMode := BasicMode;
    GridInfo.FileNum := FileNum;
    GridInfo.IENS := IENS;
    GridInfo.Data := CurrentData;
    LoadAnyGridFromInfo(GridInfo);
    GridInfo.Free;
  end;

procedure TfrmPtDemoEdit.LoadAnyGridFromInfo(GridInfo : TGridInfo);
  //This assumes that GridInfo already has loaded info.
  var
    Grid : TSortStringGrid;  //the TSortStringGrid to load
    BasicMode: boolean;
    FileNum : string;
    IENS : string;
    CurrentData : TStringList;

    procedure LoadOneLine (Grid : TSortStringGrid; oneEntry : string; GridRow : integer);
    var
      tempFile,IENS : string;
      fieldNum,fieldName,fieldDef : string;
      subFileNum : string;
      value : string;
    begin
      tempFile := Piece(oneEntry,'^',1);
      if tempFile = FileNum then begin //handle subfiles later...
        IENS := Piece(oneEntry,'^',2);
        fieldNum := Piece(oneEntry,'^',3);
        value := Piece(oneEntry,'^',4);
        fieldName := Piece(oneEntry,'^',5);
        fieldDef := Piece(oneEntry,'^',6);
        Grid.RowCount := GridRow + 1;
        Grid.Cells[0,GridRow] := fieldNum;
        Grid.Cells[1,GridRow] := fieldName;
        if Pos('W',fieldDef)>0 then begin
          Grid.Cells[2,GridRow] := CLICK_TO_EDIT;
        end else if IsSubFile(fieldDef, subFileNum) then begin
          if IsWPField(FileNum,fieldNum) then begin
            Grid.Cells[2,GridRow] := CLICK_TO_EDIT;
          end else begin
            Grid.Cells[2,GridRow] := CLICK_FOR_SUBS;
          end;
        end else if Pos('C',fieldDef)>0 then begin
          Grid.Cells[2,GridRow] := COMPUTED_FIELD;
        end else begin
          Grid.Cells[2,GridRow] := value;
        end;
        Grid.RowHeights[GridRow] := DEF_GRID_ROW_HEIGHT;
      end;
    end;

    function getOneLine(CurrentData : TStringList; oneFileNum,oneFieldNum : string) : string;
    var i : integer;
        FileNum,FieldNum : string;
    begin
      result := '';
      // FileNum^IENS^FieldNum^FieldName^newValue^oldValue
      for i := 1 to CurrentData.Count - 1 do begin
        FileNum := piece(CurrentData.Strings[i],'^',1);
        if FileNum <> oneFileNum then continue;
        FieldNum := piece(CurrentData.Strings[i],'^',3);
        if FieldNum <> oneFieldNum then continue;
        result := CurrentData.Strings[i];
        break;
      end;
    end;

  var i : integer;
      oneEntry  : string;
      oneFileNum,oneFieldNum : string;
      gridRow : integer;

  begin
    FLoadingGrid := true;
    if GridInfo=nil then exit;
    Grid := GridInfo.Grid;
    BasicMode := GridInfo.BasicMode;
    FileNum := GridInfo.FileNum;
    IENS := GridInfo.IENS;
    CurrentData := GridInfo.Data;

    Grid.Cells[0,1] := '';
    Grid.Cells[1,1] := '';
    Grid.Cells[2,1] := '';
    Grid.RowCount :=2;
    Grid.ColWidths[0] := 50;
    Grid.ColWidths[1] := 200;
    Grid.ColWidths[2] := 300;
    Grid.Cells[0,0] := '#';
    Grid.Cells[1,0] := 'Name';
    Grid.Cells[2,0] := 'Value';

    if BasicMode=false then begin
      for i := 1 to CurrentData.Count-1 do begin  //start at 1 because [0] = 1^Success
        oneEntry := CurrentData.Strings[i];
        LoadOneLine (Grid,oneEntry,i);
      end;
    end else if BasicMode=true then begin
      gridRow := 1;
      for i := 0 to BasicTemplate.Count-1 do begin
        oneFileNum := Piece(BasicTemplate.Strings[i],'^',1);
        if oneFileNum <> fileNum then continue;
        oneFieldNum := Piece(BasicTemplate.Strings[i],'^',2);
        oneEntry := getOneLine(CurrentData,oneFileNum,oneFieldNum);
        LoadOneLine (Grid,oneEntry,gridRow);
        Inc(GridRow);
      end;
    end;
    FLoadingGrid := false;
  end;

  function TfrmPtDemoEdit.GetInfoForGrid(Grid : TSortStringGrid) : TGridInfo;
  var i : integer;
  begin
    i := GetInfoIndexForGrid(Grid);
    if i > -1 then begin
      result := TGridInfo(DataForGrid.Objects[i]);
    end else begin
      result := nil;
    end;
  end;


  function TfrmPtDemoEdit.GetInfoIndexForGrid(Grid : TSortStringGrid) : integer;
  var s : string;
  begin
    s := IntToStr(integer(Grid));
    result := Dataforgrid.indexof(s);
  end;

function TfrmPtDemoEdit.IsSubFile(FieldDef: string ; var SubFileNum : string) : boolean;
  //SubFileNum is OUT parameter
  begin
    SubFileNum := ExtractNum(FieldDef,1);
    result := (SubFileNum <> '');
  end;
    
  function TfrmPtDemoEdit.IsWPField(FileNum,FieldNum : string) : boolean;
  var RPCResult : string;
      SrchStr : string;
      Idx: integer;
  begin
    SrchStr := FileNum + '^' +  FieldNum + '^';
    //Idx := CachedWPField.IndexOf(SrchStr + 'YES');
    //if Idx > -1 then begin Result := true; exit; end;
    //Idx := CachedWPField.IndexOf(SrchStr + 'NO');
    //if Idx > -1 then begin Result := false; exit; end;
  
    result := false;
    RPCBrokerV.remoteprocedure := 'TMG CHANNEL';
    RPCBrokerV.param[0].ptype := list;
    RPCBrokerV.Param[0].Mult['"REQUEST"'] := 'IS WP FIELD^' + FileNum + '^' + FieldNum;
    //RPCBrokerV.Call;
    CallBroker;
    RPCResult := RPCBrokerV.Results[0];    //returns:  error: -1;  success=1
    if piece(RPCResult,'^',1)='-1' then begin
      //FMErrorForm.Memo.Lines.Assign(RPCBrokerV.Results);
      //FMErrorForm.PrepMessage;
      //FMErrorForm.ShowModal;
    end else begin
      RPCResult := piece(RPCResult,'^',3);
      result := (RPCResult = 'YES');
      //CachedWPField.Add(SrchStr + RPCResult);
    end;    
  end;

  function TfrmPtDemoEdit.ExtractNum (S : String; StartPos : integer) : string;
  var i : integer;
      ch : char;
  begin
    result := '';
    if (S = '') or (StartPos < 0) then exit;
    i := StartPos;
    repeat
      ch := S[i]; 
      i := i + 1;
      if ch in ['0'..'9','.'] then begin
        Result := Result + ch;
      end;  
    until (i > length(S)) or not  (ch in ['0'..'9','.'])
  end;

  procedure TfrmPtDemoEdit.gridPatientDemoSelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
    (*
    For Field def, here is the legend
    character     meaning

    BC 	          The data is Boolean Computed (true or false).
    C 	          The data is Computed.
    Cm 	          The data is multiline Computed.
    DC 	          The data is Date-valued, Computed.
    D 	          The data is Date-valued.
    F 	          The data is Free text.
    I 	          The data is uneditable.
    Pn 	          The data is a Pointer reference to file "n".
    S 	          The data is from a discrete Set of codes.
    
    N 	          The data is Numeric-valued.
    
    Jn 	          To specify a print length of n characters.
    Jn,d 	        To specify printing n characters with decimals.

    V 	          The data is a Variable pointer.
    W 	          The data is Word processing.
    WL 	          The Word processing data is normally printed in Line mode (i.e., without word wrap).
      *)
  var oneEntry,FieldDef : string;                                     
      date,time: string;
      FileNum,FieldNum,SubFileNum : string;
      GridFileNum : string;
      UserLine : integer;
      Grid : TSortStringGrid;
      IEN : int64;
      IENS : string;
      CurrentData : TStringList;
      GridInfo : TGridInfo;
      SubFileForm : TSubFileForm;
  begin
    if FLoadingGrid then exit;  //prevent pseudo-clicks during loading...
    Grid := (Sender as TSortStringGrid);
    GridInfo := GetInfoForGrid(Grid);
    if GridInfo=nil then exit;
    GridFileNum := GridInfo.FileNum;
    CanSelect := false;  //default to NOT selectable.
    CurrentData := GridInfo.Data;
    if CurrentData=nil then exit;
    if CurrentData.Count = 0 then exit;
    UserLine := GetUserLine(CurrentData,Grid,ARow);
    if UserLine = -1 then exit;
    oneEntry := CurrentData.Strings[UserLine];
    FieldDef := Piece(oneEntry,'^',6);
    if Pos('F',FieldDef)>0 then begin  //Free text
      CanSelect := true;
    end else if IsSubFile(FieldDef,SubFileNum) then begin  //Subfiles.
      FileNum :=  Piece(oneEntry,'^',1);
      FieldNum :=  Piece(oneEntry,'^',3);
      if IsWPField(FileNum,FieldNum) then begin
        IENS :=  Piece(oneEntry,'^',2);
        EditTextForm.PrepForm(FileNum,FieldNum,IENS);
        EditTextForm.ShowModal;
      end else begin
        //handle subfiles here
        IENS := '';
        if GridInfo.Message = MSG_SUB_FILE then begin  //used message from subfile Grid
          IENS := GridInfo.IENS;
        end; // else if LastSelTreeNode <> nil then begin  //this is one of the selction trees.
          IEN := strtoint(Patient.DFN); //longInt(LastSelTreeNode.Data);
          if IEN > 0 then IENS := InttoStr(IEN) + ',';
        if GridInfo.Data = CurrentAnyFileData then begin
          IEN := strtoint(patient.dfn);  //get info from selected record
          if IEN > 0 then IENS := InttoStr(IEN) + ',';
        end;
        if IENS <> '' then begin
          SubFileForm := TSubFileForm.Create(self);
          SubFileForm.PrepForm(SubFileNum,IENS);
          SubfileForm.ShowModal;  // note: may call this function again recursively for sub-sub-files etc.
          SubFileForm.Free;
        end else begin
          MessageDlg('IENS for File="".  Can''t process.',mtInformation,[MBOK],0);
        end;
      end;
    end else if Pos('C',FieldDef)>0 then begin  //computed fields.
      CanSelect := false;
    end else if Pos('D',FieldDef)>0 then begin  //date field
      date := piece(Grid.Cells[ACol,ARow],'@',1);
      time := piece(Grid.Cells[ACol,ARow],'@',2);
      if date <> '' then begin
        SelDateTimeForm.DateTimePicker.Date := StrToDate(date);
      end else begin
        SelDateTimeForm.DateTimePicker.Date := SysUtils.Date;
      end;
      if SelDateTimeForm.ShowModal = mrOK then begin
        date := DateToStr(SelDateTimeForm.DateTimePicker.Date);
        time := TimeToStr(SelDateTimeForm.DateTimePicker.Time);
        if time <> '' then date := date; // + '@' + time;    elh 8/15/08
        Grid.Cells[ACol,ARow] := date;
      end;
      CanSelect := true;
    end else if Pos('S',FieldDef)>0 then begin  //Set of Codes
      SetSelForm.PrepForm(Piece(oneEntry,'^',7));
      if SetSelForm.ShowModal = mrOK then begin
        Grid.Cells[ACol,ARow] := SetSelForm.ComboBox.Text;
        CanSelect := true;
      end;
    end else if Pos('I',FieldDef)>0 then begin  //uneditable
      ShowMessage('Sorry. Flagged as UNEDITABLE.');
    end else if Pos('P',FieldDef)>0 then begin  //Pointer to file.
      FileNum := ExtractNum (FieldDef,Pos('P',FieldDef)+1);
      //check for validity here...
      FieldLookupForm.PrepForm(FileNum,Grid.Cells[ACol,ARow]);
      if FieldLookupForm.ShowModal = mrOK then begin
        Grid.Cells[ACol,ARow] := FieldLookupForm.ORComboBox.Text;
        CanSelect := true;
      end;
    end;
    if CanSelect then begin
      FLastSelectedRow := ARow;
      FLastSelectedCol := ACol;
      SetModified(True);
    end;
    //GridInfo.ApplyBtn.Enabled := true;
    //GridInfo.RevertBtn.Enabled := true;
  end;

  function TfrmPtDemoEdit.GetLineInfo(Grid : TSortStringGrid; CurrentUserData : TStringList; ARow: integer) : tFileEntry;
  var fieldNum : string;
      oneEntry : string;
      fileNum : string;
      gridRow : integer;
  begin
    fieldNum := Grid.Cells[0,ARow];
    gridRow := FindInStrings(fieldNum, CurrentUserData, fileNum);
    if gridRow > -1 then begin
      oneEntry := CurrentUserData.Strings[gridRow];
      Result.Field := fieldNum;
      Result.FieldName := Grid.Cells[1,ARow];
      Result.FileNum := fileNum;
      Result.IENS := Piece(oneEntry,'^',2);
      Result.oldValue := Piece(oneEntry,'^',4);
      Result.newValue := Grid.Cells[2,ARow];
    end else begin
      Result.Field := '';
      Result.FieldName := '';
      Result.FileNum := '';
      Result.IENS := '';
      Result.oldValue := '';
      Result.newValue := '';
    end;
  end;

procedure TfrmPtDemoEdit.GetOneRecord(FileNum, IENS : string; Data, BlankFileInfo: TStringList);
  var cmd,RPCResult : string;
      i : integer;
      oneEntry : string;
  begin
    Data.Clear;
    if (IENS='') then exit;
    if Pos('+',IENS)=0 then begin //don't ask server to load +1 records.
      RPCBrokerV.remoteprocedure := 'TMG CHANNEL';
      RPCBrokerV.Param[0].Value := '.X';  // not used
      RPCBrokerV.param[0].ptype := list;
      cmd := 'GET ONE RECORD^' + FileNum + '^' + IENS;
      RPCBrokerV.Param[0].Mult['"REQUEST"'] := cmd;
      //RPCBrokerV.Call;
      CallBroker;
      RPCResult := RPCBrokerV.Results[0];    //returns:  error: -1;  success=1
      if piece(RPCResult,'^',1)='-1' then begin
      FMErrorForm.Memo.Lines.Assign(RPCBrokerV.Results);
      FMErrorForm.PrepMessage;
      FMErrorForm.ShowModal;
      end else begin
        Data.Assign(RPCBrokerV.Results);
      end;
    end else begin
      Data.Add('1^Success');  //to keep same as call to server
      if BlankFileInfo.Count = 0 then begin
        //Format is: FileNum^^FieldNum^^DDInfo...
        //  elh GetBlankFileInfo(FileNum,BlankFileInfo);
      end;  
      for i := 1 to BlankFileInfo.Count-1 do begin  //0 is 1^success
        oneEntry := BlankFileInfo.Strings[i];
        //  elh SetPiece(oneEntry,'^',2,IENS);
        Data.Add(oneEntry);
      end;
    end;
  end;

function TfrmPtDemoEdit.GetUserLine(CurrentUserData : TStringList; Grid : TSortStringGrid; ARow: integer) : integer;
  var fieldNum: string;
      tempFileNum : string;
  begin
    fieldNum := Grid.Cells[0,ARow];
    Result := FindInStrings(fieldNum,CurrentUserData,tempFileNum);
  end;

  function TfrmPtDemoEdit.FindInStrings(fieldNum : string; Strings : TStringList; var fileNum : string) : integer;
  //Note: if fileNum is passed blank, then first matching file will be placed in it (i.e. OUT parameter)
  var tempFieldNum : string;
      oneEntry,tempFile : string;
      i : integer;
  begin
    result := -1;
    fileNum := '';
    for i := 1 to Strings.Count-1 do begin   //0 --> 1^success
      oneEntry := Strings.Strings[i];
      tempFile := Piece(oneEntry,'^',1);
      if fileNum='' then fileNum := tempFile;
      if tempFile <> fileNum then continue; //ignore subfiles
      tempFieldNum := Piece(oneEntry,'^',3);
      if tempFieldNum <> fieldNum then continue;
      Result := i;
      break;
    end;
  end;

 procedure TfrmPtDemoEdit.AddGridInfo(Grid: TSortStringGrid;
                                  Data : TStringList;
                                  BasicMode : boolean;
                                  DataLoader : TGridDataLoader;
                                  FileNum : string);
  var tempGridInfo : TGridInfo;
  begin
    tempGridInfo := TGridInfo.Create;
    tempGridInfo.Grid := Grid;
    tempGridInfo.Data := Data;
    tempGridInfo.BasicMode := BasicMode;
    tempGridInfo.FileNum := FileNum;
    tempGridInfo.DataLoadProc := DataLoader;
    //tempGridInfo.ApplyBtn := ApplyBtn;
    //tempGridInfo.RevertBtn := RevertBtn;
    RegisterGridInfo(tempGridInfo);
  end;

procedure TfrmPtDemoEdit.RegisterGridInfo(GridInfo : TGridInfo);
  var s : string;
  begin
    if GridInfo = nil then exit;
    s := IntToStr(integer(GridInfo.Grid));
    DataForGrid.AddObject(s,GridInfo);
  end;

procedure TfrmPtDemoEdit.gridPatientDemoSetEditText(Sender: TObject; ACol,
                                            ARow: Integer; const Value: String);
begin
  SetModified(True);
end;

procedure TfrmPtDemoEdit.PageControlChanging(Sender: TObject;
  var AllowChange: Boolean);
var
   intAnswer : Integer;
begin
//Before changing the form, find out if changes need to be applied and
//prompt user.            elh
    if ApplyBtn.enabled = True then begin
       intAnswer := messagedlg('Do you want to apply your changes?', mtWarning,mbYesNoCancel,0);
       if intAnswer = mrYes then begin  //Yes
          ApplyBtnClick(Sender);
          //messagedlg('Changes Saved.', mtWarning,[mbOK],0);
          SetModified(False);
        end else if intAnswer = mrNo then begin    //No
          SetModified(False);
        end else if intAnswer = mrCancel then begin    //Cancel
          AllowChange := False;
        end;
    end;
end;
end.
