/******************************************************************************

#  $RCSfile: hl7_boom.sc,v $

#******************************************************************************

#     This is a component of Axon, the Real-Time HL7 Interface System

#     developed at the University of Washington Academic Medical Centers

#     by the HL7 Interface Team.

#

#  Author: J. Martin, from Boom Specs by T. Rozmyn et al...

#

#  Purpose: Container for functions used to support hl7_boom processing.

#

#           Functions:

#           ---------

#           msg_list_t * hl7_boom(msg_list_t *);

#             int          get_BOOM_person_no(msg_list_t *);

#             int          get_BOOM_pat_id();

#               msg_list_t * create_BOOM_list(msg_list_t *);

#

#******************************************************************************

#

#  $Source: /homes/hit/interfac/packages/rtif/common/src/RCS/hl7_boom.sc,v $

#

#******************************************************************************

#  $Log: hl7_boom.sc,v $

# Revision 1.6  2000/06/08  03:13:27  martinj

# added calls to get_bb_times

#

# Revision 1.5  2000/03/14  02:06:20  jalex

# added call to comma_del_remove to delete current patient

# from list of pat_no's to boom.

#

# Revision 1.4  2000/03/07  18:40:33  interfac

# *** empty log message ***

#

# Revision 1.1  2000/01/05  18:42:10  feattest

# Initial revision

#

# Revision 1.3  1999/11/09  16:53:54  jalex

# *** empty log message ***

#

# Revision 1.2  1999/11/02  00:44:07  jalex

# added functionality to create ZP2 and populate it when

# a non-patient person update (in NK1) occurs

#

# Revision 1.1  1999/10/18  17:21:36  martinj

# Initial revision

#

#******************************************************************************/

 

static char rcsid[] = "$Id: hl7_boom.sc,v 1.6 2000/06/08 03:13:27 martinj Exp $";

 

EXEC SQL INCLUDE SQLCA;

 

#include <stdio.h>

#include <sys/types.h>                        

#include <errno.h>

#include <strings.h>

#include <ctype.h>

#include "event.h"

#include "hl7_snd.h"

#include "error_stdout.h"

#include "safe_strcat.h"

#include "del_seg.h"

 

char *strPersonList;           /* list of person_no's  */

char *strPatIDList;            /* list of pat id's     */

 

/* set in get_BOOM_person_no                     */

char *strPID_patient_id[64];   

 

char        errmsg[128];

extern int     verbose_level;

 

extern evn_desc_t          *pEvn;

 

/* objects for hl7_getset                       */

extern spec_t EVN_event_code;

extern spec_t EVN_timestamp;

extern spec_t EVN_operator_id;

 

extern spec_t MSA_ack_code;

extern spec_t MSA_control_id;

extern spec_t MSH_send_app;

extern spec_t MSH_send_facility;

extern spec_t MSH_dest_app;   

extern spec_t MSH_dest_facility;

extern spec_t MSH_msg_timestamp;

extern spec_t MSH_msg_type;   

extern spec_t MSH_msg_event;

extern spec_t MSH_sequence_id;

extern spec_t MSH_hl7_version;

 

extern spec_t PID_set_id;    

extern spec_t PID_patient_id;

extern spec_t PID_alt_pat_id;

extern spec_t PID_alt_id_type;

extern spec_t PID_name_last;

extern spec_t PID_name_first;

extern spec_t PID_name_middle;

extern spec_t PID_name_suffix;

extern spec_t PID_ssn;

      

extern spec_t ZVN_upd_by; 

extern spec_t ZVN_upd_area;

extern spec_t ZVN_screen_id;

extern spec_t ZVN_netsec_updby;

 

/* objects to support BOOM person_no rules               */

extern spec_t ZP2_person_no;

spec_t ZN2_person_no    = { "ZN2",  3, 0, 0 };

spec_t NK1_set_id = { "NK1",  1, 0, 0 };

spec_t GT1_guar_no      = { "GT1",  2, 0, 0 };

spec_t ZI2_person_no    = { "ZI2", 33, 0, 0 };

extern spec_t ZMG_merge_type;

 

 

/*****************************************************************************

* function:    get_BOOM_person_no

* args:        msg_list_t *

* returns:     int (0=failure, 1=found a person_no/pat_id, 2=perform no Booming)

* usage info:

*

* accepts a msg_list_t pointer to a discrete event and

* extracts all the person_no's from the message using extraction

* rules given in boom_process.doc (T. Rozmyn).  Each person_no is

* concated into a string, suitable for input into Jay Alexander's

* process_bb.comma_del_sort_u function.

*

* HISTORY:

* --------

* Programmer:

* Date:

* Mod:

*

* Programmer:  J. Alexander

* Date:            16-Nov-1999

* Mod:             got rid of A28/A31 ZN2_person_no hack.

*            now using validate_syntax / hl7_set_by_grp.

*

* Programmer:  Jeff Martin

* Date:        28-Oct-1999

* Mod:         implemented v2.1 person_no rules.

*

* Programmer:  Jeff Martin

* Date:            18-Oct-1999

* Mod:             started.

*

******************************************************************************/

int

get_BOOM_person_no(msg_list_t *REGlist)

{

 

hl7_union_t *vs_result, *msgReg; /* message in hl7_get format              */

char    *c, *sub_c;              /* generic string pointers for hl7_get    */

char    evn_code[4];             /* evn_code from REG event                */

int     handledEvent = 0;        /* set if event code is BOOM eligible     */

int     shutdownEnable = 1;      /* used to further gate return(0)         */

 

segment_t    *pSeg_t;

 

char         *strWorking[MAX_HL7_MESSAGE_SIZE];

 

extern evn_desc_t  *pEvn;

evn_desc_t         *pTrav;

char               evn_grammar[1025];

 

/***** code section **************************************************/

evn_grammar[0]=(char)'\0';

 

if( verbose_level >= 100)

    log_bb_times("get_BOOM_person_no: start");

 

 

/* convert message to storage format  */

if((msgReg =  (hl7_union_t *)str2mesg(REGlist->msg)) == NULL) {

     sprintf(errmsg,

             "REG event %d failed str2msg",

             REGlist->seq_no );

     error_notify(__FILE__, __LINE__,errmsg, NOTIFY_FATAL);

     return(0);

}

 

/* get the REG event code     */

c = (char *) hl7_get(msgReg, &EVN_event_code, 1, 0, NULL, 0, 0);

if (c == NULL) {

  sprintf(errmsg,

         "BOOM can't get EVENT CODE for REG event %d",

          REGlist->seq_no );

  error_notify(__FILE__, __LINE__,errmsg, NOTIFY_FATAL);

  freemesg(msgReg);

  return(0);

}

strcpy(evn_code, c);

 

sprintf(errmsg,

      "BOOM got event code %s.",evn_code);

error_notify(__FILE__, __LINE__,errmsg, NOTIFY_UPDATE);

 

for(pTrav = pEvn; pTrav; pTrav = pTrav->next){

  if(!strcmp(pTrav->event_code, evn_code)) break;

}

if(!pTrav) {

  sprintf(errmsg, "No HL7 grammar defined for message %s", evn_code);

  error_notify(__FILE__, __LINE__, errmsg, NOTIFY_FATAL);

  freemesg(msgReg);

  return(0);

} else {

  safe_strcat(evn_grammar, pTrav->event_desc,1025);

  if(safe_strcat_err) {

    freemesg(msgReg);

    return(0);

  }

  if(strlen(evn_grammar) == 0) {

    sprintf(errmsg, "No message grammar defined for event %s",

            evn_code);

    error_notify(__FILE__, __LINE__, errmsg, NOTIFY_FATAL);

    freemesg(msgReg);

    return(0);

  } else {

    hl7_union_t *vs_result;

 

    vs_result = (hl7_union_t*)validate_syntax(evn_grammar, msgReg);

    if(!vs_result) {

      sprintf(errmsg, "Message failed syntax validation");

      error_notify(__FILE__, __LINE__, errmsg, NOTIFY_SERIOUS);

      printmesg(msgReg);

      sprintf(errmsg, "Validate_syntax:  Error: syntax must match %s",

              evn_grammar);

      error_notify(__FILE__, __LINE__, errmsg, NOTIFY_FATAL);

      freemesg(msgReg);

      return(0);

      }

    msgReg = vs_result;

  }

}

evn_grammar[0]=(char)'\0';

 

sprintf(errmsg,

      "Finished validate_syntax.");

error_notify(__FILE__, __LINE__,errmsg, NOTIFY_UPDATE);

 

/* allocate some storage for strPersonList      */

strPersonList = (char *) calloc(512, sizeof(char));

if(strPersonList == NULL) {

        error_notify(__FILE__, __LINE__,

                 "Can't calloc for strPersonList",

                 NOTIFY_FATAL);

        freemesg(msgReg);

        return NULL;

       }

 

/* implement BOOM person_no rules.  See boom_process.doc */

if (strcmp(evn_code,"A04") == 0) {

    handledEvent = 1;

    c = (char *) hl7_get(msgReg, &ZP2_person_no, 1, 0, NULL, 0, 0);

    if (c != NULL) {

       if (verbose_level >= 10000)

           printf("\t\t\tgot A04 ZP2_person_no: %s\n",c);

       strcat(strPersonList, c);

       strcat(strPersonList,",");

    }

 

} /* A04        */

 

if (strcmp(evn_code,"A08") == 0) {

    handledEvent = 1;

    c = (char *) hl7_get(msgReg, &ZP2_person_no, 1, 0, NULL, 0, 0);

    if (c != NULL) {

      if (verbose_level >= 10000)        

            printf("\t\t\tgot A08 ZP2_person_no: %s\n",c);

        strcat(strPersonList, c);

        strcat(strPersonList,",");

    }

 

    c = (char *) hl7_get(msgReg, &ZN2_person_no, 1, 0, NULL, 0, 0);

    /* strWorking is a hack at a big stump in the

       field I've decided to plow around     */

    sprintf(strWorking,"%s",c?c:"<null>");   

 

    if (c != NULL)  {

        sub_c = (char *) hl7_get(msgReg, &NK1_set_id, 1, 0, NULL, 0, 0);

        if (sub_c != NULL ) {

            if ( strcmp(sub_c,"PTN")==0 || strcmp(sub_c,"LNOK")==0 ) {

                if (verbose_level >= 10000)

                    printf("\t\t\tgot A08 ZN2_person_no: %s\n",strWorking);

            strcat(strPersonList, strWorking);

            strcat(strPersonList,",");

               

            }

         }

    }

 

    c = (char *) hl7_get(msgReg, &GT1_guar_no, 1, 0, NULL, 0, 0);

    if (c != NULL) {

        if (verbose_level >= 10000)

            printf("\t\t\tgot A08 GT1_guar_no: %s\n",c);

        strcat(strPersonList, c);

        strcat(strPersonList,",");

    }

 

    c = (char *) hl7_get(msgReg, &ZI2_person_no, 1, 0, NULL, 0, 0);

    if (c != NULL) {

        if (verbose_level >= 10000)   

            printf("\t\t\tgot A08 ZI2_person_no: %s\n",c);

        strcat(strPersonList, c);

        strcat(strPersonList,",");

    }

 

} /* A08        */

 

if (strcmp(evn_code,"A28") == 0 || strcmp(evn_code,"A31") == 0) {

    handledEvent = 1;

    c = (char *) hl7_get(msgReg, &ZP2_person_no, 1, 0, NULL, 0, 0);

    if ( c != NULL ) {

         if (verbose_level >= 10000)

             printf("\t\t\tA28/A31 handler got ZP2_person_no: %s\n",c);

         strcat(strPersonList,c);

         strcat(strPersonList,",");

    }

    else {

        /* no ZP2, try to get ZN2   */

          c = (char *) hl7_get(msgReg, &ZN2_person_no, 1, 0, NULL, 0, 0);

 

          if (c != NULL ) {

              if (verbose_level >= 10000)

                  printf("\t\t\tA28/A31 handler got ZN2 person_no %s\n",c);

 

              hl7_set_by_grp(msgReg,&ZP2_person_no,1,0,NULL,0,c);

 

              pSeg_t = (segment_t *) hl7_find_seg(msgReg, "NK1",

                                        1, 0, 0, 0, 0);

              /* blank NK1 / ZN2 if they exist  */

              if( pSeg_t ) {

              if( hl7_set(msgReg,&NK1_set_id,

                            1, 0, 0, 0, NULL)) {

                    sprintf(errmsg,"BOOM can't zero %s.NK1",

                            evn_code);

                    error_notify(__FILE__, __LINE__,

                                 errmsg, NOTIFY_FATAL);

                    return(0);

                }

              }

 

              pSeg_t = (segment_t *) hl7_find_seg(msgReg, "ZN2",

                                                  1, 0, 0, 0, 0);

              if( pSeg_t ) {

                 if( hl7_set(msgReg,&ZN2_person_no,

                             1, 0, 0, 0, NULL)) {

                     sprintf(errmsg,"BOOM can't zero %s.ZN2",

                             evn_code);

                     error_notify(__FILE__, __LINE__,

                                  errmsg, NOTIFY_FATAL);

                     return(0);

                  }

               }

 

             if(strip_seg(msgReg,"NK1",1,0,0)) {

             sprintf(errmsg,

                  "A28/A31 handler failed to strip the NK1 in event %d (%s)",

                   REGlist->seq_no, evn_code );

                   error_notify(__FILE__, __LINE__,

                                errmsg, NOTIFY_FATAL);

               return(0);

             }

 

             if(strip_seg(msgReg,"ZN2",1,0,0)) {

             sprintf(errmsg,

                  "A28/A31 handler failed to strip the ZN2 in event %d (%s)",

                   REGlist->seq_no, evn_code );

                   error_notify(__FILE__, __LINE__,

                                errmsg, NOTIFY_FATAL);

               return(0);

             }

 

           /* convert the modified msg to string,

            append person_no list */

             mesg2str(msgReg,REGlist->msg);

             strcat(strPersonList,c);

             strcat(strPersonList,",");

     

             /* we've modified the Boom list head,

                we should tell someone...        */ 

             if (verbose_level >= 10000 ) {

                  sprintf(errmsg,

                  "A28/A31 handler modified ZP2,ZN2,NK1 in event %d (%s)",

                   REGlist->seq_no, evn_code );

                   error_notify(__FILE__, __LINE__,

                                errmsg, NOTIFY_UPDATE);

             }

 

           } /* ZN2 */

     } /* ZP2 */

 

} /* A28/A31        */

 

if (strcmp(evn_code,"A34") == 0) {

    handledEvent = 1;

    c = (char *) hl7_get(msgReg,

                     &ZP2_person_no, 1, 0, NULL, 0, 0);

    strcpy(strWorking,c);

    if ( c != NULL ) {

       sub_c = (char *) hl7_get(msgReg,

                          &ZMG_merge_type, 1, 0, NULL, 0, 0);

       if (sub_c != NULL) {

         if (strcmp(sub_c,"PERMNO") == 0) {

             if(verbose_level >= 10000)

                 printf("\t\t\tgot A34 ZP2_person_no: %s\n",

                     strWorking);

             strcat(strPersonList, strWorking);

             strcat(strPersonList,",");

         }

        else

          /* got a ZP2_person_no, return(2) returns

           the orignial list without Booming    */

          return(2);

       }

    }

 

} /* A34    */   

 

/* filt_msg should've trapped this              */

if (handledEvent == 0 ) {

   if (verbose_level >= 10000 ) {

       sprintf(errmsg,

               "No person_no handler for event %d (%s)",

                REGlist->seq_no,evn_code );

       error_notify(__FILE__, __LINE__,errmsg, NOTIFY_SERIOUS);

   }

   freemesg(msgReg);

 

   if( verbose_level >= 100)

       log_bb_times("get_BOOM_person_no: start");

 

   return(2);

}

 

if ((strPersonList        == NULL ||

    strlen(strPersonList) == 0)   &&

    (shutdownEnable       == 1 )) {

    printmesg(msgReg);

    sprintf(errmsg,

            "BOOM can't find a person_no for event %d (%s)",

            REGlist->seq_no, evn_code);

    error_notify(__FILE__, __LINE__,errmsg, NOTIFY_FATAL);

    freemesg(msgReg);

    shutdown_primary();

}

 

/* store patient_id           */   

c = (char *) hl7_get(msgReg,

                      &PID_patient_id, 1, 0, NULL, 0, 0);

if( c == NULL && (strcmp(evn_code,"A28") && strcmp(evn_code,"A31"))) {

    sprintf(errmsg,

            "BOOM can't get PID_patient_id for event %d (%s)",

             REGlist->seq_no, evn_code);

    error_notify(__FILE__, __LINE__,errmsg, NOTIFY_FATAL);

    freemesg(msgReg);

    return(0);

} else if( c == NULL) {

strPID_patient_id[0]='\0';

} else {

strcpy(strPID_patient_id,c);         /* get data for get_BOOM_pat_id  */

}

 

if(msgReg)

 freemesg(msgReg);

 

if( verbose_level >= 100)

    log_bb_times("get_BOOM_person_no: end");

 

 

return(1);

 

}/********** end of get_BOOM_person_no **************************************/

 

 

/*****************************************************************************

* function:    get_BOOM_pat_id

* args:        none

* returns:     int, 0 if errors.

* usage info:

*

* parses a global string that contains person_no(s) from

* get_BOOM_person_no(), passes each to two SQL commands

* that return all the patient identifiers associated

* with the person_no.  The patient identifiers are

* concated into a string (strPatIDList) suitable for input

* into Jay Alexander's process_bb.comma_del_sort_u function.

*

* HISTORY:

* --------

* Programmer:

* Date:

* Mod:

*

*

* Programmer: Jeff Martin

* Date:       14-Jun-2000

* Mod:        Exclude source idrs from patient idr list for boosting.

*

* Programmer:  T. Rozmyn

* Date:            21-Feb-2000

* Mod:         Removed hosp/pat_no clauses from pat_pers_rel query; added

*              pers_syn query to get pat_nos when pat is purged.

*

* Programmer:  Jeff Martin

* Date:        20-Oct-1999

* Mod:         started.

*

******************************************************************************/

int

get_BOOM_pat_id() {

 

EXEC SQL BEGIN DECLARE SECTION;

  char   hosp[2];

  char   msg_hosp[2];

  char   pat_no[8];

  char   msg_pat_no[8];

  char   pat_id[11];

  int    msg_person_no;

EXEC SQL END DECLARE SECTION;

 

int  counter=0;         /* counts char in strPatIDList  */

int  minor_counter=0;   /* counts char in strPersonNo   */

char *strPersonNo;      /* extract from strPersonList */

char *strPatID[11];     /* appended to strPatIDList   */

 

/********* code **************************************************************/

 

/* init buffers         */

 

if( verbose_level >= 100)

    log_bb_times("get_BOOM_pat_id: start");

 

 

strPersonNo = (char *) calloc(strlen(strPersonList), sizeof(char));

if(strPersonNo == NULL) {

        error_notify(__FILE__, __LINE__,

                     "Can't calloc for strPersonNo",

                     NOTIFY_SERIOUS);

        return(0);

       }

strPatIDList = (char *) calloc(512, sizeof(char));

if(strPatIDList == NULL) {

        error_notify(__FILE__, __LINE__,

                     "Can't calloc for strPatIDList",

                     NOTIFY_SERIOUS);

        free(strPersonNo);

        return(0);

       }

 

/* parse get_BOOM_person_no.strPID_patient_id for this list */

if(strlen(strPID_patient_id)){

sscanf(strPID_patient_id,"%c%s",msg_hosp,msg_pat_no);

sprintf(msg_hosp,"%c",strPID_patient_id[0]);

} else {

msg_hosp[0]='\0';

msg_pat_no[0]='\0';

}

 

/* get patient identifiers for each person_no              */

for(counter=0; counter<=strlen(strPersonList); counter++){

    if (strPersonList[counter] != ',') {

         /* parse strPersonList     */

       strPersonNo[minor_counter++] = strPersonList[counter];

         if( minor_counter >= strlen(strPersonList) ){

             error_notify(__FILE__, __LINE__,

           "BOOM tried to parse an INVALID strPersonList",

           NOTIFY_SERIOUS);

             free(strPersonNo);

             return(0);

         }

    }

    else {

         /* do work           */

         strPersonNo[minor_counter++] = '\0';

         minor_counter=0;

       msg_person_no = atoi(strPersonNo);

 

         if( verbose_level >= 10 ) {

             sprintf(errmsg,

                     "get_BOOM_pat_id:  working on person_no %d",

                      msg_person_no);

             error_notify(__FILE__, __LINE__,errmsg,NOTIFY_UPDATE);

         } 

           

/******* get patient identifiers from PAT_PERS_REL  *********/

 

       if (verbose_level >= 10000 ) {

 printf("\nEXEC SQL REPEATED SELECT DISTINCT    hosp,  pat_no\n"

        "INTO                                :hosp, :pat_no\n"

        "FROM    pat_pers_rel\n"             

        "WHERE   person_no                =  %d\n"

        "AND     eff_thru_dt              =  '31-dec-2099 23:59:59'\n"

        "AND     pers_rel_to_pat_cd      !=  'NO'\n"

        "AND     pers_rel_to_pat_cd      !=  'RF'\n\n",

        msg_person_no, msg_pat_no, msg_hosp);

        }

       

      EXEC SQL REPEATED SELECT DISTINCT   SQUEEZE(hosp), SQUEEZE(pat_no)

        INTO                                :hosp, :pat_no

        FROM    pat_pers_rel

        WHERE   person_no                =  :msg_person_no

        AND     eff_thru_dt              =  '31-dec-2099 23:59:59'

        AND     pers_rel_to_pat_cd      !=  'NO'

        AND     pers_rel_to_pat_cd      !=  'RF';

 

      EXEC SQL BEGIN;

          sprintf(strPatID,"%s%s",hosp, pat_no);

 

          /* exclude source idr from strPatID                   */

          if( strcmp(strPID_patient_id,strPatID) ) {

              strncat(strPatIDList,strPatID,sizeof(strPatID));

              strcat(strPatIDList,",");

          }

 

          if (verbose_level >= 10000 ) {

                sprintf(errmsg,"PAT_PERS_REL query returned %s",

                        strPatID);

                error_notify(__FILE__, __LINE__,errmsg,NOTIFY_UPDATE);

          }

        EXEC SQL END;

 

        switch(sqlca.sqlcode) {

        case 0:

            break;

      case 100:

                    if (verbose_level >= 10000 ) {

                 error_notify(__FILE__, __LINE__,

                          "PAT_PERS_REL query returned no rows",

                              NOTIFY_UPDATE);

            }

            break;

      default:

               ingerr(__FILE__, __LINE__, sqlca.sqlcode,DEFAULT_SEQ_NO);

               error_notify(__FILE__, __LINE__,

                            "BOOM can't select against PAT_PERS_REL",

                      NOTIFY_FATAL);

               shutdown_primary();

 

        } /* switch */

 

/******* get patient identifiers from COVERAGE  *********/

 

/*

if(comma_del_remove(strPatIDList,strPID_patient_id)){

     ;

}

*/

 

         if (verbose_level >= 10000 ) {

 printf("\nEXEC SQL REPEATED SELECT DISTINCT    hosp,  pat_no\n"

        "INTO                                :hosp, :pat_no\n"

        "FROM    coverage\n"

        "WHERE   person_no                =  %d\n"

        "AND     eff_thru_dt              =  '31-dec-2099 23:59:59'\n"

        "AND     pat_no                  !=  '%s'\n"

        "AND     hosp                    !=  '%s'\n\n",

        msg_person_no, msg_pat_no, msg_hosp);

        }

 

        EXEC SQL REPEATED SELECT DISTINCT   SQUEEZE(hosp), SQUEEZE(pat_no)

        INTO                                :hosp, :pat_no

        FROM    coverage

        WHERE   person_no                =  :msg_person_no

        AND     eff_thru_dt              =  '31-dec-2099 23:59:59'

        AND     pat_no                  !=  :msg_pat_no

        AND     hosp                    !=  :msg_hosp;

 

        EXEC SQL BEGIN;

 

          sprintf(strPatID,"%s%s",hosp, pat_no);

 

          /* exclude source idr from strPatID                   */

          if( strcmp(strPID_patient_id,strPatID) ) {

              strncat(strPatIDList,strPatID,sizeof(strPatID));

              strcat(strPatIDList,",");

          }

 

          if (verbose_level >= 10000 ) {

                sprintf(errmsg,"COVERAGE query returned %s",

                        strPatID);

                error_notify(__FILE__, __LINE__,

                            errmsg,NOTIFY_UPDATE);

          }

        EXEC SQL END;

 

        switch(sqlca.sqlcode) {

        case 0:

                break;

        case 100:

                if (verbose_level >= 10000 ) {

                     error_notify(__FILE__, __LINE__,

                                  "COVERAGE query returned no rows",

                                  NOTIFY_UPDATE);

                }

                break;

        default:

               ingerr(__FILE__, __LINE__, sqlca.sqlcode,DEFAULT_SEQ_NO);

               error_notify(__FILE__, __LINE__,

                            "BOOM can't select against COVERAGE",

                            NOTIFY_FATAL);

               shutdown_primary();

 

          } /* switch */

 

/*

 *  get patient identifiers from PERS_SYN using msg person_no.  This is

 *  to catch those patients that have been purged and do not have a

 *  PAT_PERS_REL 'PAT/SE' record.  T. Rozmyn 2/21/2000.

 */

 

       if (verbose_level >= 10000 ) {

 printf("\nEXEC SQL REPEATED SELECT DISTINCT hosp,  pat_no\n"

        "INTO                                :hosp, :pat_no\n"

        "FROM    pers_syn              \n"

        "WHERE   person_no                =  %d\n"

        "AND     hosp                    !=  '' \n"

        "AND     pat_no                  !=  '' \n"

        "AND     current_name             = 'Y'\n"       

        "AND     bypass_rs                = 'N'\n",

        msg_person_no);

        }

       

      EXEC SQL REPEATED SELECT DISTINCT   SQUEEZE(hosp), SQUEEZE(pat_no)

        INTO                                :hosp, :pat_no

        FROM    pers_syn

        WHERE   person_no                =  :msg_person_no

      AND     hosp                    != ''

        AND     pat_no                  != ''                                      

        AND     current_name             = 'Y'

        AND     bypass_rs                = 'N';

 

      EXEC SQL BEGIN;

 

          sprintf(strPatID,"%s%s",hosp, pat_no);

 

          /* exclude source idr from strPatID                   */

          if( strcmp(strPID_patient_id,strPatID) ) {

              strncat(strPatIDList,strPatID,sizeof(strPatID));

              strcat(strPatIDList,",");

          }

 

          if (verbose_level >= 10000 ) {

                sprintf(errmsg,"PERS_SYN query returned %s",

                        strPatID);

                error_notify(__FILE__, __LINE__,

                            errmsg,NOTIFY_UPDATE);

          }

        EXEC SQL END;

 

        switch(sqlca.sqlcode) {

        case 0:

            break;

      case 100:

                    if (verbose_level >= 10000 ) {

                 error_notify(__FILE__, __LINE__,

                          "PERS_SYN query returned no rows",

                              NOTIFY_UPDATE);

            }

            break;

      default:

               ingerr(__FILE__, __LINE__, sqlca.sqlcode,DEFAULT_SEQ_NO);

               error_notify(__FILE__, __LINE__,

                            "BOOM can't select against PERS_SYN",

                      NOTIFY_FATAL);

               shutdown_primary();

 

          } /* switch */

 

 

    } /* if (strPersonList[counter] != ',')     */

} /* for(counter<=strlen(strPersonList))  */

 

 

if (strPatIDList         == NULL ||

    strlen(strPatIDList) == 0) {

      if (verbose_level >= 10000 ) {

          sprintf(errmsg,

                  "BOOM can't find any PAT ID's for PERSON %d ",

                   msg_person_no);

          error_notify(__FILE__, __LINE__,errmsg, NOTIFY_SERIOUS);

       }

    free(strPersonNo);

 

    if( verbose_level >= 100)

        log_bb_times("get_BOOM_pat_id: end");

 

 

    return(0);

}

 

 

free(strPersonNo);

 

if( verbose_level >= 100)

    log_bb_times("get_BOOM_pat_id: end");

 

return(1);

}/******** end of get_BOOM_pat_id *******************************************/

 

 

/*****************************************************************************

* function:    create_BOOM_list

* args:        msg_list_t * to current REG event

* returns:     new msg_list_t * starting with current REG event

*            followed by zero or more stub A31 events.

* usage info:

*

* HISTORY:

* --------

* Programmer:

* Date:

* Mod:

*

* Programmer:  Jeff Martin

* Date:        20-Oct-1999

* Mod:         started.

*

******************************************************************************/

msg_list_t *

create_BOOM_list(msg_list_t * myREGlist) {

 

msg_list_t  *pHead, *pOld, *pNew;

hl7_union_t *msgReg;

 

char    *c;

int     intNodeCount = 0;

 

/* properties for A31 stubs                 */

char    strDateTime[16];

int     intDate;

int     intTime;

char    strMSH_send_app[64];

char    strMSH_send_facility[64];

char    strMSH_dest_app[64];

char    strMSH_dest_facility[64];

char    strMSH_hl7_version[64];

char    strEVN_timestamp[64];

char    strEVN_operator_id[64];

char    strZVN_upd_by[64];

char    strZVN_upd_area[64];

 

int  counter=0;

int  minor_counter=0;

char *strBoomPatID;                     /* extract from strPatIDList   */

char strPersonNo[14];                   /* value for hl7_set           */

 

EXEC SQL BEGIN DECLARE SECTION;

  char   boomee_hosp[2];

  char   boomee_pat_no[8];

  int    boomee_person_no;

EXEC SQL END DECLARE SECTION;

 

/************ code ******************************************************/

 

if( verbose_level >= 100)

    log_bb_times("create_BOOM_list: start");

 

 

/* init buffers         */

strBoomPatID = (char *) calloc(strlen(strPatIDList), sizeof(char));

if(strBoomPatID == NULL) {

     sprintf(errmsg,

             "tried to calloc %d bytes for BOOM list\n%s",

              strlen(strPatIDList),

              strerror(errno));

     error_notify(__FILE__, __LINE__,

                 errmsg, NOTIFY_FATAL);

     /* enable shutdown_primary */

     return(NULL);

}

 

/* init head            */

 pNew = (msg_list_t *) calloc(1, sizeof(msg_list_t));

 if (pNew == NULL) {

     sprintf(errmsg,

             "tried to calloc %d bytes for BOOM list\n%s",

              sizeof(msg_list_t),

              strerror(errno));

     error_notify(__FILE__, __LINE__,

                 errmsg, NOTIFY_FATAL);

     return(NULL);

}

pNew->seq_no = myREGlist->seq_no;

strcpy(pNew->msg,myREGlist->msg);

 

pHead = pNew;

pOld  = pNew;

 

/*  get stub constants from REG message  */

msgReg = (hl7_union_t *) str2mesg(myREGlist->msg);

 

c = (char *) hl7_get(msgReg, &MSH_send_app, 1, 0, NULL, 0, 0);

  strcpy(strMSH_send_app, ( c ? c : "" ));

c = (char *) hl7_get(msgReg, &MSH_send_facility, 1, 0, NULL, 0, 0);  

 strcpy(strMSH_send_facility, ( c ? c : "" ));

c = (char *) hl7_get(msgReg, &MSH_dest_app, 1, 0, NULL, 0, 0);

 strcpy(strMSH_dest_app, ( c ? c : "" ));

c = (char *) hl7_get(msgReg, &MSH_dest_facility, 1, 0, NULL, 0, 0);

 strcpy(strMSH_dest_facility, ( c ? c : "" ));

c = (char *) hl7_get(msgReg, &MSH_hl7_version, 1, 0, NULL, 0, 0);

 strcpy(strMSH_hl7_version, ( c ? c : "" ));

c = (char *) hl7_get(msgReg, &EVN_timestamp, 1, 0, NULL, 0, 0); 

 strcpy(strEVN_timestamp, ( c ? c : "" )); 

c = (char *) hl7_get(msgReg, &EVN_operator_id, 1, 0, NULL, 0, 0);   

 strcpy(strEVN_operator_id, ( c ? c : "" ));   

c = (char *) hl7_get(msgReg, &ZVN_upd_by, 1, 0, NULL, 0, 0); 

 strcpy(strZVN_upd_by, ( c ? c : "" )); 

c = (char *) hl7_get(msgReg, &ZVN_upd_area, 1, 0, NULL, 0, 0); 

 strcpy(strZVN_upd_area, ( c ? c : "" )); 

 

if(msgReg)

   freemesg(msgReg);

 

/* trasverse patient identifier list            */

for(counter=0; counter<=strlen(strPatIDList); counter++){

    if (strPatIDList[counter] != ',') {

         /* parse strPatIDList */

         strBoomPatID[minor_counter++] = strPatIDList[counter];

         if( minor_counter >= strlen(strPatIDList) ){

             error_notify(__FILE__, __LINE__,

             "BOOM tried to parse an INVALID strPatIDList",

             NOTIFY_FATAL);

             return(NULL);

         }

    }

    else {

         /* play     */

         strBoomPatID[minor_counter++] = '\0';

         minor_counter=0;

 

      /* parse hosp, pat_no */

        sscanf(strBoomPatID,"%c%s",

             boomee_hosp, boomee_pat_no);

        sprintf(boomee_hosp,"%c",strBoomPatID[0]);

 

        /* populate each node with a stub A31   */

 

        /* Obtain the patient's person_no       */

        if (verbose_level >= 10000 ) {   

         printf(

           "\nEXEC SQL REPEATED SELECT DISTINCT  person_no\n"

           "INTO                              :boomee_person_no\n"

           "FROM  PERS_SYN\n"

           "WHERE pat_no                       = '%s'\n"

           "AND   hosp                         = '%s'\n"

           "AND   current_name                 = 'Y'\n"

           "AND   bypass_rs                    = 'N'\n\n",

           boomee_pat_no, boomee_hosp);

        }

 

      EXEC SQL REPEATED SELECT DISTINCT  person_no

        INTO                              :boomee_person_no

        FROM  PERS_SYN

        WHERE pat_no                      = :boomee_pat_no

        AND   hosp                        = :boomee_hosp

        AND   current_name                = 'Y'

        AND   bypass_rs                   = 'N';

 

        switch(sqlca.sqlcode) {

        case 0:

              intNodeCount++;

            sprintf(strPersonNo,"%d",boomee_person_no);

               if (verbose_level >= 10000 ) {

                    sprintf(errmsg,"PERS_SYN query returned %s",

                            strPersonNo);

                    error_notify(__FILE__, __LINE__,

                                 errmsg,NOTIFY_UPDATE);

               }

 

              /* allocate a node for an A31 stub      */

              pNew = (msg_list_t *) calloc(1, sizeof(msg_list_t));

              if (pNew == NULL) {

                  sprintf(errmsg,

                          "tried to calloc %d bytes for BOOM list\n%s",

                           sizeof(msg_list_t),

                           strerror(errno));

                   error_notify(__FILE__, __LINE__,

                                errmsg, NOTIFY_FATAL);

                   return(NULL);

              }

            /* build the A31 stub

             (copied in part from pat_xref_uwmc_hmc_batch.sc) */

 

              /* timedate.c        */    

              intDate = hl7_getdate();

              intTime = gettime();

            sprintf(strDateTime,"%d%d",intDate,intTime);

 

            sprintf(pNew->msg,

                     "MSH|^~\\&|%s|%s|%s|%s|%s||ADT^A31||P|%s|%c"

                     "EVN|A31|%s|||%s%c"

                     "ZVN|%s|%s|%c"

                     "PID|||%s%s||%c"

                     "ZP2||||||||||||||||||||||||||||||||"

                        "||||||||||||||||||||||||||||||%d%c",

 

             /* MSH  */

               strMSH_send_app,

               strMSH_send_facility,

                 strMSH_dest_app,

                 strMSH_dest_facility,           

             strDateTime, 

                 strMSH_hl7_version,

              

             /* EVN */

             13,

             strEVN_timestamp,

                 strEVN_operator_id,

 

             /* ZVN */

               13,

                 strZVN_upd_by,

                 strZVN_upd_area,

 

             /* PID */

             13,

                 boomee_hosp,

                 boomee_pat_no,

 

                 /* ZP2 */

                 13,

                 boomee_person_no,13);

 

            /* point at the next node               */

              pOld->next = pNew;

              pOld       = pNew;   

              break;

        case 100:

                if (verbose_level >= 10000 ) {

                    sprintf(errmsg,

                            "BOOM can't find a PERSON in PERS_SYN for %s%s",

                             boomee_hosp,boomee_pat_no);

                    error_notify(__FILE__, __LINE__,errmsg, NOTIFY_SERIOUS);

                }

                break;

        default:

               ingerr(__FILE__, __LINE__, sqlca.sqlcode,DEFAULT_SEQ_NO);

               error_notify(__FILE__, __LINE__,

                            "BOOM can't select against PERS_SYN",

                            NOTIFY_FATAL);

               shutdown_primary();

 

          } /* switch */

 

    } /* if (strPatIDList[counter] != ',')      */

 

} /* for(counter<=strlen(strPatIDList))         */

 

/* terminate the list                     */

pNew->next = NULL;

 

if( verbose_level >= 10) {

    sprintf(errmsg,"returning %d related idrs to BOOST",intNodeCount);

    error_notify(__FILE__, __LINE__,errmsg, NOTIFY_UPDATE);

}

 

if( verbose_level >= 100)

    log_bb_times("create_BOOM_list: end");

 

return(pHead);

}/**************** end of create_BOOM_list **********************************/

 

 

 

/*****************************************************************************

* function:    hl7_boost

* args:        msg_list_t *

* returns:     msg_list_t *

* usage info:

*

* recieves a pointer to a discrete HL7 message in

* msg_list_t, and extracts a list of any BOOM eligible

* person_no's found in the message.

*

* For each eligible person_no found, emits a series of

* stub A31 messages for each related patient identifier.

* The series head is always the original message.

*

* If no BOOM eligible person_no's or related patient

* identifiers can be found, the original message is

* returned.  Otherwise, the list of A31 stubs is

* returned as a new msg_list_t *.

*

* HISTORY:

* --------

* Programmer:

* Date:

* Mod:

*

* Programmer:     Jeff Martin

* Date:           17-Oct-1999

* Mod:            Started

*

******************************************************************************/

msg_list_t *

hl7_boom(msg_list_t *REGlist)

{

msg_list_t   *BOOMlist;

 

int        intStatus;

 

/****** code section ************************/

 

/* find the person_no's for the event type      */

intStatus = get_BOOM_person_no(REGlist);

 

sprintf(errmsg,

      "Finished get_BOOM_person_no with status %d",

      intStatus);

error_notify(__FILE__, __LINE__,errmsg, NOTIFY_UPDATE);

 

if (intStatus == 0) {

      if(strPersonList)

      free(strPersonList);

 

      shutdown_primary();

}

 

/* perform no BOOMing                     */

if (intStatus == 2)

    return(REGlist);

 

if (verbose_level >= 10) {

     sprintf(errmsg,

             "Booming REG event %d",REGlist->seq_no);

     error_notify(__FILE__, __LINE__,errmsg, NOTIFY_UPDATE);

}

 

/* remove duplicates from the person_no list    */

if ( comma_del_sort_u(strPersonList) != 0) {

     sprintf(errmsg,

             "%s %s %d \nstrPersonList: %s",

             "comma_del_sort_u failed parsing",

             "strPersonList for REG event",

             REGlist->seq_no, strPersonList);

     error_notify(__FILE__, __LINE__,errmsg, NOTIFY_FATAL);

     /* the event should be BOOMed, but can't be parsed. */

     shutdown_primary();

}

 

if( verbose_level >= 10 ) {

    sprintf(errmsg,

            "person_no list for patient_id %s: %s",

           strPID_patient_id, strPersonList);

    error_notify(__FILE__, __LINE__,errmsg, NOTIFY_UPDATE);

}

 

/* get all the patient identifiers related to each person_no */

if (get_BOOM_pat_id()==0) {

 

    if( verbose_level >= 10 ) {

        error_notify(__FILE__, __LINE__,

                     "No related idrs found, returning only source to BOOST",

                     NOTIFY_UPDATE);

    }

 

    if(strPersonList)

       free(strPersonList);

    if(strPatIDList)

       free(strPatIDList);

    return(REGlist);

}

 

/* remove duplicates from the patient_id list    */

if ( comma_del_sort_u(strPatIDList) != 0) {

     sprintf(errmsg,

            "%s %s %d \nstrPatIDList: %s",

            "comma_del_sort_u failed parsing",

            "strPatIDList for REG event",

             REGlist->seq_no, strPatIDList);

     error_notify(__FILE__, __LINE__,errmsg, NOTIFY_FATAL);

     /* the event should be BOOMed, but can't be parsed. */

     shutdown_primary();

}

 

if( verbose_level >= 10 ) {

    sprintf(errmsg, "patient_idr list: %s",strPatIDList);

    error_notify(__FILE__, __LINE__,errmsg, NOTIFY_UPDATE);

}

 

/* create a msg_list_t of stub A31's for each patient identifiers */

BOOMlist = (msg_list_t *) create_BOOM_list(REGlist);

 

if(strPersonList)

    free(strPersonList);

if(strPatIDList)

    free(strPatIDList);

 

return(BOOMlist);

 

}/********* end of hl7_boom ************************************************/