/**
  @file
  @brief dynamic where clause creation
  @details Generates a where clause based on the following inputs:

  @li The filter_RK (if provided)
  @li The mode (if EDIT then filter for current records)
  @li The user permissions (Row Level Security)

  This macro should be used whenever surfacing data to the user.  Note that
  it is not possible to %include filerefs directly in a proc sql where clause.
  The workaround is to use a data step view.

  Note - DCLIB should be assigned.

  @param [in] mode The mode.  If EDIT, then current rows are returned. Valid
    Values:
    @li EDIT
    @li VIEW
    @li DLOAD - used in getrawdata
    @li ULOAD - used by stagedata.sas to prevent restricted rows being submitted

  @param [in] libds The target libref.dataset to which the filter will apply.
  @param [in] filter_rk= (-1) The filter_rk, if available
  @param [in] dclib= The libref of the DC control tables
  @param [out] outref= The output fileref to create (containing the filter)
  @param [out] outds= (work.query) The query dataset (if filter_rk supplied)

  <h4> SAS Macros </h4>
  @li mf_fmtdttm.sas
  @li mf_getuser.sas
  @li mf_getuniquefileref.sas
  @li mf_getuniquename.sas
  @li mf_nobs.sas
  @li mp_abort.sas
  @li mp_filtergenerate.sas
  @li mpe_getgroups.sas

  @version 9.3
  @author 4GL Apps Ltd
  @copyright 4GL Apps Ltd.  This code may only be used within Data Controller
    and may not be re-distributed or re-sold without the express permission of
    4GL Apps Ltd.
**/

%macro mpe_filtermaster(mode,libds,
  dclib=,
  filter_rk=-1,
  outref=0,
  outds=work.query
);

%put &sysmacroname entry vars:;
%put _local_;

%let mode=%upcase(&mode);
%let libds=%upcase(&libds);


%mp_abort(iftrue= (
    &mode ne EDIT and &mode ne VIEW and &mode ne DLOAD and &mode ne ULOAD
  )
  ,mac=&sysmacroname
  ,msg=%str(Invalid MODE: &mode)
)
%mp_abort(iftrue= (&outref = 0)
  ,mac=&sysmacroname
  ,msg=%str(Please provide a fileref!)
)
%mp_abort(iftrue= (&syscc ne 0)
  ,mac=&sysmacroname
  ,msg=%str(syscc=&syscc)
)

filename &outref temp;

/* ensure outputs exist */
data _null_;
  file &outref;
  put ' ';
run;
data &outds;
  set &dclib..mpe_filtersource;
  stop;
run;

/**
  * Deal with FILTER_RK first
  */
%if &filter_rk gt 0 %then %do;

  data _null_;
    file &outref;
    put '( '@@;
    set &dclib..mpe_filteranytable(where=(filter_rk=&filter_rk));
    call symputx('filter_hash',filter_hash,'l');
  run;

  proc sort data=&dclib..mpe_filtersource(where=(filter_hash="&filter_hash"))
    out=&outds(drop=filter_hash filter_line processed_dttm);
    by filter_line;
  run;
  %mp_filtergenerate(&outds,outref=&outref)

%end;

/* Now filter for current records if the MODE is EDIT or DLOAD */
%local varfrom varto;
%let varfrom=0;

proc sql;
select coalescec(var_txfrom,'0'), var_txto into: varfrom,:varto
  from &dclib..MPE_TABLES
  where &dc_dttmtfmt. lt tx_to
    and libref="%scan(&libds,1,.)" and dsn="%scan(&libds,2,.)";

%put &=varfrom;
%put &=varto;

/**
  * Check if the date variables were mentioned in the query
  * This is a trigger for serving a historical view instead of current
  * we skip this part when checking an ULOAD as there are no date vars
  */
%if &varfrom ne 0 and (&mode=EDIT or &mode=DLOAD) %then %do;
  %local validityvars;
  proc sql;
  select count(*) into: validityvars
    from &outds
    where variable_nm in ("&varfrom","&varto");
  %if &validityvars=0 %then %do;
    data _null_;
      file &outref mod;
      length filter_text $32767;
      varfrom=symget('varfrom');
      varto=symget('varto');
      filter_text=catx(' ',
        '("%sysfunc(datetime(),',"%mf_fmtdttm()",')"dt <',varto,')'
      );
      if &filter_rk > 0 then put 'AND ' filter_text;
      else put filter_text;
    run;
  %end;
%end;

/**
  * Now do Row Level Security based on the MPE_ROW_LEVEL_SECURITY table
  */

/* first determine users group membership */
%mpe_getgroups(user=%mf_getuser(),outds=work.groups)
%local admin_check;
proc sql;
select count(*) into: admin_check
  from work.groups
  where groupname="&mpeadmins";

%put &sysmacroname: &=admin_check &=mpeadmins;
%if &admin_check=0 %then %do;
  %local scopeval;
  %if &mode=DLOAD %then %let scopeval=VIEW;
  %if &mode=ULOAD %then %let scopeval=EDIT;
  %else %let scopeval=&mode;
  /* extract relevant rows */
  %local rlsds;
  %let rlsds=%mf_getuniquename();
  proc sql;
  create table work.&rlsds as
    select rls_group,
      rls_group_logic as group_logic,
      rls_subgroup_logic as subgroup_logic,
      rls_subgroup_id as subgroup_id,
      rls_variable_nm as variable_nm,
      rls_operator_nm as operator_nm,
      rls_raw_value as raw_value
    from &mpelib..mpe_row_level_security
    where &dc_dttmtfmt. lt tx_to
      and rls_scope in ("&scopeval",'ALL')
      and upcase(rls_group) in (select upcase(groupname) from work.groups)
      and rls_libref="%scan(&libds,1,.)"
      and rls_table="%scan(&libds,2,.)"
      and rls_active=1
    order by rls_group,rls_subgroup_id;
  %if &sqlobs>0 %then %do;
    /* check if we currently have filter or not */
    data ;
      infile &outref end=eof;
      input;
      if _n_=1 and eof and cats(_infile_)='' then newfilter=1;
      output;
      stop;
    run;
    data _null_;
      set &syslast;
      file &outref mod;
      if newfilter=1 then put '(';
      else put 'AND (';
    run;

    /* loop through and apply filters for each group membership */
    %local fref ds;
    %let fref=%mf_getuniquefileref();
    %let ds=%mf_getuniquename();

    proc sql noprint;
      select distinct rls_group into : group1 -
      from work.&rlsds;

    %do i=1 %to &sqlobs;
      data work.&ds;
        set work.&rlsds;
        where rls_group="&&group&i";
        drop rls_group;
      run;
      %mp_filtergenerate(&ds,outref=&fref)
      data _null_;
        infile &fref;
        file &outref mod;
        input;
        if &i>1 and _n_=1 then put '  OR ';
        put _infile_;
      run;
    %end;
    data _null_;
      file &outref mod;
      put ')';
    run;
  %end; /* &sqlobs>0 */
  %else %do;
    %put &sysmacroname: no matching groups;
    data _null_;
      set work.groups;
      putlog (_all_)(=);
    run;
  %end;
  %mp_abort(iftrue= (&syscc>0)
    ,mac=&sysmacroname
    ,msg=%str(Row Level Security Generation Error)
  )
%end; /* &admin_check=0  */

%put leaving &sysmacroname with the following query:;

%local empty;
%let empty=0;
data _null_;
  infile &outref end=eof;
  input;
  putlog _infile_;
  if _n_=1 and eof and cats(_infile_)='' then do;
    put '1=1';
    call symputx('empty',1,'l');
  end;
run;
%if &empty=1 %then %do;
  data _null_;
    file &outref;
    put '1=1';
  run;
%end;

%mend mpe_filtermaster;
