/* ScanSettings.cmd
 *
 * Settings enumerator
 *    looks through all applications to find global settings used. The
 *    argument is a semicolon delimited list of sequence files.
 * 
 * Copyright (C) 2018 Blonde Guy
 * All Rights Reserved
 */
 
Call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
Call SysLoadFuncs

signal on syntax

/* add to system path */
call 'cd-env'

/* output */
rptout = 0
guiout = 0
tpout = 1
tpwait = ''

if rptout = 1 then do
   call LogCdi "ScanSettings version 0.68 by Blonde Guy"
   call LogCdi "starting" date() time()
end

originalDir = Directory()

parse arg seqList
call ProcessSeqList seqList

/* display progress */
if tpout = 1 then do
   call LogCdi "!setseqbar" 20
end

call BubbleSort

setting.0 = 0
used.0 = 0

/* scan all suntan files */
suntanDir = strip(sysini("User", 'Suntan Special', 'Settings'), 'T', d2c(0))
if suntanDir <> 'ERROR:' then do
   call SysFileTree suntanDir || '\*.cmd', 'tanList', 'FO'
   do j=1 to tanList.0
      call ProcessSuntanFile tanList.j
   end
end
else do
   call LogCdi "Suntan directory not found"
end

/* scan all apps */
do j=1 to AppList.0
   /* skip duplicates */
   key = translate(substr(AppList.j, lastpos('\', AppList.j) + 1))

   if key <> prev then do
      call ProcessApp AppList.j
   end

   prev = key
end

if tpout = 1 then do
   dialogName = 'Settings'
   cr = d2c(13)
   instructions = "Settings Editor" || cr || cr ||,
                  "Single click each line to get a description of the item",
                  "on that line. Double click or press enter to edit or change",
                  "the value of a setting."
   
   tpcmd = dialogName || d2c(10) || instructions || d2c(10) || "SetEdCB.cmd" || d2c(10) ||"SetEdCB.cmd" || d2c(10) || "~Edit"

   /* should editor wait for the list panel to return OK */
   if tpwait = "Wait" then do
      tpcmd = tpcmd d2c(10) || "Wait"
   end
   else do
      tpcmd = tpcmd d2c(10) || "not"
   end

   tpcmd = tpcmd || d2c(10) || "; Settings for" sequence
end

/* display progress */
if tpout = 1 then do
   call LogCdi "!setseqbar" 30
end

/* scan all settings */
do j=1 to setting.0
   if rptout = 1 then do
      call LogCdi "Setting:" setting.j
      call LogCdi "Times used:" used.j
      call LogCdi "Used by:" usedby.j
   end
   call ProcessSetting setting.j
   if guiout = 1 then do
      call LogCdi "Calling QuerySettings(" setting.j ", 'Query')"
      response = QuerySettings(setting.j, 'Query')
      call LogCdi "response =" response
      call SetSetting setting.j, response
   end
   if tpout = 1 then do
      tpcmd = tpcmd || d2c(10) || setting.j
      call LogCdi "!setseqbar" trunc(30 + j * 60 / setting.0)
   end
end

/* display progress */
if tpout = 1 then do
   call LogCdi "!setseqbar" 90
end

if tpout = 1 then do
   call LogCdi "!listpanel" tpcmd
end

/* display progress */
if tpout = 1 then do
   call LogCdi "!setseqbar" 100
end

return

/* scan the sequence list for a list of applications */
ProcessSeqList:

parse arg seqList
AppSeq.0 = 0

if tpout = 1 then do
   call LogCdi "Scanning settings for" seqList
   call LogCdi "!setseqbar" 0
end

AppNo = 0
if seqList <> '' then do
   do while seqList <> ''
      parse var seqList sequence ';' seqList
      do while lines(sequence)
         sline = linein(sequence)
         if left(sline, 1) <> ';' then do
            AppNo = AppNo + 1
            AppSeq.AppNo = sline
         end
      end
      call stream sequence, 'c', 'close'
   end
   
   if AppNo = 0 then do
      parse arg seqList
      call LogCdi "No applications found in" seqList
      return
   end
   AppSeq.0 = AppNo
end

/* display progress */
if tpout = 1 then do
   call LogCdi "!setseqbar" 10
end

sourcePath = cdglobal('sourceDir')

/* parse source path into source directories */
j = 0
do while sourcePath \= ''
   parse var sourcePath sourceDir ';' sourcePath
   if sourceDir \= '' then do
      j = j + 1
      Dir.j = sourceDir
   end
end
Dir.0 = j

AppNo = 0
do j = 1 to Dir.0
   sourceDir = Dir.j
   call SysFileTree sourceDir || '\*.*', 'tempList', 'DO'
   do k = 1 to tempList.0

      /* process all applications in the sourceDir list */
      if AppSeq.0 = 0 then do
         AppNo = AppNo + 1
         AppList.AppNo = TempList.k
      end

      /* process only applications in the sequence */
      else do
         tempApp = substr(tempList.k, lastpos('\', tempList.k) + 1)
         found = 0
         do m=1 to AppSeq.0
            if tempApp = AppSeq.m then do
               found = 1
            end
         end
         if found <> 0 then do
            AppNo = AppNo + 1
            AppList.Appno = TempList.k
         end
      end
   end
end

AppList.0 = AppNo

return

/* scan each application for globals */
ProcessApp:
parse arg appDir

glob = ''
cf = appDir || '\cdi.cmd'
if stream(cf, 'c', 'query exists') \= '' then do
   appName = substr(appDir, lastpos('\', appDir) + 1)
   do while lines(cf) > 0
      rexxStmt = linein(cf)
      pp = pos('CDGLOBAL', translate(rexxStmt))
      if pp > 0 then do
         po = pos('(', substr(rexxStmt, pp))
         pa = substr(rexxStmt, pp + po + 1)
         pc = pos(')', pa)
         pa = left(pa, pc - 1)
         pa = strip(pa,, '"')
         pa = strip(pa,, "'")
         glob = glob pa
         found = 0
         do k=1 to setting.0
            if translate(setting.k) = translate(pa) then do
               found = 1
               used.k = used.k + 1
               usedby.k = usedby.k || ';' || appName
            end
         end
         if found = 0 then do
            k = setting.0 + 1
            setting.k = pa
            setting.0 = k
            used.0 = k
            used.k = 1
            usedby.k = appName
         end
      end
   end

   call stream cf, 'c', 'close'

   if glob <> '' then do
      if rptout = 1 then do
         call LogCdi appDir "globals used" glob
      end
   end

return


/* scan each suntan file for globals */
ProcessSuntanFile:
parse arg cf
appName = 'Suntan'

glob = ''
if stream(cf, 'c', 'query exists') \= '' then do
   do while lines(cf) > 0
      rexxStmt = linein(cf)
      pp = pos('CDGLOBAL', translate(rexxStmt))
      if pp > 0 then do
         po = pos('(', substr(rexxStmt, pp))
         if po = 0 then leave
         pa = substr(rexxStmt, pp + po + 1)
         pc = pos(')', pa)
         if pc = 0 then leave
         pa = left(pa, pc - 1)
         if pos('"', pa) = 0 & pos("'", pa) = 0 then leave
         pa = strip(pa,, '"')
         pa = strip(pa,, "'")
         glob = glob pa
         found = 0
         do k=1 to setting.0
            if translate(setting.k) = translate(pa) then do
               found = 1
               used.k = used.k + 1
               if pos(appName, usedby.k) = 0 then do
                  usedby.k = usedby.k || ';' || appName
               end
            end
         end
         if found = 0 then do
            k = setting.0 + 1
            setting.k = pa
            setting.0 = k
            used.0 = k
            used.k = 1
            usedby.k = appName
         end
      end
   end

   call stream cf, 'c', 'close'

   if glob <> '' then do
      if rptout = 1 then do
         call LogCdi cf "globals used" glob
      end
   end

end

return

/* process one setting */
processSetting:

parse arg sname

svalue = querysettings(sname, 'Value')
sdefault = querysettings(sname, 'DefaultValue')
sinstruct = querysettings(sname, 'Instructions')

if rptout = 1 then do
   call LogCdi "Value:" svalue
   call LogCdi "DefaultValue:" sdefault
   call LogCdi "Instructions:" sinstruct
   call LogCdi "---"
end

return

 /* ------------------------------------------------------------------ */
 /* function: bubble sort routine from REXX tips and tricks            */
 /*                                                                    */
 /* call:     BubbleSort                                               */
 /*                                                                    */
 /* returns:  nothing                                                  */
 /*                                                                    */
 /* notes:    You must save the elements to sort in the stem "AppList."*/
 /*           stem.0 must contain the number of elements in the stem.  */
 /*                                                                    */
 /*                                                                    */
 BubbleSort: PROCEDURE expose AppList.
 
 say "bubble sort" AppList.0 "items"
 
   do i = AppList.0 to 1 by -1 until flip_flop = 1
     flip_flop = 1
     do j = 2 to i
       m = j - 1
       mName = translate(filespec('name', AppList.m))
       jName = translate(filespec('name', AppList.j))
       if mName >> jName then do
         xchg = AppList.m
         AppList.m = AppList.j
         AppList.j = xchg
         flip_flop = 0
       end /* if AppList.m ... */
     end /* do j = 2 ... */
   end /* do i = AppList.0 ... */
 return
 
/* by returning this string, puts error checking in each interpret statement */
syntax:
call LogCdi "Condition" Condition('c') "was raised"
call LogCdi "ScanSettings Error" rc "on line" sigl
call LogCdi ErrorText(rc)
return rc
