unit BatchAddU;
   (* 
   WorldVistA Configuration Utility
   (c) 8/2008 Kevin Toppenberg
   Programmed by Kevin Toppenberg, Eddie Hagood  
   
   Family Physicians of Greeneville, PC
   1410 Tusculum Blvd, Suite 2600
   Greeneville, TN 37745
   kdtop@yahoo.com
                                                 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *)   

interface

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

type
  TBatchAddForm = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    BatchGrid: TStringGrid;
    btnCreateTemplate: TBitBtn;
    btnOpenDataFile: TBitBtn;
    btnDoRegistration: TBitBtn;
    btnClearGrid: TBitBtn;
    OpenDialog: TOpenDialog;
    btnDone: TBitBtn;
    ProgressBar: TProgressBar;
    btnSaveGrid: TBitBtn;
    btnAbortRegistration: TBitBtn;
    SaveDialog: TSaveDialog;
    procedure btnCreateTemplateClick(Sender: TObject);
    procedure btnClearGridClick(Sender: TObject);
    procedure btnOpenDataFileClick(Sender: TObject);
    function LTrim(s,subStr : string): string;
    function RTrim(s,subStr : string): string;
    function Trim(s,subStr : string): string;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure btnDoRegistrationClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnAbortRegistrationClick(Sender: TObject);
    procedure btnSaveGridClick(Sender: TObject);
    procedure BatchGridSetEditText(Sender: TObject; ACol, ARow: Integer;
      const Value: String);
  private
    { Private declarations }
    FieldNumList : TStringList;
    FAbortRegistration : boolean;
    procedure ClearGrid;
    procedure LoadData(fileName : string);
    procedure AddHeaderCol(oneEntry : string);  
    procedure GetColFieldNums(List : TStringList);
    function GetOneRow(row : integer; ColFields : TStringList) : string;
    function RegisterOne(oneRow : string; Log : TStringList) : string;
    procedure DelGridRow(BatchGrid : TStringGrid; row : integer);
  public
    { Public declarations }
  end;

var
  BatchAddForm: TBatchAddForm;

implementation

uses CreateTemplateU, StrUtils,ORNet, ORFn, Trpcb, FMErrorU;

const NOT_ADDED='(Not Added)';
      ADD_ROW='Add-->';
      ALREADY_ADDED='(Already Registered)';
{$R *.dfm}

  procedure TBatchAddForm.ClearGrid;
  begin
    BatchGrid.ColCount := 2;
    BatchGrid.RowCount := 3;
    BatchGrid.Cells[0,0] := 'Field NAME';
    BatchGrid.Cells[0,1] := 'Field NUM';
    BatchGrid.Cells[0,2] := '';
    BatchGrid.Cells[1,0] := '';
    BatchGrid.Cells[1,1] := '';
    BatchGrid.Cells[1,2] := '';
  end;


  procedure TBatchAddForm.btnCreateTemplateClick(Sender: TObject);
  begin
    CreateTemplateForm.PrepForm('2');
    CreateTemplateForm.ShowModal;
  end;

  procedure TBatchAddForm.btnClearGridClick(Sender: TObject);
  begin
    if MessageDlg('Clear All Patients?',mtConfirmation,mbOKCancel,0) = mrOK then begin
      ClearGrid;
      btnSaveGrid.Enabled := false;
      btnDoRegistration.Enabled := false;
      btnClearGrid.Enabled := false;
      btnCreateTemplate.Enabled := true;
      btnOpenDataFile.Enabled := true;
    end;
  end;

  procedure TBatchAddForm.btnOpenDataFileClick(Sender: TObject);
  begin
    if OpenDialog.Execute then begin
      LoadData(OpenDialog.FileName);
      btnClearGrid.Enabled := true;
      btnDoRegistration.Enabled := true;
      btnCreateTemplate.Enabled := false;
      btnOpenDataFile.Enabled := false;
    end;
  end;

  function TBatchAddForm.RTrim(s,subStr : string): string;
  var p,subLen : integer;       
  begin
    result := s;
    p := Pos(subStr,s);
    subLen := length(subStr);
    if p <> length(s)-subLen+1 then exit;
    result := MidStr(s,1, length(s)-subLen);
  end;

  
  function TBatchAddForm.LTrim(s,subStr : string): string;
  var p,subLen : integer;
  begin
    result := s;
    p := Pos(subStr,s);
    subLen := length(subStr);
    if p <> 1 then exit;
    result := MidStr(s,subLen+1,999);
  end;

  function TBatchAddForm.Trim(s,subStr : string): string;
  begin
    result := LTrim(s,subStr);
    result := RTrim(result,subStr);
  end;
  

  procedure TBatchAddForm.LoadData(fileName : string);
  var Data: TStringList;
      Line1List: TStringList;
      oneLine : string;
      value : string;
      row,i,j : integer;
      fldName,fldNum : string;
      dataFound : boolean;
      oneEntry : string;
  begin
    Data := TStringList.Create;
    Line1List := TStringList.Create;
    Data.LoadFromFile(fileName);
    if Data.Count < 3 then begin
      MessageDlg('Template file has less than 3 lines.'+#10+#13+
                 'Doesn''t appear to be valid template'+#10+#13+
                 'filled with patient data.  Please fill '+#10+#13+
                 'with patient demographics first.', mtError,[mbOK],0);
      exit;           
    end;
    ClearGrid;    
    //------- set up header rows  (name and number) ------------------
    oneLine := Data.Strings[0];
    PiecesToList(oneLine, #9, Line1List);
    oneLine := Data.Strings[1];
    PiecesToList(oneLine, #9, FieldNumList);
    for i := 1 to Line1List.Count-1 do begin
      fldName := Trim(Line1List.Strings[i],'"');
      if i < FieldNumList.Count then begin
        fldNum := LTrim(FieldNumList.Strings[i],'"<');
        fldNum := RTrim(fldNum,'>"');
      end else begin
        fldNum := '??';
      end;
      oneEntry := fldNum+'^'+fldName;
      AddHeaderCol(oneEntry);  
    end;    
    //--------- now load data ----------------------
    dataFound := true;
    for i := 2 to Data.Count-1 do begin
      if dataFound then begin
        if BatchGrid.RowCount = 3 then begin
          if BatchGrid.Cells[0,2] <> '' then BatchGrid.RowCount := BatchGrid.RowCount + 1;
        end else begin
          BatchGrid.RowCount := BatchGrid.RowCount + 1;
        end;  
      end;  
      row := BatchGrid.RowCount-1;
      oneLine := Data.Strings[i];    
      PiecesToList(oneLine, #9, Line1List);
      BatchGrid.Cells[0,row] := ADD_ROW;
      dataFound := false;  //don't advance line if data row is empty.
      for j := 1 to Line1List.Count-1 do begin  //don't use first column of data file
        value := Line1List.Strings[j];
        value := Trim(value,'"');
        if FieldNumList.Strings[j]='"<.09>"' then begin
          value := LTrim(value,'<');
          value := RTrim(value,'>');
        end;
        if value <> '' then dataFound := true;
        BatchGrid.Cells[j,row]:= value;
      end;
      if (dataFound = false) and (i = Data.Count-1) then begin
        BatchGrid.RowCount := BatchGrid.RowCount - 1;
      end;
    end;
    Data.Free;
    Line1List.Free;
  end;

  procedure TBatchAddForm.AddHeaderCol(oneEntry : string);  
  //oneEntry format: fldNum^fldName
  var i : integer;
      fldName,fldNum : string;
  begin
    CreateTemplateForm.GetNumName(oneEntry,fldName,fldNum);    
    i := BatchGrid.ColCount-1;
    if BatchGrid.Cells[i,0] <> '' then begin
      BatchGrid.ColCount := BatchGrid.ColCount + 1;
    end;
    i := BatchGrid.ColCount-1;

    BatchGrid.Cells[i,0] := fldName;      
    BatchGrid.Cells[i,1] := fldNum;      
  end;


  procedure TBatchAddForm.FormClose(Sender: TObject; var Action: TCloseAction);
  begin
    {
    if MessageDlg('Leave Batch Registration? (Later check to ensure data was saved)',mtConfirmation,mbOKCancel,0) = mrOK then begin
      Action := caHide;
    end else begin
      Action := caNone;
    end;
    }
  end;

  procedure TBatchAddForm.FormCreate(Sender: TObject);
  begin
    FieldNumList := TStringList.Create;
  end;

  
  procedure TBatchAddForm.btnDoRegistrationClick(Sender: TObject);
  var row : integer;
      ColFields : TStringList;
      onePostEntry : string;
      newIEN : string;
      Log : TStringList;
      Success,Failure,PreExisting : integer;
  begin
    btnOpenDataFile.Enabled := false;
    btnClearGrid.Enabled := true;
    btnAbortRegistration.Enabled := True;
    btnClearGrid.Enabled := False;
    btnSaveGrid.Enabled := False;
    
    Log := TStringList.Create;
    Success := 0;
    Failure := 0;
    PreExisting := 0;
    FMErrorForm.Memo.Lines.clear;
    ColFields := TStringList.Create;
    GetColFieldNums(ColFields);
    ProgressBar.Max := BatchGrid.RowCount-1;
    FAbortRegistration := false;  //abort button can change this.
    for row := 2 to BatchGrid.RowCount-1 do begin
      if FAbortRegistration = true then break;
      ProgressBar.Position := row;
      onePostEntry := GetOneRow(row,ColFields);
      newIEN := RegisterOne(onePostEntry,Log);
      BatchGrid.Cells[0,row] := newIEN;
      if newIEN = NOT_ADDED then inc(Failure) 
      else if newIEN = ALREADY_ADDED then inc(PreExisting) 
      else inc(Success);     
      Application.ProcessMessages;
    end;
    ProgressBar.Position := 0;
    ColFields.free;
    MessageDlg(IntToStr(Success)+' successful registrations,  '+#10+#13+
               IntToStr(PreExisting)+' Patients were already registered,'+#10+#13+
               IntToStr(Failure)+' failures.',
               mtInformation,[mbOK],0);
    for row := BatchGrid.RowCount-1 downto 2 do begin
      if (BatchGrid.Cells[0,row] <> NOT_ADDED)
      and (BatchGrid.Cells[0,row] <> ADD_ROW) then begin
        DelGridRow(BatchGrid,row);
      end;
    end;                        
    if Log.Count>0 then begin
      FMErrorForm.Memo.Lines.Assign(Log);
      FMErrorForm.PrepMessage;
      FMErrorForm.ShowModal;
    end;  
    Log.Free;
    if (BatchGrid.RowCount=3)and(BatchGrid.Cells[0,2]='') then begin
      btnSaveGrid.Enabled := false;
      btnDoRegistration.Enabled := false;
      btnClearGrid.Enabled := false;
      btnCreateTemplate.Enabled := true;
      btnOpenDataFile.Enabled := true;
      btnAbortRegistration.Enabled := true;
    end else begin
      btnClearGrid.Enabled := true;
      btnSaveGrid.Enabled := true; 
      btnAbortRegistration.Enabled := false;
    end;
  end;

  function TBatchAddForm.RegisterOne(oneRow : string; Log : TStringList) : string;
  var RPCResult : string;
      Msg : string;
      i : integer;
  begin
    RPCBrokerV.remoteprocedure := 'TMG CHANNEL';
    RPCBrokerV.param[0].ptype := list;
    RPCBrokerV.Param[0].Mult['"REQUEST"'] := 'REGISTER PATIENT^'+oneRow;
    RPCBrokerV.Call;
    RPCResult := RPCBrokerV.Results[0];    //returns:  error: -1;  success=1
    Msg := piece(RPCResult,'^',2);
    result := piece(RPCResult,'^',3);
    if result = '' then result := NOT_ADDED;
    if piece(RPCResult,'^',1)='-1' then begin
      if Msg='Patient already registered' then begin
        result := ALREADY_ADDED; 
        exit;
      end;  
      FMErrorForm.Memo.Lines.Assign(RPCBrokerV.Results);
      FMErrorForm.PrepMessage;  //Does some clean up of the message format
      //FMErrorForm.ShowModal;  //later just put these in log...
      Log.Add('-----------------------------------------------');
      Log.Add('There was a problem with registering a patient.');
      //Log.Add('This was the data sent to the server: ');
      //Log.Add('    '+oneRow);
      for i:= 0 to FMErrorForm.Memo.Lines.Count-1 do begin
        Log.Add(FMErrorForm.Memo.Lines.Strings[i]);
      end;    
      Log.Add(' ');      
      FMErrorForm.Memo.Lines.Clear;      
      if Msg='Success (but see message)' then exit;
      result := NOT_ADDED;
    end;     
  end;

  procedure TBatchAddForm.DelGridRow(BatchGrid : TStringGrid; row : integer);
  var col : integer;
  begin
    if row >= BatchGrid.RowCount then exit;
    repeat
      if row = BatchGrid.RowCount-1 then begin
        if BatchGrid.RowCount=3 then begin
          for col := 0 to BatchGrid.ColCount-1 do begin
            BatchGrid.Cells[col,row] := '';
          end;
        end else begin
          BatchGrid.RowCount := BatchGrid.RowCount-1;
        end;  
        exit;
      end;
      for col := 0 to BatchGrid.ColCount-1 do begin
        BatchGrid.Cells[col,row] := BatchGrid.Cells[col,row+1]
      end;
      inc(row);
    until (1=0);      
  end;  
  
  procedure TBatchAddForm.FormDestroy(Sender: TObject);
  begin
    FieldNumList.Free;
  end;

  procedure TBatchAddForm.GetColFieldNums(List : TStringList);
  var i : integer;
  begin
    List.Clear;
    List.Add(''); //fill 0'th column will null
    for i := 1 to BatchGrid.ColCount-1 do begin
      List.Add(BatchGrid.Cells[i,1]);      
    end;
  end;

  function TBatchAddForm.GetOneRow(row : integer; ColFields : TStringList) : string;
  //Output format: FldNum1^Value1^fldNum2^Value2^FldNum3^Value3...
  var i : integer;
      oneValue : string;
  begin    
    result := '';
    if row >= BatchGrid.RowCount then exit;
    for i := 1 to BatchGrid.ColCount-1 do begin
      result := result + ColFields.Strings[i]+'^'+BatchGrid.Cells[i,row]+'^';
    end;
  end;

  procedure TBatchAddForm.btnAbortRegistrationClick(Sender: TObject);
  begin
    FAbortRegistration := true;
  end;

  procedure TBatchAddForm.btnSaveGridClick(Sender: TObject);
  var DataLines : TStringList;
      Value : string;
      row,col : integer;
      Line : string;
  begin
    If SaveDialog.Execute then begin
      DataLines := TStringList.Create;
      for row := 0 to BatchGrid.RowCount-1 do begin
        Line := '';
        for col := 0 to BatchGrid.ColCount-1 do begin
          Value := BatchGrid.Cells[col,row];
          if Value = ADD_ROW then Value := ' ';          
          if (row=1)or((BatchGrid.Cells[col,1]='.09')and(row<>0)) then begin
            Value := '<'+Value+'>';  //protect field numbers as text
          end;  
          Line := Line + '"'+Value+'"' + #9
        end;  
        DataLines.Add(Line);
      end;
      DataLines.Add(' ');
      DataLines.Add('Add as many rows as needed)');
      DataLines.Add(' ');
      DataLines.Add('When done, save file and import with');
      DataLines.Add('  the WorldVista Config Utility.');
      DataLines.Add('Save in CSV format, using TAB as field');
      DataLines.Add(' delimiter, and " as text delimiter.');
      DataLines.SaveToFile(SaveDialog.FileName);
      DataLines.Free;
    end;
  end;

  procedure TBatchAddForm.BatchGridSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: String);
  begin
    btnSaveGrid.Enabled := true;
  end;

end.

