FOCUS AREAS

Statistics and Operations Research: Examples

Source Code for the Forecast Command Builder

/* Copyright(c) 2000 by SAS Institute Inc., Cary, NC USA */
/* FORCCMD.SCL:  Source code for Forecast Command Builder*/
/* application.  This code can be copied for use as a    */
/* demo or an example. To run the application, you do    */
/* not need source code.  Use the command                */
/* AF C=SASHELP.FORCAST.FORCCMD.FRAME.                   */
/* To build the application, copy FORCCMD.FRAME from the */
/* forcast catalog provided in the sashelp library with  */
/* SAS/ETS software.  Copy this source code to an SCL    */
/* catalog entry in the same catalog and with the same   */
/* name as the frame entry, then open the frame entry    */
/* and compile.                                          */
/* Other frames called by this program:                  */
/* sashelp.etstool.interval.frame,                       */
/* sashelp.forcast.forcsser.frame,                       */
/* sashelp.forcast.forccout.frame.                       */
/* Revised 8/29/2000 for release 8.2, including the      */
/* following enhancements:                               */
/* o Supports new FORECAST command arguments diag=yes/no,*/
/*   keep=n, and audit=yes/no.                           */
/* o Multiple series can be selected from a data set.    */
/*   When added to command list, a separate FORECAST     */
/*   command is added for each series selected.          */
/* o Field validation added for several items.           */
/* o Automatic time id and interval detection.           */
/* o Uses interval.frame, which allows specification of  */
/*   exotic intervals.                                   */
/* o Graphics tab provides capability to create forecast */
/*   graphs for all series in batch, with optional output*/
/*   to a framed web page.                               */
/* o Individual forecast graphs can use either the new   */
/*   Time Series Plot class (forcgraf.frame, default),   */
/*   or the classic Graphics class (forccgrf.frame).     */

length cmdtext $ 200 btnname $ 8 critname fmtmsg $ 40 ;
length returnString $ 40 olddsn $ 41 sname gdatefmt $ 32;
length interval $80 answer $ 8 text $ 80 savlist $ 84;
length addtitle $ 100 level1 level3 $ 8 level2 $ 40;

init:

   /* Instantiate the SAS Data File Class. */
   dfile =
     instance(loadclass('sashelp.fsp.datafile.class'));

   /* Create lists. */

   dcl list mkeepsel=
       {'best', 'best 2','best 3','best 4','best 5',
        'best6 ','best 7','best 8','best 9','all'};

   dcl list mkeepnum=
       {'1','2','3','4','5','6','7','8','9','999'};

   dcl list entries={'FORECAST','AUTOFIT','MAIN','DEVMOD',
                     'VIEWMOD','VIEWSER',' ' };

   dcl list entlabels=
       { 'FORECAST - Unattended Forecasting',
         'AUTOFIT - Unattended Automatic Model Fitting',
         'MAIN - Time Series Forecasting Window',
         'DEVMOD - Develop Models Window',
         'VIEWMOD - Model Viewer Window',
         'VIEWSER - Series Viewer Window',
         'None (default is MAIN)'};

   dcl list confpu={'50','75','90','925','95','975','99'};

   dcl list horzpu =
     { '1','2','3','4','5','6','7','8','9','10','11','12'};

   varlist   = makelist();  * Variable information list;
   serlist   = makelist();  * List of variable names:labels for popup;
   selsers   = makelist();  * List of selected variables ;
   intervals = makelist();  * List of intervals/formats;
   stats     = makelist();  * List of statistics of fit;
   modcpu    = makelist();  * List of fit criteria for
                              popup;
   modcnames = makelist();  * List of names corresponding
                              to modcpu;
   cmdlist   = makelist();  * Command list;
   attrlist  = makelist();  * Attibute list for savelist
                              function;
   msglist   = makelist(1); * Used for messagebox function;

   /* Populate the intervals list */
   rc = fillist(
          'catalog', 'sashelp.etstool.interval.slist',
           intervals );
   intpopup = getniteml( intervals, 'interval_names' );

   /* Populate the model criterion popup list. */
   rc = fillist( 'catalog',
        'sashelp.forcast.fitstats.slist', stats );
   snames = getniteml( stats, 'statnames'  );
   slabels= getniteml( stats, 'statlabels' );
   sflags = getniteml( stats, 'statmax'    );
   do i=1 to listlen( snames );
      if getitemn( sflags, i ) >= 0
      then do;
             modcpu = insertc(
                    modcpu, getitemc( slabels, i ));
             modcnames = insertc (
                    modcnames, getitemc( snames, i ));
             end;
      end;

   modcpu    = insertc( modcpu,
               'None (default is Root Mean Square Error)', -1 );
   modcnames = insertc( modcnames, ' ', -1 );

   /* Initialize the refitopt radio box. */
   refitopt = 'Neither';

   /* Initially gray out delete btn on command list tab. */
   call notify( 'delete', '_gray_' );

   /* Set defaults. */
   entry = 'FORECAST';
   usediag = 1;
   audit   = 0;

   /* Initially gray the save button. */
   call notify( 'save', '_gray_' );

   /* Remember last selected data set. */
   olddsn = ' ';

   /* Instantiate etsscl class to for automatic */
   /* interval detection. */
   etsscl = instance( loadclass(
             'SASHELP.ETSSCL.ETSSCL.CLASS' ) );

   /* Set initial state of graph tab widgets */
   graphall = 0;
   call notify('graphcat', '_gray');
   call notify('makehtml', '_gray');
   graphcat = 'WORK.GSEG';
   datefrmt = 'as in dataset';
   gdatefmt = ' ';
   makehtml = 0;
   incldate = 0;
   incltime = 0;
   call notify('htmldir', '_gray');
   call notify('grfbrows', '_gray');
   call notify('htmbrows', '_gray');
   call notify('incldate', '_gray');
   call notify('incltime', '_gray');
   call notify('title2',   '_gray');
   call notify('datefrmt', '_gray');
   call notify('frmtctrl', '_gray');

return;  /* init */

main:
   if selser = '‹multiple›'
   then call notify('toolbar', '_gray',   'RUNCUR' );
   else call notify('toolbar', '_ungray', 'RUNCUR' );

   if listlen(cmdlist) < 1
   then call notify('toolbar', '_gray',   'RUNLIST' );
   else call notify('toolbar', '_ungray', 'RUNLIST' );
return; /* main */

term:
   call send( dfile, '_term_' );
   call send( etsscl, '_term_' );

   varlist   = dellist(varlist);
   serlist   = dellist(serlist);
   selsers   = dellist(selsers );
   intervals = dellist(intervals);
   entries   = dellist(entries);
   entlabels = dellist(entlabels);
   stats     = dellist(stats);
   modcpu    = dellist(modcpu);
   modcnames = dellist(modcnames);
   confpu    = dellist(confpu);
   horzpu    = dellist(horzpu);
   cmdlist   = dellist(cmdlist);
   attrlist  = dellist(attrlist);
   mkeepsel  = dellist(mkeepsel);
   mkeepnum  = dellist(mkeepnum);
   msglist   = dellist(msglist);
return;   /* term */

/****** Labeled blocks in alphabetical order *************/

audit:
   link buildcmd;
return;   /* audit */

buildcmd:
   /* Build the current command using current info. */
   cmdtext = 'FORECAST';
   if seldsn ^= _blank_
   then cmdtext = cmdtext || ' DATA=' || seldsn;

   if selser ^= _blank_
   then cmdtext = cmdtext || ' VAR=' || scan(selser,1,':');

   if seltid ^= _blank_
   then cmdtext = cmdtext || ' ID=' || scan(seltid,1,':');

   if selint ^= _blank_
   then cmdtext = cmdtext || ' INTERVAL=' || selint;

   if selproj ^= _blank_
   then cmdtext = cmdtext || ' PROJECT=' || selproj;

   if entry ^= _blank_
   then cmdtext = cmdtext || ' ENTRY=' || entry;

   if outdsn ^= _blank_
   then cmdtext = cmdtext || ' OUT=' || outdsn;

   if conflim ^= _blank_
   then cmdtext = cmdtext || ' CLIMIT=' || conflim;

   if horizon ^= _blank_
   then cmdtext = cmdtext || ' HORIZON=' || horizon;

   if critname ^= _blank_
   then cmdtext = cmdtext || ' STAT=' || critname;

   if upcase(refitopt) ^= 'NEITHER'
   then cmdtext = cmdtext || ' ' || refitopt;

   if modkeep ^= _blank_
   then cmdtext = cmdtext || ' KEEP=' || compress(modkeep);

   if ^usediag
   then cmdtext = cmdtext || ' DIAG=NO';

   if audit
   then cmdtext = cmdtext || ' AUDIT=YES';

   call notify( 'curcmd1', '_clear_' );
   call notify( 'curcmd2', '_clear_' );
   call notify( 'curcmd3', '_clear_' );
   call notify( 'curcmd4', '_clear_' );
   call notify( 'curcmd1', '_set_text_', cmdtext );
   call notify( 'curcmd2', '_set_text_', cmdtext );
   call notify( 'curcmd3', '_set_text_', cmdtext );
   call notify( 'curcmd4', '_set_text_', cmdtext );
return;    /* buildcmd */

catcheck:
    /* Check graphics catalog specified.  Also make */
    /* sure there is an html directory specified if */
    /* 'Place graphs in web page' is checked.       */
    if exist(graphcat, 'CATALOG') then do;
      msglist = setitemc(msglist,
        'Output catalog ' || graphcat || ' already exists.'
        || 'Do you want to overwrite it?', 1 );
      answer=messagebox(msglist,'?','YN',
             'Forecast Command Builder','Y');
      if answer = 'YES'
      then rc = delete(graphcat, 'CATALOG' );
      end;

      rc = 0;
      level1 = scan(graphcat,1,'.');
      level2 = scan(graphcat,2,'.');
      level3 = scan(graphcat,3,'.');

      if level2 = ' '
      then if ^sasname(graphcat)
           then rc = 1;
           else;
      else do;
             if ^sasname(level2) then rc = 1;
             if libref(level1) then rc = 2;
             if level3 ^= ' ' then rc = 3;
             end;

      if rc then do;
         if rc=1
         then msglist = setitemc(msglist,
                graphcat || ' is not a valid name.', 1 );
         else if rc = 2
              then msglist = setitemc(msglist,
                level1 || ' libname is not assigned.', 1 );
              else msglist = setitemc(msglist,
                'A one or two level name is required', 1 );
         answer=messagebox(msglist,'i',
                'O','Forecast Command Builder','Y');
         return;
         end;

      if makehtml & (htmldir = ' ') then do;
         msglist = setitemc(msglist,
           'HTML directory must be specified if you want to '
           || 'place output in a web page.', 1 );
         answer=messagebox(msglist,'i',
                'O','Forecast Command Builder','Y');
         rc = 1;
         end;

return;  /* catcheck */

clear:
   /* Clear the command list. */
   rc = clearlist( cmdlist );
   call notify( 'cmdlb', '_update_' );
   call notify( 'save', '_gray_' );
return;  /* clear */

clearflds:
   /* Clear some fields when data set changes. */
   selser  = '';
   seltid  = '';
   selint  = '';
   outdsn  = '';
   selproj = '';
   modkeep = '';
   usediag = 1;
   audit   = 0;
   nsers   = 1;
   rc      = clearlist(selsers);
   rc      = clearlist(serlist);
   rc      = clearlist(varlist);
return;   /* clearflds */

cmdlb:
   /* Command list box. */
   call notify( 'cmdlb', '_get_last_sel_',
                row, issel );
   if row
   then do;
           call notify( 'delete', '_ungray_' );

           /* Parse command in the selected row and use  */
           /* to populate the widgets so user can edit a */
           /* previously saved command.                  */
           cmdtext = getitemc( cmdlist, row );
           call notify( 'curcmd1', '_clear_' );
           call notify( 'curcmd2', '_clear_' );
           call notify( 'curcmd3', '_clear_' );
           call notify( 'curcmd4', '_clear_' );
           call notify( 'curcmd1', '_set_text_', cmdtext );
           call notify( 'curcmd2', '_set_text_', cmdtext );
           call notify( 'curcmd3', '_set_text_', cmdtext );
           call notify( 'curcmd4', '_set_text_', cmdtext );

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'DATA=', 40, returnString );
           seldsn = returnString;
           if seldsn ^= _blank_ then link getvars;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'VAR=', 32, returnString );
           selser = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'ID=', 32, returnString );
           seltid = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'INTERVAL=', 32, returnString );
           selint = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'PROJECT=', 17, returnString );
           selproj = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'ENTRY=', 8, returnString );
           entry = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'HORIZON=', 8, returnString );
           horizon = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'CLIMIT=', 8, returnString );
           conflim = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'STAT=', 40, returnString );
           sel = searchc( modcnames, returnString );
           if 0 < sel < listlen(modcpu)
           then do;
                  crit     = getitemc( modcpu,    sel );
                  critname = getitemc( modcnames, sel );
                  end;
           else do;
                  crit     = ' ';
                  critname = ' ';
                  end;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'OUT=', 17, returnString );
           outdsn = returnString;

           if index( cmdtext, 'REFIT' )
           then refitopt = 'REFIT' ;
           else if index( cmdtext, 'REEVAL' )
                then refitopt = 'REEVAL';
                else refitopt = 'NEITHER';

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'KEEP=', 3, returnString );
           modkeep = returnString;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'AUDIT=', 3, returnString );
           if returnString = 'YES'
           then audit = 1;
           else audit = 0;

           call method( 'forcmtd.scl', 'getarg', cmdtext,
                'DIAG=', 3, returnString );
           if returnString = 'NO'
           then usediag = 0;
           else usediag = 1;

           /* clear multiple series selections */
           nsers = 1;
           rc    = clearlist(selsers);
           end;

   else call notify( 'delete', '_ungray_' );
return;  /* cmdlb */

critctrl:
   /* Model fit criterion selector. */
   sel = popmenu( modcpu );
   if ^sel then return;
   crit = getitemc( modcpu, sel );
   critname = getitemc( modcnames, sel );
   if critname = ' ' then crit = ' ';
   link buildcmd;
return;   /* critctrl */

confctrl:
   /* Confidence limits selector. */
   sel = popmenu( confpu, 20 );
   if ^sel then return;
   conflim = getitemc( confpu, sel );
   link buildcmd;
return;   /* confctrl */

conflim:
   /* Confidence limits input field. */
   link buildcmd;
return;   /* conflim */

datefrmt:
   if datefrmt = 'as in dataset'
   then gdatefmt = ' ';
   else gdatefmt = datefrmt;
return;   /* datefrmt */

delete:
   /* Delete button on command list tab. */
   call notify( 'cmdlb', '_get_last_sel_',
                row, issel );
   if ^row then return;

   cmdlist = delitem( cmdlist, row );

   call notify( 'cmdlb', '_update_' );

   if listlen( cmdlist ) < 1
   then do;
          call notify( 'save', '_gray_' );
          call notify( 'delete', '_gray_' );
          end;
   else if listlen( cmdlist ) >= row
        then call notify( 'cmdlb', '_select_row_', row );
        else call notify( 'cmdlb', '_select_row_', 1 );

   link clearflds;
   seldsn   = '';
   horizon  = '';
   conflim  = '';
   crit     = '';
   refitopt = 'Neither';
   call notify( 'curcmd1', '_clear_' );
   call notify( 'curcmd2', '_clear_' );
   call notify( 'curcmd3', '_clear_' );
   call notify( 'curcmd4', '_clear_' );

   cursor seldsn;
return;   /* delete */

dsctrl:
   /* Input data selector: Prompt for a SAS data set or */
   /* view. */
   seldsn = dirlist( '*', '*', 1, 'Y' );
   link seldsn;
return;   /* dsctrl */

entrctrl:
   /* Entry selector.  Display labels but return name */
   /* corresponding to selected label.                */
   sel = popmenu( entlabels, 20 );
   if ^sel then return;
   entry = getitemc( entries, sel );
   if entry ^= 'FORECAST' then outdsn = ' ';
   link buildcmd;
return;    /* entrctrl */

frmtctrl:
   /* Specify format for time id variable in graph. */
   formatid =
     instance(loadclass('SASHELP.SQL.QWFORMAT.CLASS'));
   fmtmsg = '';
   call send(formatid,'SELECT_FORMAT',gdatefmt,'N',
             '','TIMEDATE',.,fmtmsg);
   call send(formatid,'_TERM_');
   if gdatefmt ^= _blank_
   then datefrmt = gdatefmt;
return;   /* frmtctrl */

getvars:
   /* Get list of variables in selected data set. */
   call send( dfile, '_setup_', seldsn );
   call send( dfile, '_get_members_', varlist, '',
              'label' );
   if listlen( varlist ) < 1 then return;

   /* Convert to list of names:labels for popmenu and   */
   /* list of names only for....                        */
   rc = clearlist( serlist );

   do i=1 to listlen( varlist );
      sname  = nameitem(varlist,i);
      slabel = getitemc(getiteml(varlist,i),1);

      if slabel ^= ''
      then sitem = sname || ": " || slabel;
      else sitem = sname;

      rc = insertc(serlist,  sitem, -1 );
      end;

   /* Clear the selected varibles list */
   rc = clearlist(selsers);
return;   /* getvars */

graphall:
   if graphall then do;
      call notify('graphcat', '_ungray' );
      call notify('grfbrows', '_ungray' );
      call notify('makehtml', '_ungray' );
      call notify('incldate', '_ungray' );
      call notify('incltime', '_ungray' );
      call notify('title2'  , '_ungray' );
      call notify('datefrmt', '_ungray' );
      call notify('frmtctrl', '_ungray' );
      end;

   else do;
      makehtml = 0;
      call notify('graphcat', '_gray' );
      call notify('grfbrows', '_gray' );
      call notify('makehtml', '_gray' );
      call notify('htmldir' , '_gray' );
      call notify('htmbrows', '_gray' );
      call notify('incldate', '_gray' );
      call notify('incltime', '_gray' );
      call notify('title2'  , '_gray' );
      call notify('datefrmt', '_gray' );
      call notify('frmtctrl', '_gray' );
      end;
return;   /* graphall */

grfbrows:
   graphcat = dirlist( '*', 'CATALOG', 1, 'Y' );
return;   /* grfbrows */

horzctrl:
   /* Forecast horizon selector. */
   sel = popmenu( horzpu, 20 );
   if ^sel then return;
   horizon = getitemc( horzpu, sel );
   link buildcmd;
return;   /* horzctrl */

htmbrows:
   rc = filedialog( 'AGGREGATE', htmldir, ' ', ' ' );
return;  /* htmbrows */

horizon:
   /* Forecast horizon input field. */
   link buildcmd;
return;   /* horizon */

intctrl:
   /* Interval selector. */
   call display('sashelp.etstool.interval.frame',
                selint, intpopup);

   link buildcmd;
return;     /* intctrl */

load:
   /* Open button on command list tab. */

   if savlist = _blank_ then
   savlist = 'sasuser.fmsproj._cmdlst_.slist';
             /* default save location */

   savlist = catlist('*', 'SLIST', 1, 'Y',
        'Select an entry containing a saved command list');

   if savlist = _blank_ | sysrc(-1) = -1 then return;

   /* Retrieve the saved command list, if it exists. */
   rc = fillist( 'catalog', savlist, cmdlist );
   if rc then return;

   if listlen(cmdlist) < 1
   then mtext = savlist || ' is empty.';
   else mtext = 'Command list was opened from ' ||
                savlist ;
   msglist = setitemc(msglist,mtext,1);
   answer=messagebox(msglist,'i','O',
          'Forecast Command Builder','O','');

   call notify( 'cmdlb', '_update_' );
   call notify( 'save', '_ungray_' );
return;    /* load */

makehtml:
   if makehtml then do;
      call notify('htmldir',  '_ungray' );
      call notify('htmbrows', '_ungray' );
      end;
   else do;
      call notify('htmldir',  '_gray' );
      call notify('htmbrows', '_gray' );
      end;
return;   /* makehtml */

mkeepctl:
   sel = popmenu(mkeepsel);
   if ^sel then return;
   modkeep = getitemc(mkeepnum, sel);
   link buildcmd;
return;   /* mkeepctl */

outctrl:
   /* Output data set selector. */
   /* Prompt for a SAS data set to save forecasts to. */
   outdsn = dirlist( '*', 'DATA', 1, 'Y' );
   link buildcmd;
return;     /* outctrl */

outdsn:
   /* Output data set input field. */
   link buildcmd;
return;    /* outdsn */

output:
   if entry ^= 'FORECAST' then return;
 * if datefrmt = 'as in dataset'
   then gdatefmt = ' ';
 * else gdatefmt = datefrmt;

   if ^graphall & ^makehtml then do;
      call display( 'forccout.frame',
                    templist, ' ',' ',' ', gdatefmt );
      return;
      end;

   addtitle = title2;

   if incldate
   then addtitle = addtitle || ' ' || putn(today(),
                   'date9.');

   if incltime
   then addtitle = addtitle || ' ' || putn(time(),'time.');

   if makehtml
   then call display( 'forccout.frame', templist,
                      graphcat, htmldir, addtitle, gdatefmt );
   else call display( 'forccout.frame', templist,
                      graphcat, ' ', addtitle, gdatefmt );
return;     /* output */

projctrl:
   /* Project selector. */
   selproj = catlist(
             'sasuser.fmsproj', 'FMSPROJ', 1, 'Y' );
   link buildcmd;
return;   /* projctrl */

refitopt:
  link buildcmd;
return;   /* refitopt */

runcheck:
    /* Make sure we have a data set and series if  */
    /* ENTRY=FORECAST */

    rc = 0;
    text = ' ';
    if entry ^= 'FORECAST' then return;

    if seldsn = ' '
    then text = 'Please select a data source.';
    else if selser = ' '
         then text = 'Please select one or more series.';
         else return;

    msglist = setitemc(msglist, text, 1 );
    answer=messagebox(msglist,'!','O',
           'Forecast Command Builder','O','');

    rc = 1;
return;   /* runcheck */

save:
   /* Save button on command list tab. */
   descrip = 'Forecast Command Builder command list.' ;
   savlist = ' ';
   savlist = saveentrydialog( 'SLIST',
             'sasuser.fmsproj._cmdlist_.slist',' ',0,
             descrip );

   if savlist = ' ' then return;  /* user cancelled */

   /* Save command list to selected slist catalog entry. */
   rc = savelist( 'catalog', savlist, cmdlist, attrlist,
                  descrip );
   if rc then return;

   msglist = setitemc
     (msglist, 'Command list was saved to ' || savlist, 1);

   answer=messagebox(msglist,'i','O',
         'Forecast Command Builder','O','');
return;   /* save */

seldsn:
   /* Input data set input field. */
   if seldsn ^= olddsn then link clearflds;
   if seldsn ^= _blank_ then do;

   olddsn = seldsn;

   /* Find out if there is a variable called 'DATE',*/
   /* TIME, or DATETIME.                            */
   if exist(seldsn) then link getvars;
   else if exist(seldsn,'VIEW') then link getvars;

   varn = nameditem(varlist,'DATE');
   if varn then seltid = 'DATE';
   else do;
          varn = nameditem(varlist,'TIME');
          if varn then seltid = 'TIME';
          else do;
                 varn = nameditem(varlist,'DATETIME');
                 if varn then seltid = 'DATETIME';
                 end;
          end;

   if varn then do;
        call send( etsscl, '_GET_TIMEID_INTERVAL_',
              seldsn, seltid, interval, rc   );
        if ^rc then selint = interval;
        end;
   end;

   link buildcmd;

return;    /* seldsn */

selint:
   /* Interval input field. */
   link buildcmd;
return;   /* selint */

selproj:
   /* Project input field. */

   /* Inform user if typed-in project already exists. */
   if selproj ^= _blank_ then do;
       if ^index(selproj,'.')
       then text = 'sasuser.fmsproj.' || selproj ||
                   '.fmsproj';
       else text = selproj;
       if exist(text,'CATALOG') then do;
          text = 'This is an existing project.';
          msglist = setitemc(msglist, text, 1 );
          answer=messagebox(msglist,'i','O',
                 'Forecast Command Builder','O','');
          end;
       end;

   link buildcmd;
return;  /* selproj */

selser:
   /* Series input field. */
   if selser = _blank_
   then nsers = 0;
   else nsers = 1;

   /* Set project and outdsn to same name as series */
   /* by default. */
   selproj = selser;
   outdsn  = selser;

   link buildcmd;
return;   /* selser */

seltid:
   /* Time ID input field. */
   if seltid ^= _blank_ & selint = _blank_ then do;
        call send( etsscl, '_GET_TIMEID_INTERVAL_',
              seldsn, seltid, interval, rc   );
        if ^rc then selint = interval;
        end;

   link buildcmd;
return;   /* seltid */

sersel:
   /* Series dual list box selector window */
   availsers = copylist(serlist);
   rc = clearlist(selsers);
   call display('sashelp.forcast.forccser.frame',
                availsers, selsers );
   rc = setlattr(serlist, 'UPDATE' );
   rc = setlattr(selsers , 'UPDATE' );
   nsers = listlen(selsers);
   select(nsers);
      when(0) selser = ' ';
      when(1) selser = getitemc(selsers, 1 );
      otherwise selser = '‹multiple›';
      end;

   selproj = scan(selser,1,':');
   outdsn  = selproj;
   link buildcmd;
   availsers = dellist(availsers);
return;   /* sersel */

tidctrl:
   /* Time ID selector. */
   sel = popmenu( serlist, 20 );
   if ^sel then return;
   seltid = getitemc( serlist, sel );

   if seltid ^= _blank_ & selint = _blank_ then do;
        call send( etsscl, '_GET_TIMEID_INTERVAL_',
              seldsn, seltid, interval, rc   );
        if ^rc then selint = interval;
        end;

   link buildcmd;
return;   /* tidctrl */

toolbar:
   /* Perform action assigned to toolbar button selected.*/
   call notify( 'toolbar', '_get_last_sel_',
                sel, issel, btnname );
   select( btnname );

      /*-- add current --*/
      when( 'ADD'     )

           /*- make sure there is a data set and series -*/
           link runcheck;
           if rc then return;

           /*- if just one series, add to command list -*/
           if nsers = 1
           then cmdlist = insertc( cmdlist, cmdtext, -1 );

           /* If multiple series, add command for each. */
           else do i=1 to nsers;
                   curtext = cmdtext;
                   curser = scan(getitemc( selsers, i ), 1, ':');
                   ppos = index(curtext,'VAR=') + 4;
                   if substr(curtext,ppos,10)='‹multiple›'
                   then do;
                      curtext = substr(curtext,1,ppos-1)
                                || curser
                                || substr(curtext,ppos+10);
                      end;

                   if selproj = '‹multiple›' then do;
                      ppos = index(curtext,'PROJECT=') + 8;
                      if ppos > 8
                      then if substr(curtext,ppos,10)
                              = '‹multiple›'
                           then do;
                                  curtext =
                                   substr(curtext,1,ppos-1)
                                   || curser ||
                                   substr(curtext,ppos+10);
                                  end;
                      end;

                   if outdsn = '‹multiple›' then do;
                      ppos = index(curtext,'OUT=') + 4;
                      if ppos > 4
                      then if substr(curtext,ppos,10)
                              = '‹multiple›'
                           then do;
                                  curtext = substr(
                                          curtext,1,ppos-1)
                                   || curser ||
                                   substr(curtext,ppos+10);
                                  end;
                      end;

                   cmdlist = insertc(cmdlist, curtext, -1);
                   end;

           call notify( 'cmdlb', '_update_' );
           call notify( 'save', '_ungray_' );

      when( 'RUNCUR'  )
           link runcheck;
           if rc then return;

           if graphall then link catcheck;
           if rc then return;

           call execcmdi( cmdtext );

           if entry='FORECAST' then do;
              templist = makelist();
              templist = insertc( templist, cmdtext, -1 );
              link output;
              templist = dellist( templist );
              end;

      when( 'RUNLIST' )

           if graphall then link catcheck;
           if rc then return;

           do i = 1 to listlen( cmdlist );
              cmdtext = getitemc( cmdlist, i );
              call execcmdi( cmdtext );
              end;

           templist = cmdlist;
           link output;

      when( 'QUIT'    )  call execcmd( 'END' );

      when( 'HELP'    )  call execcmd(
                'wbrowse "http://www.sas.com/rnd' ||
                '/app/ets/forecasting/cmdbldr82.html"');

      otherwise;
      end;
return;  /* toolbar */

usediag:
   link buildcmd;
return;    /* usediag */

/* Nonexecutable:  Prevent compiler warnings. */
rc = rc;