****************************************************************************************************
*                                           PROGRAM OVERVIEW
****************************************************************************************************
*
* PROGRAM: ms_pov1dose.sas  
* Created (mm/dd/yyyy): 06/01/2021
*
*--------------------------------------------------------------------------------------------------
* PURPOSE:
*   This program will find all index dates that meet a cumulative and/or current filled daily
*   dose criteria
*
*  Program inputs:                                                                                   
*   -Dataset with eligible index dates
*   -Dataset with all claims 
* 
*  Program outputs:                                                                                                                                       
*   -Dataset with eligible index dates meeting the dose criteria  
*   -Dataset with index dates not meeting the dose criteria
* 
* PARAMETERS:
*   -InFile         = Name of the dataset with eligible index dates
*   -ClaimFile      = Name of the dataset with all claims
*   -ExclIndexFile  = Name of the dataset with index dates excluded due to not meeting criteria
*   -OutFile        = Name of the output dataset meeting the dose criteria
*   -mincumdose     = Minimum prior cumulative dose
*   -maxcumdose     = Maximum prior cumulative dose
*   -mincfdd        = Minimum current filled daily dose
*   -maxcfdd        = Maximum current filled daily dose
*   -lookback       = Number of days prior to index date to evaluate mincumdose/maxcumdose
*   -RxSupVar       = Variable holding dispensing RX Days Supply
*
*  Programming Notes:                                                                                
*   - Cumulative dose is evaluated in the window [-lookback, indexdate -1]                                                            
*
*--------------------------------------------------------------------------------------------------
* CONTACT INFO: 
*  Sentinel Coordinating Center
*  info@sentinelsystem.org
*
*--------------------------------------------------------------------------------------------------
***************************************************************************************************;

%macro ms_pov1dose(InFile=,
                   ClaimFile=, 
                   ExclIndexFile=, 
                   OutFile=, 
                   Mincumdose=, 
                   Maxcumdose=, 
                   Mincfdd=, 
                   Maxcfdd=, 
                   Lookback=,
                   RxSupVar=);

    %put =====> MACRO CALLED: ms_pov1dose;

    /*----------------------------------------------------------------------------------------------------------
      Cumulative Dose
    ----------------------------------------------------------------------------------------------------------*/

    %if &mincumdose. ne . | &maxcumdose. ne . %then %do;
	
        /*----------------------------------------------------------------------------------------------------
        Select claims in lookback window - cumulative dose
        ----------------------------------------------------------------------------------------------------*/

        proc sql noprint;
            create table _claimsinlookback as
            select in.patid,
                   in.adate,
                   claim.adate as claimadate,
                   claim.expiredt as claimexpiredt,
                   claim.cumdose,
                   claim.&rxsupvar.
            from &infile. as in,
                 &claimfile. as claim
            where in.patid = claim.patid and %MS_PeriodsOverlap(period1=in.Adate-&lookback. in.Adate-1,
                                                                period2=claim.adate claim.ExpireDt);
        quit;

        /*----------------------------------------------------------------------------------------------------
        Remove dose occuring outside the looback window
        ----------------------------------------------------------------------------------------------------*/

        data _claimsinlookback1;
        	set _claimsinlookback;

            ToDeductBf=0;
            ToDeductAf=0;

        	if claimadate < adate-&lookback. then do; *Starts before lookback period;
                ToDeductBf=adate-&lookback.-claimadate;
            end; 
        	if claimexpiredt > adate-1 then do;   *Ends after lookback period;
                ToDeductAf=claimexpiredt-adate-1;
            end;
        
            if cumdose > 0 then cumdose=cumdose *(&rxsupvar.-sum(ToDeductBf,ToDeductAf))/&rxsupvar.; 
            drop ToDeductBf ToDeductAf &rxsupvar. claimadate claimexpiredt;
        run;

        /*----------------------------------------------------------------------------------------------------
        Compute total cumulative dose in lookback window and output all index dates meeting/not meeting criteria
        ----------------------------------------------------------------------------------------------------*/

    	proc means data=_claimsinlookback1 noprint nway;
    		var cumdose;
    	    class patid adate;
    	    output out=_claimsdose sum=;
    	run;

    	data _claimsmeetingdose(drop=attrition_reason) _doseattrition1(keep=patid adate attrition_reason);
        	merge _claimsdose(in=a) &infile.(in=b keep=patid adate);
            by patid adate;

        length attrition_reason 3;
        attrition_reason = 1; /*cumulative dose*/

        if a and b then do;
        	%if &mincumdose. ne . AND &maxcumdose. ne . %then %do;
        		if round(cumdose,1)>=&mincumdose. AND round(cumdose,1)<=&maxcumdose. then output _claimsmeetingdose;
        		else output _doseattrition1;
        	%end;
        	%else %if &mincumdose. ne . %then %do;
        		if round(cumdose,1)>=&mincumdose. then output _claimsmeetingdose;
        		if round(cumdose,1)<&mincumdose. then output _doseattrition1;
        	%end;
        	%else %if &maxcumdose. ne . %then %do;
        		if round(cumdose,1)<=&maxcumdose. then output _claimsmeetingdose;
        		if round(cumdose,1)>&maxcumdose. then output _doseattrition1;
        	%end;
        end;
        else if b and not a then do;
        	%if &mincumdose. ne . AND &maxcumdose. ne . %then %do;
                /*dosen't meet mincumdose*/
                output _doseattrition1;
        	%end;
        	%else %if &mincumdose. ne . %then %do;
                output _doseattrition1;
        	%end;
        	%else %if &maxcumdose. ne . %then %do;
        		/*index claim always meets maxcumdose*/
        	%end;
        end;
    	run;

    	proc sort data=_claimsmeetingdose nodupkey;
    	by _ALL_;
    	run;
    	proc sort data=_doseattrition1 nodupkey;
    	by _ALL_;
    	run;

    	%if &mincumdose. = . %then %do;
    	    data &outfile.;
    	         if 0 then set _doseattrition1(keep=patid adate);
    	         declare hash m(dataset:"_doseattrition1");
    	         m.definekey('patid', 'adate');
    	         m.definedone();

    			do until (eof);
    				set &infile. end=eof;
    				if m.find() ne 0 then output &outfile.;
    			end;
    	    run;
    	%end;
    	%else %do;
    	    data &outfile.;
    	         if 0 then set _claimsmeetingdose(keep=patid adate);
    	         declare hash m(dataset:'_claimsmeetingdose');
    	         m.definekey('patid', 'adate');
    	         m.definedone();

    			do until (eof);
    				set &infile. end=eof;
    				if m.find() = 0 then output &outfile.;
    			end;
    	    run;
    	%end;

        proc datasets library=work nolist nowarn;
            delete _claimsinlookback _claimsinlookback1 _claimsmeetingdose;
        quit;

    %end; /*cumulative dose*/

    /*----------------------------------------------------------------------------------------------------------
      Current Filled Daily Dose
    ----------------------------------------------------------------------------------------------------------*/
    %if &mincfdd. ne . | &maxcfdd. ne . %then %do;

        /*----------------------------------------------------------------------------------------------------
          Determine # of stockgroups - if >1 recompute cFDD on index date
        ----------------------------------------------------------------------------------------------------*/
        proc sql noprint;
            select distinct stockgroup into :defstocklist separated by ' '
            from infolder.&cohortcodes.(where=(indexcriteria='DEF' and group = "&itgroup."));
        quit;

        %if %eval(%sysfunc(countw(%str(&defstocklist.), ' '))>1) %then %do;
            %let sameday_supp_oper=sum;
            %let sameday_amt_oper=sum;
            %if &unique_stock_params >=1 %then %do;
                data _null_;
                    set STOCKPILE_NONCOVAR;
                    where group="&ITGROUP" and stockgroup = "%scan(%str(&defstocklist.), 1)";
                    /*need to determine whether to max rxsup*/
                    if lowcase(strip(substr(SameDay,1,1))) = 'x' then call symputx("sameday_supp_oper",'max');
                run;
            %end;

            /*Aggregate same day claims - modified from ms_stockpiling*/
            proc sql noprint;
                create table _claimsinlookback as
                select d.patid,
                       d.adate,
                       (c.strength*c.&rxamtvar.)/c.&rxsupvar. as cfdd
                from
                    (select b.*
                            ,a.strength
                    from (select patid
    		                    ,adate
                                ,sum(strengthamt)/sum(&rxamtvar.) as strength
                          from (select patid
                                       ,(strength * &rxamtvar.) as strengthamt
             			               ,&rxamtvar.
    						           ,adate
                                from &claimfile.)
                                group by patid, adate) as a
                         inner join
                                (select patid
                                        ,adate
             	                        ,&sameday_supp_oper.(&rxsupvar.) as &rxsupvar.
             	                        ,&sameday_amt_oper.(&rxamtvar.) as &rxamtvar.
                                from &claimfile.
                                group by patid, adate) as b
                        on a.adate = b.adate and a.patid = b.patid) as c
                inner join &infile. as d
                on c.patid = d.patid and c.adate = d.adate;
            quit;
        %end;
        %else %do;
            proc sql noprint;
                create table _claimsinlookback as
                select in.patid,
                       in.adate,
                       (claim.strength*claim.&rxamtvar.)/claim.&rxsupvar. as cfdd
                from &infile. as in,
                     &claimfile. as claim
                where in.patid = claim.patid and in.adate = claim.adate;
            quit;
        %end;

    	data _claimsmeetingdose(drop=attrition_reason) _doseattrition2(keep=patid adate attrition_reason);
    	   set _claimsinlookback;
            length attrition_reason 3;

        	%if &mincfdd. ne . AND &maxcfdd. ne . %then %do;
        		if round(cfdd,1)>=&mincfdd. AND round(cfdd,1)<=&maxcfdd. then do; 
                    output _claimsmeetingdose;
                end;
        		else do;
                    if round(cfdd,1)<&mincfdd. then attrition_reason = 2; /*does not meet mincfdd*/
                    else if round(cfdd,1)>&maxcfdd. then attrition_reason = 3; /*does not meet maxcfdd*/
                    output _doseattrition2;
                end;
        	%end;
        	%else %if &mincfdd. ne . %then %do;
                attrition_reason = 2;
        		if round(cfdd,1)>=&mincfdd. then output _claimsmeetingdose;
        		else output _doseattrition2;
        	%end;
        	%else %if &maxcfdd. ne . %then %do;
                attrition_reason = 3;
        		if round(cfdd,1)<=&maxcfdd. then output _claimsmeetingdose;
        		else output _doseattrition2;
        	%end;
    	run;

        proc sort data=_claimsmeetingdose nodupkey;
    	by _ALL_;
    	run;
    	proc sort data=_doseattrition2 nodupkey;
    	by _ALL_;
    	run;

        data &outfile.;
             if 0 then set _claimsmeetingdose(keep=patid adate);
             declare hash m(dataset:'_claimsmeetingdose');
             m.definekey('patid', 'adate');
             m.definedone();

    		do until (eof);
    			set &infile. end=eof;
    			if m.find() = 0 then output &outfile.;
    		end;
        run;

        proc datasets library=work nolist nowarn;
            delete _claimsinlookback _claimsmeetingdose;
        quit;

    %end; /*current filled daily dose*/

    /*----------------------------------------------------------------------------------------------------------
      Create final dataset containing excluded index dates
    ----------------------------------------------------------------------------------------------------------*/
    data &ExclIndexFile.;
        set _doseattrition:;
    run;

    proc datasets library=work nolist nowarn;
        delete _doseattrition:;
    quit;

    %put NOTE: ********END OF MACRO: ms_pov1dose ********;

%mend ms_pov1dose;