****************************************************************************************************
*                                           PROGRAM OVERVIEW
****************************************************************************************************
*
* PROGRAM: createlibref.sas  
* Created (mm/dd/yyyy): 11/28/2017
*
*--------------------------------------------------------------------------------------------------
* PURPOSE: This macro creates concatenated libref from a list of DPs and a file path,
*	automatically defaults to most recent version, and checks for the existence of each folder path 
*                                        
*  Program inputs:                                                                                   
*  	-
* 
*  Program outputs:                                                                                                                                       
*  	-
* 
*  PARAMETERS: 
*   - dplist: list of DPs separated by a space
*   - dpinfofile: file containing list of DPs and optional path
*   - dataroot: location of /data folder in the standard structure /data/[version]/[dp]/msoc/ 
*   - signaturefile: signature file from which to extract DP metadata            
*
*  Programming Notes:                                                                                
*                                                                           
*
*--------------------------------------------------------------------------------------------------
* CONTACT INFO: 
*  Sentinel Coordinating Center
*  info@sentinelsystem.org
*
***************************************************************************************************;

%macro createlibref(dplist=,
                    dpinfofile = , 
	    		    dataroot = ,
	   			    signaturefile = );

	**********************************************************
	macro %dynamiclibref automatically creates libnames for
	each DP based on K:/Sentinel folder structure 
	*********************************************************;
	%macro dynamiclibref(dp_list=);

		filename root "&dataroot.";
		/*Retrieve each version*/
		data files_and_folders;
			length name $50;
			drop rc did i;
			did=dopen("root");
			if did > 0 then do;
				do i=1 to dnum(did);
					name=upcase(dread(did,i));
					output;
				end;
				rc=dclose(did);
			end;
			else put 'Could not open directory';
		run;

		/*Defensive coding*/
		proc sort data=files_and_folders; 
			by descending name; 
		run; 

		/*Put name of versions into macro variable*/
		proc sql noprint;
			select lowcase(name) into: versions separated by ' '
			from files_and_folders
			where substr(upcase(name),1,1) in ('V', 'B', 'T')
			order by case substr(upcase(name),1,1)
                     when 'V' then 3
                     when 'B' then 2
                     when 'T' then 1
                     else .
                     end desc,
                     name desc;
		quit;
		%put &versions;

		/*For each DP, confirm the existence of the directory. Only include directories that exist in the final concatenated libname*/
        %let dp_list = %lowcase(&dp_list);
		%let DpCnt = %sysfunc(Countw(&dp_list)); /*Number of DPs to loop*/
		%let VerCnt = %sysfunc(Countw(&versions)); /*Number of versions to loop*/

		%do a = 1 %to &DpCnt;
			%let DPSITEID = %scan(&dp_list,&a); /*Current DP*/
					
			/*reset in_version counter*/
			%let in_version = ;

			%do b = 1 %to &VerCnt;
				%let CurrVer = %scan(&versions,&b); /*Current version*/
				/*does directory exist for current version?*/
				%let dir = &dataroot./&CurrVer./&DPSITEID./msoc/;
					
				%let rc = %sysfunc(filename(fileref,&dir)) ;
				%if %sysfunc(fexist(&fileref)) %then %let in_version = &in_version &CurrVer;
				%else %put NOTE: The directory "&dir" does not exist ;				
			%end;
			%put The libname for &DPSITEID contains the following Package Versions: &in_version;

			%if %length(&in_version) = 0 %then %do;
				%put WARNING: There are no valid directories for DP="&DPSITEID." Check for the existence of this DP directory or designate a bypass directory path;
			%end;
			%else %do;
				/*Loop through each valid directory to create concatenated libname*/
				%let DirCnt = %sysfunc(Countw(&in_version)); /*Number of versions to include in libname*/	
				%let VerList = ;
				%do c = 1 %to &DirCnt;
					%let CurrDir = %scan(&in_version,&c); 
						%let &DPSITEID&c = &dataroot.&CurrDir./&DPSITEID./msoc/.;
						/*assign final concatenated libname*/
						%if &c = 1 %then %do;
							libname &DPSITEID ("&&&DPSITEID.&c.") access=readonly;
						%end;
						%else %do;
							libname &DPSITEID&c "&dataroot.&CurrDir./&DPSITEID./msoc/.";
							libname &DPSITEID (&DPSITEID &&DPSITEID.&c.) access=readonly;
						%end;
				%end;			
						
				/*Update signature file with VersionID*/
				%if "&signaturefile" ne "" %then %do;
				%if %sysfunc(exist(&DPSITEID..&signaturefile.)) %then %do;
					data _signature; set &DPSITEID..&signaturefile.; 
						format DP $6.;
						DP = "&DPSITEID."; 	
						where upcase(var) in ('VERID', 'REQID', 'PROJID', 'WPTYPE', 'WPID', 'DPID', 'MPVER', 'DPMINDATE', 'DPMAXDATE');
					run;	

					proc transpose data = _signature out = _signature (drop = _NAME_ rename =(col1 = ReqID 
                                                                                              col2 = PROJID
                                                                                              col3 = WPTYPE
                                                                                              col4 = WPID
                                                                                              col5 = DPID
                                                                                              col6 = DPversion 
                                                                                              col7 = QRPversion
																							  col8 = DPMINDATE 
                                                                                              col9 = DPMAXDATE));
						by DP;
						var value;
					run;

					proc append data=_signature base=dpsignature force; run;

					proc datasets nowarn noprint lib=work; delete _signature; quit;
				%end;
				%else %put WARNING: (Sentinel) Signature file for "&DPSITEID." does not exist;
				%end;
			%end;
		%end;
	%mend dynamiclibref;

	***************************************************************
	macro %bypass_autoversion uses an input file to assign libnames
	***************************************************************;
	%macro bypass_autoversion();

		%macro wrapper();
    		%global DPCOMMALIST;
    		%let countvars = %sysfunc(Countw(%quote(&DPLIST.)));
    		%do c = 1 %to &countvars.;
    			%let word = %scan(%quote(&DPLIST),&c.);
    				%if &c. = 1 %then %do;
    					%let DPCOMMALIST = "&word.";
    				%end;
    				%else %do;
    					%let DPCOMMALIST = &DPCOMMALIST. , "&word.";
    				%end;
    		%end;
		%mend;
		%wrapper();
	
		/*Put list of DPs we are bypassing into macro variable*/

		%let bypassDPList = ;
		%let BypassCnt = 0; 

		proc sql noprint;
			select DP into: bypassDPlist separated by ' '
			from dppath
			where lowcase(DP) in (&DPCOMMALIST.);
		quit;

		/*Loop through list and assign correct libname */
		%if %length(&bypassDPList) > 0 %then %let BypassCnt = %sysfunc(Countw(&bypassDPlist)); 
		%let ModDPList = %lowcase(&DPLIST);

		%do cnt = 1 %to &BypassCnt;
			%let DPSITEID = %lowcase(%scan(&bypassDPlist,&cnt));
			data _null_;
				set dppath;
				call symputx("PATH",strip(path));
				where lowcase(DP) = "&DPSITEID.";
			run;		
            
            %if %soc_dirExist(&path.) %then %do;
			  /* Prevent library path from being written to log */
			     proc printto log=log;
			     run;
			
			     libname &DPSITEID "&PATH." access=readonly;
				 
			  /* Resume writing to log */
				 proc printto log="&OUTPUT.qrp_report_log&reportid..log";
				 run;
            %end;
            %else %do;
                %put ERROR: (Sentinel) Path specified in DPINFOFILE for &DPSITEID. does not exist. Package will abort.;
                %abort;
            %end;

			/*Update signature file with VersionID*/
			%if "&signaturefile" ne "" %then %do;
			%if %sysfunc(exist(&DPSITEID..&signaturefile.)) %then %do;
				data _signature; set &DPSITEID..&signaturefile.; 
					format DP $6.;
					DP = "&DPSITEID."; 	
				    where upcase(var) in ('VERID', 'REQID', 'PROJID', 'WPTYPE', 'WPID', 'DPID', 'MPVER', 'DPMINDATE', 'DPMAXDATE');
					run;	

					proc transpose data = _signature out = _signature (drop = _NAME_ rename =(col1 = ReqID 
                                                                                              col2 = PROJID
                                                                                              col3 = WPTYPE
                                                                                              col4 = WPID
                                                                                              col5 = DPID
                                                                                              col6 = DPversion 
                                                                                              col7 = QRPversion
																							  col8 = DPMINDATE 
                                                                                              col9 = DPMAXDATE));
						by DP;
						var value;
					run;

				proc append data=_signature base=dpsignature force; run;

				proc datasets nowarn noprint lib=work; delete _signature; quit;
			%end;
			%else %put WARNING: (Sentinel) Signature file for "&DPSITEID." does not exist;
			%end;

			/*Modify DPlist if additional DPs will be assigned libname automatically*/
			%if %eval(&BypassCnt) ne %eval(&NUM_DP) %then %do;
				%let ModDPList = %sysfunc(compbl(%sysfunc(transtrn(&ModDPList, &DPSITEID,))));
			%end;
		%end;

		%if %eval(&BypassCnt) ne %eval(&NUM_DP) %then %do;
			%put &ModDPList;
			%dynamiclibref(dp_list = &ModDPList);
		%end;
	%mend bypass_autoversion;

	***********
	macro calls
	***********;

	%let num_dp = %sysfunc(countw(&dplist));
    %let dplist = %lowcase(&dplist);

	%if %length(&dpinfofile.)> 0 %then %do;

        /*Create file with list of DPs where path is not missing*/
        data dppath;
            set &dpinfofile.(where=(missing(path)=0));
        run;

		%let nobs=0;
		%if %sysfunc(exist(dppath))=1 and %length(dppath) ne 0 %then %do;
			data _null_;
			dsid=open("dppath");
			call symputx("NOBS",attrn(dsid,"NLOBS"));
			run;
		%end;	

		%if %eval(&nobs.>0) %then %do;
			%bypass_autoversion();
		%end;
		%else %do;
			%dynamiclibref(dp_list = &dplist);
		%end;
	%end;
	%else %do;
		%dynamiclibref(dp_list = &dplist);
	%end;

    *save signature file and merge in maskedDP info if available;
    %if "&signaturefile" ne "" %then %do;
        %let nobs=0;
	    %if %sysfunc(exist(dpsignature))=1 %then %do;
            data _null_;
            dsid=open("dpsignature"); 
            call symputx("NOBS",attrn(dsid,"NLOBS"));
			run;
		%end;	

        %if %eval(&nobs.>0) %then %do;
            %let nobs=0;
    	    %if %sysfunc(exist(output.dpinfo))=1 %then %do;
                data _null_;
                dsid=open("output.dpinfo"); 
                call symputx("NOBS",attrn(dsid,"NLOBS"));
    			run;
    		%end;	
            %if %eval(&nobs.>0) %then %do;
                proc sql noprint undo_policy=none;
                    create table output.dpinfo as
                    select distinct y.maskedID,
                                    x.* 
                    from output.dpinfo as y
                    full join dpsignature as x
                    on x.dp = y.dp;
                quit;
            %end;
            %else %do;
                data output.dpinfo;
                    set dpsignature;
                run;
            %end;
        %end;
    %end;

	*clean-up;
	proc datasets nowarn noprint lib=work;
		delete files_and_folders list_dp dppath dpsignature;
	quit;

%mend createlibref;