/*** HELP START ***//*
 
## >>> `%splitDSIntoBlocks()` macro: <<< <a name="splitdsintoblocks-macro"></a> #######################  

The splitDSIntoBlocks() macro allows to split the `set` dataset into blocks 
of size `blockSize` in datasets: `prefix1` to `prefixN`.

The last dataset may have less observations then the `blockSize`.

Macro covers `BASE` engine (`v9`, `v8`, `v7`, `v6`) and `SPDE` engine datasets.

See examples below for the details.

### SYNTAX: ###################################################################

The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~sas
%splitDSIntoBlocks(
    blockSize
  <,set>
  <,prefix>
)
~~~~~~~~~~~~~~~~~~~~~~~

**Arguments description**:

1. `blockSize`   - *Required*, the size of the block of data,
                   in other words number of observations in 
                   one block of split data.
                   Block size must be positive integer.

2. `set`         - *Required/Optional*, the name of the dataset to split.
                   If empty then `&syslast.` is used.

3. `prefix`      - *Required/Optional*, the name-prefix for new datasets.
                   If missing then set to `part`. 

---

*//*** HELP END ***/

%macro splitDSIntoBlocks(
 blockSize
,set
,prefix
);
  %if %superq(prefix)= %then
    %do;
      %let prefix=part;
    %end;
  %if %superq(set)= %then
    %do;
      %let set=&syslast.;
    %end;

  /* verify engine of input dataset */
  /* DO */
  %let syslast=&set.;
  %let set=&syslast.;
  proc sql noprint;
    create table &prefix.0 as
    select distinct engine
    from DICTIONARY.LIBNAMES
    where libname=scan(symget('set'),1,".");
  quit;
  /* END */
  /* ------------------------------ */

  /* execute splitting process */
  /* DO */
  data _null_;
    blockSize = int(symgetn('blockSize'));
    if blockSize < 1 then 
      do; 
        put "ERROR: [&sysmacroname.] Block size must be positive integer!" blockSize=; 
        stop; 
      end;

    parts = ceil(NobsInSource/blockSize);
    if parts < 1 then 
      do; 
        put "ERROR: [&sysmacroname.] Number of parts must be positive integer!" parts=; 
        stop; 
      end;

    length first last $ 32;
    do until (EOF);
      set &prefix.0 END=EOF;
      if engine in ('V9' 'V8' 'V7' 'V6' 'BASE') then 
        do;
          first="FIRSTOBS=";
          last ="OBS=";
          EOF  =42;
          supportedEngine=1;
        end;
      if engine in ('SPDE') then 
        do;
          first="STARTOBS=";
          last ="ENDOBS=";
          EOF  =42;
          supportedEngine=1;
        end;
    end;

    if supportedEngine then
      do part = 1 to parts;
        call execute(cats(
        "data &prefix.",part,";",
        "  set &set.(",first,(part-1)*blockSize+1,last,part*blockSize,");",
        "run;"
        ));
      end;
    else 
      put "ERROR: [&sysmacroname.] Library Engine is not supported!"

    stop;
    set &set.(drop=_all_) nobs=NobsInSource;
  run;
  /* END */
  /* ------------------------- */

  /* clenup */
  proc delete data=&prefix.0;run;
  /* ------ */
%mend splitDSIntoBlocks;


/*
Error handling test:

%splitDSIntoBlocks(3,blablabla)
%splitDSIntoBlocks(big)
*/


/*** HELP START ***//*
 
### EXAMPLES AND USECASES: ####################################################

**EXAMPLE 1.** Split `sashelp.class` into 5 elements datasets ABC1 to ABC4:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
  %splitDSIntoBlocks(5,sashelp.class,ABC)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


**EXAMPLE 2.** By default splits the `_last_` dataset into `part1` to `partN` datasets:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
  data lastData;
    set sashelp.cars;
  run;

  %splitDSIntoBlocks(123)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


**EXAMPLE 3.** Works with `SPDE` engine too:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
  options dlcreatedir;
  libname test "%sysfunc(pathname(work))/testSPDE";
  libname test;
  libname test SPDE "%sysfunc(pathname(work))/testSPDE";

  data test.test;
    set sashelp.cars;
  run;

  %splitDSIntoBlocks(100,test.test,work.spde)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

---

*//*** HELP END ***/

/**###################################################################**/
/*                                                                     */
/*  Copyright Bartosz Jablonski, since 2023 onward.                    */
/*                                                                     */
/*  Code is under the MIT license. If you want - you can use it.       */
/*  But it comes with absolutely no warranty whatsoever.               */
/*  If you cause any damage or something - it will be your own fault.  */
/*  You've been warned! You are using it on your own risk.             */
/*  However, if you decide to use it don't forget to mention author.   */
/*  Bartosz Jablonski (yabwon@gmail.com)                               */
/*                                                                     */
/**###################################################################**/


