unit rGroupNote;

interface

uses SysUtils, Classes, Forms, ORNet, ORFn, ORClasses, uCore;

type
  TUserInfo = record                              // record for ORWU USERINFO
    DUZ: Int64;
    Name: string;
    UserClass: Integer;
    CanSignOrders: Boolean;
    IsProvider: Boolean;
    OrderRole: Integer;
    NoOrdering: Boolean;
    DTIME: Integer;
    CountDown: Integer;
    EnableVerify: Boolean;
    NotifyAppsWM: Boolean;
    PtMsgHang: Integer;
    Domain: string;
    Service: Integer;
    AutoSave: Integer;
    InitialTab: Integer;
    UseLastTab: Boolean;
    WebAccess: Boolean;
    IsRPL: string;
    RPLList: string;
    HasCorTabs: Boolean;
    HasRptTab: Boolean;
    IsReportsOnly: Boolean;
    ToolsRptEdit: Boolean;
    DisableHold: Boolean;
    StationNumber: string;
    GECStatusCheck: Boolean;
  end;

  TPtIDInfo = record                              // record for ORWPT IDINFO
    Name: string;
    SSN: string;
    DOB: string;
    Age: string;
    Sex: string;
    SCSts: string;
    Vet: string;
    Location: string;
    RoomBed: string;
  end;

  TPtSelect = record                              // record for ORWPT SELECT
    Name: string;
    ICN: string;
    SSN: string;
    DOB: TFMDateTime;
    Age: Integer;
    Sex: Char;
    LocationIEN: Integer;
    Location: string;
    WardService: string;
    RoomBed: string;
    SpecialtyIEN: Integer;
    CWAD: string;
    Restricted: Boolean;
    AdmitTime: TFMDateTime;
    ServiceConnected: Boolean;
    SCPercent: Integer;
    PrimaryTeam: string;
    PrimaryProvider: string;
    Attending: string;
  end;

  TEncounterText = record                         // record for ORWPT ENCTITL
    LocationName: string;
    LocationAbbr: string;
    RoomBed: string;
    ProviderName: string;
  end;

function GetUserInfo: TUserInfo;
function GetPtIDInfo(const DFN: string): TPtIDInfo;  //*DFN*
function HasSecurityKey(const KeyName: string): Boolean;
function DfltPtList: string;
function MakeRPLPtList(RPLList: string): string;
procedure ListPtByDflt(Dest: TStrings);
procedure ListProviderTop(Dest: TStrings);
procedure ListClinicTop(Dest: TStrings);
procedure ListSpecialtyAll(Dest: TStrings);
procedure ListTeamAll(Dest: TStrings);
procedure ListWardAll(Dest: TStrings);

procedure ListDateRangeClinic(Dest: TStrings);
function DfltDateRangeClinic: string;

function SubSetOfProviders(const StartFrom: string; Direction: Integer): TStrings;
function SubSetOfClinics(const StartFrom: string; Direction: Integer): TStrings;

function ReadRPLPtList(RPLJobNumber: string; const StartFrom: string; Direction: Integer) : TStrings;
function SubSetOfPatients(const StartFrom: string; Direction: Integer): TStrings;

function GetDfltSort: string;
procedure ListPtByProvider(Dest: TStrings; ProviderIEN: Int64);
procedure ListPtByTeam(Dest: TStrings; TeamIEN: Integer);
procedure ListPtBySpecialty(Dest: TStrings; SpecialtyIEN: Integer);
procedure ListPtByClinic(Dest: TStrings; ClinicIEN: Integer; FirstDt, LastDt: string); //TFMDateTime);
procedure ListPtByWard(Dest: TStrings; WardIEN: Integer);
procedure ListPtByLast5(Dest: TStrings; const Last5: string);
procedure ListPtByRPLLast5(Dest: TStrings; const Last5: string);
procedure ListPtByFullSSN(Dest: TStrings; const FullSSN: string);
procedure ListPtByRPLFullSSN(Dest: TStrings; const FullSSN: string);
procedure ListPtTop(Dest: TStrings);

function FormatSSN(const x: string): string;
function IsSSN(const x: string): Boolean;
function IsFMDate(const x: string): Boolean;

function ServerVersion(const Option, VerClient: string): string;

procedure SelectPatient(const DFN: string; var PtSelect: TPtSelect);   //*DFN*
procedure CheckSensitiveRecordAccess(const DFN: string; var AccessStatus: Integer;
  var MessageText: string);
procedure LoadDemographics(Dest: TStrings; const PtDFN: string);
function DateOfDeath(const DFN: string): TFMDateTime;
function LogSensitiveRecordAccess(const DFN: string): Boolean;

function SubSetOfNewLocs(const From: string; dir: integer): TStrings;

function GetEncounterText(const DFN: string; Location: integer; Provider: Int64): TEncounterText;  //*DFN*

function FMNow: TFMDateTime;
function FMToday: TFMDateTime;
procedure CleanGNPtList;
function IsValidLocation(ALocation: integer): boolean;
function IsAuthUser: boolean;
function IsMaxICD10(Term: string): string;

implementation

var
  uFMToday: TFMDateTime; 
  uPtListDfltSort: string = '';  // Current user's patient selection list default sort order.

function GetUserInfo: TUserInfo;
{ returns a record of user information,
  Pieces: DUZ^NAME^USRCLS^CANSIGN^ISPROVIDER^ORDERROLE^NOORDER^DTIME^CNTDN^VERORD^NOTIFYAPPS^
          MSGHANG^DOMAIN^SERVICE^AUTOSAVE^INITTAB^LASTTAB^WEBACCESS^ALLOWHOLD^ISRPL^RPLLIST^
          CORTABS^RPTTAB^STATION# }
var
  x: string;
begin
  x := sCallV('ORWU USERINFO', [nil]);
  with Result do
  begin
    DUZ := StrToInt64Def(Piece(x, U, 1), 0);
    Name := Piece(x, U, 2);
    UserClass := StrToIntDef(Piece(x, U, 3), 0);
    CanSignOrders := Piece(x, U, 4) = '1';
    IsProvider := Piece(x, U, 5) = '1';
    OrderRole := StrToIntDef(Piece(x, U, 6), 0);
    NoOrdering := Piece(x, U, 7) = '1';
    DTIME := StrToIntDef(Piece(x, U, 8), 300);
    CountDown := StrToIntDef(Piece(x, U, 9), 10);
    EnableVerify := Piece(x, U, 10) = '1';
    NotifyAppsWM := Piece(x, U, 11) = '1';
    PtMsgHang := StrToIntDef(Piece(x, U, 12), 5);
    Domain := Piece(x, U, 13);
    Service := StrToIntDef(Piece(x, U, 14), 0);
    AutoSave := StrToIntDef(Piece(x, U, 15), 180);
    InitialTab := StrToIntDef(Piece(x, U, 16), 1);
    UseLastTab := Piece(x, U, 17) = '1';
    WebAccess := Piece(x, U, 18) <> '1';
    DisableHold := Piece(x, U, 19) = '1';
    IsRPL := Piece(x, U, 20);
    RPLList := Piece(x, U, 21);
    HasCorTabs := Piece(x, U, 22) = '1';
    HasRptTab := Piece(x, U, 23) = '1';
    StationNumber := Piece(x, U, 24);
    IsReportsOnly := false;
    if ((HasRptTab) and (not HasCorTabs)) then
      IsReportsOnly := true;
    // Remove next if and nested if should an "override" later be provided for RPL users,etc.:
    if HasCorTabs then
      if (IsRPL = '1') then
        begin
          IsRPL := '0'; // Hard set for now.
          IsReportsOnly := false;
        end;
    // Following hard set to TRUE per VHA mgt decision:
    ToolsRptEdit := true;
     //    x := GetUserParam('ORWT TOOLS RPT SETTINGS OFF');
     //    if x = '1' then
    //      ToolsRptEdit := false;

  GECStatusCheck := Piece(x,U,25) = '1';
  end;
end;

function GetPtIDInfo(const DFN: string): TPtIDInfo;  //*DFN*
{ returns the identifiers displayed upon patient selection
  Pieces: SSN[1]^DOB[2]^SEX[3]^VET[4]^SC%[5]^WARD[6]^RM-BED[7]^NAME[8] }
var
  x: string;
begin
  x := sCallV('ORWPT ID INFO', [DFN]);
  with Result do                                    // map string into TPtIDInfo record
  begin
    Name := MixedCase(Piece(x, U, 8));                                  // Name
    SSN  := Piece(x, U, 1);
    DOB  := Piece(x, U, 2);
    Age  := '';
    if IsSSN(SSN)    then SSN := FormatSSN(Piece(x, U, 1));                // SSN (PID)
    if IsFMDate(DOB) then DOB := FormatFMDateTimeStr('mmm dd,yyyy', DOB);  // Date of Birth
    //Age := IntToStr(CalcAge(MakeFMDateTime(Piece(x, U, 2))));            // Age
    Sex := Piece(x, U, 3);                                                 // Sex
    if Length(Sex) = 0 then Sex := 'U';
    case Sex[1] of
    'F','f': Sex := 'Female';
    'M','m': Sex := 'Male';
    else     Sex := 'Unknown';
    end;
    if Piece(x, U, 4) = 'Y' then Vet := 'Veteran' else Vet := '';       // Veteran?
    if Length(Piece(x, U, 5)) > 0                                       // % Service Connected
      then SCSts := Piece(x, U, 5) + '% Service Connected'
      else SCSts := '';
    Location := Piece(x, U, 6);                                         // Inpatient Location
    RoomBed  := Piece(x, U, 7);                                         // Inpatient Room-Bed
  end;
end;

function HasSecurityKey(const KeyName: string): Boolean;
{ returns true if the currently logged in user has a given security key }
var
  x: string;
begin
  Result := False;
  x := sCallV('ORWU HASKEY', [KeyName]);
  if x = '1' then Result := True;
end;

function DfltPtList: string;
{ returns the name of the current user's default patient list, null if none is defined
  Pieces: Ptr to Source File^Source Name^Source Type }
begin
  Result := sCallV('ORQPT DEFAULT LIST SOURCE', [nil]);
  if Length(Result) > 0 then Result := Pieces(Result, U, 2, 3);
end;

function MakeRPLPtList(RPLList: string): string;
{ Creates "RPL" Restricted Patient List based on Team List info in user's record. }
begin
  result := sCallV('ORQPT MAKE RPL', [RPLList]);
end;

procedure ListPtByDflt(Dest: TStrings);
{ loads the default patient list into Dest, Pieces: DFN^PATIENT NAME, ETC. }
var
  i, SourceType: Integer;
  ATime, APlace, Sort, Source, x: string;
  tmplst: TORStringList;
begin
  Sort := GetDfltSort();
  tmplst := TORStringList.Create;
  try
    tCallV(tmplst, 'ORQPT DEFAULT PATIENT LIST', [nil]);
    Source := sCallV('ORWPT DFLTSRC', [nil]);
    if Source = 'C' then                    // Clinics.
    begin
      if Sort = 'P' then                    // "Appointments" sort.
        SortByPiece(tmplst, U, 4)
      else
        SortByPiece(tmplst, U, 2);
      for i := 0 to tmplst.Count - 1 do
      begin
        x := tmplst[i];
        ATime := Piece(x, U, 4);
        APlace := Piece(x, U, 3);
        ATime := FormatFMDateTime('hh:nn  mmm dd, yyyy', MakeFMDateTime(ATime));
        SetPiece(x, U, 3, ATime);
        x := x + U + APlace;
        tmplst[i] := x;
      end;
    end
    else
    begin
      SourceType := 0;                      // Default.
      if Source = 'M' then SourceType := 1; // Combinations.
      if Source = 'W' then SourceType := 2; // Wards.
      case SourceType of
        1 : if Sort = 'S' then tmplst.SortByPieces([3, 8, 2]) // "Source" sort.
            else if Sort = 'P' then tmplst.SortByPieces([8, 2]) // "Appointment" sort.
                 else if Sort = 'T' then SortByPiece(tmplst, U, 5) // "Terminal Digit" sort.
                      else SortByPiece(tmplst, U, 2); // "Alphabetical" (also the default) sort.
        2 : if Sort = 'R' then tmplst.SortByPieces([3, 2])
            else SortByPiece(tmplst, U, 2);
      else SortByPiece(tmplst, U, 2);
      end;
    end;
    MixedCaseList(tmplst);
    Dest.Assign(tmplst);
  finally
    tmplst.Free;
  end;
end;

procedure ListProviderTop(Dest: TStrings);
{ checks parameters for list of commonly selected providers }
begin
end;

procedure ListClinicTop(Dest: TStrings);
{ checks parameters for list of commonly selected clinics }
begin
end;

procedure ListDateRangeClinic(Dest: TStrings);
{ returns date ranges for displaying clinic appointments in patient lookup }
begin
  CallV('ORWPT CLINRNG', [nil]);
  Dest.Assign(RPCBrokerV.Results);
end;

function DfltDateRangeClinic: string;
{ returns current default date range settings for displaying clinic appointments in patient lookup }
begin
  Result := sCallV('ORQPT DEFAULT CLINIC DATE RANG', [nil]);
end;

function SubSetOfProviders(const StartFrom: string; Direction: Integer): TStrings;
{ returns a pointer to a list of providers (for use in a long list box) -  The return value is
  a pointer to RPCBrokerV.Results, so the data must be used BEFORE the next broker call! }
begin
  CallV('ORWU NEWPERS', [StartFrom, Direction]);
//  MixedCaseList(RPCBrokerV.Results);
  Result := RPCBrokerV.Results;
end;

function SubSetOfClinics(const StartFrom: string; Direction: Integer): TStrings;
{ returns a pointer to a list of clinics (for use in a long list box) -  The return value is
  a pointer to RPCBrokerV.Results, so the data must be used BEFORE the next broker call! }
begin
  CallV('ORWU CLINLOC', [StartFrom, Direction]);
  MixedCaseList(RPCBrokerV.Results);
  Result := RPCBrokerV.Results;
end;

procedure ListSpecialtyAll(Dest: TStrings);
{ lists all treating specialties: IEN^Treating Specialty Name }
begin
  CallV('ORQPT SPECIALTIES', [nil]);
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListTeamAll(Dest: TStrings);
{ lists all patient care teams: IEN^Team Name }
begin
  CallV('ORQPT TEAMS', [nil]);
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListWardAll(Dest: TStrings);
{ lists all active inpatient wards: IEN^Ward Name }
begin
  CallV('ORQPT WARDS', [nil]);
  //MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

function ReadRPLPtList(RPLJobNumber: string; const StartFrom: string; Direction: Integer) : TStrings;
{ returns a pointer to a list of patients (for use in a long list box) -  The return value is
  a pointer to RPCBrokerV.Results, so the data must be used BEFORE the next broker call! }
begin
  CallV('ORQPT READ RPL', [RPLJobNumber, StartFrom, Direction]);
  MixedCaseList(RPCBrokerV.Results);
  Result := RPCBrokerV.Results;
end;

function SubSetOfPatients(const StartFrom: string; Direction: Integer): TStrings;
{ returns a pointer to a list of patients (for use in a long list box) -  The return value is
  a pointer to RPCBrokerV.Results, so the data must be used BEFORE the next broker call! }
begin
  CallV('ORWPT LIST ALL', [StartFrom, Direction]);
  MixedCaseList(RPCBrokerV.Results);
  Result := RPCBrokerV.Results;
end;

function GetDfltSort: string;
{ Assigns uPtLstDfltSort to user's default patient list sort order (string character).}
begin
  uPtListDfltSort := sCallV('ORQPT DEFAULT LIST SORT', [nil]);
  if uPtListDfltSort = '' then uPtListDfltSort := 'A'; // Default is always "A" for alpha.
  result := uPtListDfltSort;
end;

procedure ListPtByProvider(Dest: TStrings; ProviderIEN: Int64);
{ lists all patients associated with a given provider: DFN^Patient Name }
begin
  CallV('ORQPT PROVIDER PATIENTS', [ProviderIEN]);
  SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtByTeam(Dest: TStrings; TeamIEN: Integer);
{ lists all patients associated with a given team: DFN^Patient Name }
begin
  CallV('ORQPT TEAM PATIENTS', [TeamIEN]);
  SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtBySpecialty(Dest: TStrings; SpecialtyIEN: Integer);
{ lists all patients associated with a given specialty: DFN^Patient Name }
begin
  CallV('ORQPT SPECIALTY PATIENTS', [SpecialtyIEN]);
  SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtByClinic(Dest: TStrings; ClinicIEN: Integer; FirstDt, LastDt: string); //TFMDateTime);
{ lists all patients associated with a given clinic: DFN^Patient Name^App't }
var
  i: Integer;
  x, ATime, APlace, Sort: string;
begin
  Sort := GetDfltSort();
  CallV('ORQPT CLINIC PATIENTS', [ClinicIEN, FirstDt, LastDt]);
  with RPCBrokerV do
  begin
    if Sort = 'P' then
      SortByPiece(TStringList(Results), U, 4)
    else
      SortByPiece(TStringList(Results), U, 2);
    for i := 0 to Results.Count - 1 do
    begin
      x := Results[i];
      ATime := Piece(x, U, 4);
      APlace := Piece(x, U, 3);
      ATime := FormatFMDateTime('hh:nn  mmm dd, yyyy', MakeFMDateTime(ATime));
      SetPiece(x, U, 3, ATime);
      x := x + U + APlace;
      Results[i] := x;
    end;
    MixedCaseList(Results);
    Dest.Assign(Results);
  end;
end;

procedure ListPtByWard(Dest: TStrings; WardIEN: Integer);
{ lists all patients associated with a given ward: DFN^Patient Name^Room/Bed }
var
  Sort: string;
begin
  Sort := GetDfltSort();
  CallV('ORWPT BYWARD', [WardIEN]);
  if Sort = 'R' then
    SortByPiece(TStringList(RPCBrokerV.Results), U, 3)
  else
    SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtByLast5(Dest: TStrings; const Last5: string);
var
  i: Integer;
  x, ADate, AnSSN: string;
begin
{ Lists all patients found in the BS and BS5 xrefs that match Last5: DFN^Patient Name }
  CallV('ORWPT LAST5', [UpperCase(Last5)]);
  SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  with RPCBrokerV do for i := 0 to Results.Count - 1 do
  begin
    x := Results[i];
    ADate := Piece(x, U, 3);
    AnSSN := Piece(x, U, 4);
    if IsFMDate(ADate) then ADate := FormatFMDateTimeStr('mmm d, yyyy', ADate);
    if IsSSN(AnSSN)    then AnSSN := FormatSSN(AnSSN);
    SetPiece(x, U, 3, AnSSN + '   ' + ADate);
    Results[i] := x;
  end;
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtByRPLLast5(Dest: TStrings; const Last5: string);
var
  i: Integer;
  x, ADate, AnSSN: string;
begin
{ Lists patients from RPL list that match Last5: DFN^Patient Name }
  CallV('ORWPT LAST5 RPL', [UpperCase(Last5)]);
  SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  with RPCBrokerV do for i := 0 to Results.Count - 1 do
  begin
    x := Results[i];
    ADate := Piece(x, U, 3);
    AnSSN := Piece(x, U, 4);
    if IsFMDate(ADate) then ADate := FormatFMDateTimeStr('mmm d, yyyy', ADate);
    if IsSSN(AnSSN)    then AnSSN := FormatSSN(AnSSN);
    SetPiece(x, U, 3, AnSSN + '   ' + ADate);
    Results[i] := x;
  end;
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtByFullSSN(Dest: TStrings; const FullSSN: string);
{ lists all patients found in the SSN xref that match FullSSN: DFN^Patient Name }
var
  i: integer;
  x, ADate, AnSSN: string;
begin
  x := FullSSN;
  i := Pos('-', x);
  while i > 0 do
  begin
    x := Copy(x, 1, i-1) + Copy(x, i+1, 12);
    i := Pos('-', x);
  end;
  CallV('ORWPT FULLSSN', [UpperCase(x)]);
  SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  with RPCBrokerV do for i := 0 to Results.Count - 1 do
  begin
    x := Results[i];
    ADate := Piece(x, U, 3);
    AnSSN := Piece(x, U, 4);
    if IsFMDate(ADate) then ADate := FormatFMDateTimeStr('mmm d, yyyy', ADate);
    if IsSSN(AnSSN)    then AnSSN := FormatSSN(AnSSN);
    SetPiece(x, U, 3, AnSSN + '   ' + ADate);
    Results[i] := x;
  end;
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtByRPLFullSSN(Dest: TStrings; const FullSSN: string);
{ lists all patients found in the SSN xref that match FullSSN: DFN^Patient Name }
var
  i: integer;
  x, ADate, AnSSN: string;
begin
  x := FullSSN;
  i := Pos('-', x);
  while i > 0 do
  begin
    x := Copy(x, 1, i-1) + Copy(x, i+1, 12);
    i := Pos('-', x);
  end;
  CallV('ORWPT FULLSSN RPL', [UpperCase(x)]);
  SortByPiece(TStringList(RPCBrokerV.Results), U, 2);
  with RPCBrokerV do for i := 0 to Results.Count - 1 do
  begin
    x := Results[i];
    ADate := Piece(x, U, 3);
    AnSSN := Piece(x, U, 4);
    if IsFMDate(ADate) then ADate := FormatFMDateTimeStr('mmm d, yyyy', ADate);
    if IsSSN(AnSSN)    then AnSSN := FormatSSN(AnSSN);
    SetPiece(x, U, 3, AnSSN + '   ' + ADate);
    Results[i] := x;
  end;
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

procedure ListPtTop(Dest: TStrings);
{ currently returns the last patient selected }
begin
  CallV('ORWPT TOP', [nil]);
  MixedCaseList(RPCBrokerV.Results);
  Dest.Assign(RPCBrokerV.Results);
end;

function FormatSSN(const x: string): string;
{ places the dashes in a social security number }
begin
  if Length(x) > 8
    then Result := Copy(x,1,3) + '-' + Copy(x,4,2) + '-' + Copy(x,6,Length(x))
    else Result := x;
end;

function IsSSN(const x: string): Boolean;
var
  i: Integer;
begin
  Result := False;
  if (Length(x) < 9) or (Length(x) > 10) then Exit;
  for i := 1 to 9 do if not (x[i] in ['0'..'9']) then Exit;
  Result := True;
end;

function IsFMDate(const x: string): Boolean;
var
  i: Integer;
begin
  Result := False;
  if Length(x) <> 7 then Exit;
  for i := 1 to 7 do if not (x[i] in ['0'..'9']) then Exit;
  Result := True;
end;

function ServerVersion(const Option, VerClient: string): string;
begin
  Result := sCallV('ORWU VERSRV', [Option, VerClient]);
end;

procedure SelectPatient(const DFN: string; var PtSelect: TPtSelect);   //*DFN*
{ selects the patient (updates DISV, calls Pt Select actions) & returns key fields
  Pieces: NAME[1]^SEX[2]^DOB[3]^SSN[4]^LOCIEN[5]^LOCNAME[6]^ROOMBED[7]^CWAD[8]^SENSITIVE[9]^
          ADMITTIME[10]^CONVERTED[11]^SVCONN[12]^SC%[13]^ICN[14]^Age[15]^TreatSpec[16] }
var
  x: string;
begin
  x := sCallV('ORWPT SELECT', [DFN]);
  with PtSelect do
  begin
    Name := Piece(x, U, 1);
    ICN := Piece(x, U, 14);
    SSN := FormatSSN(Piece(x, U, 4));
    DOB := MakeFMDateTime(Piece(x, U, 3));
    Age := StrToIntDef(Piece(x, U, 15), 0);
    //Age := CalcAge(DOB, DateOfDeath(DFN));
    if Length(Piece(x, U, 2)) > 0 then Sex := Piece(x, U, 2)[1] else Sex := 'U';
    LocationIEN := StrToIntDef(Piece(x, U, 5), 0);
    Location := Piece(x, U, 6);
    RoomBed := Piece(x, U, 7);
    SpecialtyIEN := StrToIntDef(Piece(x, u, 16), 0);
    CWAD := Piece(x, U, 8);
    Restricted := Piece(x, U, 9) = '1';
    AdmitTime := MakeFMDateTime(Piece(x, U, 10));
    ServiceConnected := Piece(x, U, 12) = '1';
    SCPercent := StrToIntDef(Piece(x, U, 13), 0);
  end;
  x := sCallV('ORWPT1 PRCARE', [DFN]);
  with PtSelect do
  begin
    PrimaryTeam     := Piece(x, U, 1);
    PrimaryProvider := Piece(x, U, 2);
    if Length(Location) > 0 then
      begin
        Attending := Piece(x, U, 3);
        x := sCallV('ORWPT INPLOC', [DFN]);
        WardService := Piece(x, U, 3);
      end;
  end;
end;

function DateOfDeath(const DFN: string): TFMDateTime;
{ returns 0 or the date a patient died }
begin
  Result := MakeFMDateTime(sCallV('ORWPT DIEDON', [DFN]));
end;

procedure CheckSensitiveRecordAccess(const DFN: string; var AccessStatus: Integer;
  var MessageText: string);
begin
  CallV('DG SENSITIVE RECORD ACCESS', [DFN]);
  AccessStatus := -1;
  MessageText := '';
  with RPCBrokerV do
  begin
    if Results.Count > 0 then
    begin
      AccessStatus := StrToIntDef(Results[0], -1);
      Results.Delete(0);
      if Results.Count > 0 then MessageText := Results.Text;
    end;
  end;
end;

function LogSensitiveRecordAccess(const DFN: string): Boolean;
begin
  Result := sCallV('DG SENSITIVE RECORD BULLETIN', [DFN]) = '1';
end;

procedure LoadDemographics(Dest: TStrings; const PtDFN: string);
begin
  CallV('ORWPT PTINQ', [PtDFN]);
  Dest.Assign(RPCBrokerV.Results);
end;

function SubSetOfNewLocs(const From: string; dir: integer): TStrings;
begin
  CallV('ORWGN GNLOC', [From, dir]);
  Result := RPCBrokerV.Results;
end;

function GetEncounterText(const DFN: string; Location: integer; Provider: Int64): TEncounterText;  //*DFN*
{ returns resolved external values  Pieces: LOCNAME[1]^PROVNAME[2]^ROOMBED[3] }
var
  x: string;
begin
  x := sCallV('ORWPT ENCTITL', [DFN, Location, Provider]);
  with Result do
  begin
    LocationName := Piece(x, U, 1);
    LocationAbbr := Piece(x, U, 2);
    RoomBed      := Piece(x, U, 3);
    ProviderName := Piece(x, U, 4);
//    ProviderName := sCallV('ORWU1 NAMECVT', [Provider]);
 end;
end;

function FMNow: TFMDateTime;
{ return the current date/time in Fileman format }
var
  x: string;
begin
  x := sCallV('ORWU DT', ['NOW']);
  Result := StrToFloat(x);
end;

function FMToday: TFMDateTime;
{ return the current date in Fileman format }
begin
  if uFMToday = 0 then uFMToday := Int(FMNow);
  Result := uFMToday;
end;

procedure CleanGNPtList;
var
  i: integer;
begin
  if not Assigned(GNPtList) then Exit;
  for i := GNPtList.Count - 1 downto 0 do
  begin
    if TPatient(GNPtList.Items[i]) <> nil then
      TPatient(GNPtList.Items[i]).Free;
  end;
  if GnPtList.Count > 0 then
    GNPtList.Clear;
end;

function IsValidLocation(ALocation: integer): boolean;
begin
  Result := (SCallV('ORWGN GNLOC',[ALocation])= '1' );
end;

function IsAuthUser: boolean;
begin
  Result := ( SCAllV('ORWGN AUTHUSR',[NIL]) = '1');
end;

function IsMaxICD10(Term: string): string;
begin
  // TDP - 09/11/2012 - Returns whether search term frequency is greater
  //       than Max allowed frequency and if it is, includes frequency count.
  Result := SCallV('ORWGN MAXFRQ',[Term])
end;

end.
