///////////////////////////////////////////////////////////////////
// Classes for CopyFolder - Started: 8/27/2010, M.Kay
//    based on FindInFile.cc
//
// Last Updated: 12/27/2010
//
//
// Copyright (C) 2010 - dataBased Intelligence, Inc.,
//                      All Rights Reserved
//
//
// Usage:
//     set procedure to copyfolder.cc additive
//     o = new CFileListArray()
//     o.PrepareToCopy()
//
// 
// Dependencies:
//     :coreshared:dirpath.cc    
// 
// Update : 06/10/2014 - KK
//              Modified CopyCurrentDirectory to copy just the files that are missing from the destination
///////////////////////////////////////////////////////////////////


CLASS CFileObj of File CUSTOM
   this.srcFolder  = ""
   this.destFolder = ""
   //this.accessRights = ""
ENDCLASS



CLASS CFileListArray OF Array CUSTOM

   // Custom properties
   this.rootSrcFolder       = ""
   this.rootDestFolder      = ""

   this.relativePath        = ""

   this.resultFile          = ""
   this.overWrite           = True
   this.userForm            = NULL    // object reference to userinterface form

   this.cancelHWnd          = NULL    // Handle of window to check for Cancel Message

   this.copyAllSubFolders   = True
   this.filesToCopy         = "*.*"   // One or more file skeletons to filter files to copy
                                      // Separate each file skeleton with a comma ex: "*.prg,*.wfm,*.mnu"
   this.cancelOperation     = False

   this.folderStack = new Array(1)  //  Directory stack used to move down recursivly
   this.folderStack[1] = ""         //  through directory tree
   this.fStackLen = 1


   this.oFileObj = new CFileObj()        // CFileObj object used to copy
   this.oFileObj.parent = this

   this.numFilesCopied      = 0

   this.beforeRelease       := CLASS::CFILELIST_BEFORERELEASE
   

   // Custom Methods /////////////////////////////////////

   // Method: PrepareToCopy()
   // Purpose: Initializes CFileListArray object
   // 
   // Usage:  Should be called before calling any other methods
   //         of CFileListArray object
   function PrepareToCopy
      //  Do any needed setup before starting copy

      //set procedure to :coreshared:dirpath.cc additive
      //this.odirpath = new dirpath()

      set procedure to :dBStartup:sdirpath.cc additive
      this.odirpath = new sdirpath()

      this.numFilesCopied = 0
      return



   // Method: CFileList_BeforeRelease()
   // Purpose: releases any resources prior to releasing this class
   //         Called from beforeRelease() event
   function CFileList_BeforeRelease()

      this.odirpath = null
      //close procedure :coreshared:dirpath.cc
      close procedure :dBStartup:sdirpath.cc

      return


   function CheckCancel
      if not this.cancelOperation
         //if this.userForm.UserStop(this.cancelHWnd)
         //   this.cancelSearch = True
         //endif
      endif
      return this.cancelOperation


   
   function StopCopy
      // idle(0.25)
      this.cancelOperation = True
      // idle(0.25)
      return
   


   function PushFolder
   * saves current directory path onto folderStack[]
   if this.fstackLen > 1
	   this.fstackLen = this.fstackLen + 1
      this.folderStack.add(set("directory"))
   else
      if not empty(this.folderStack[1])
         this.fstackLen = this.fstackLen + 1
         this.folderStack.add(set("directory"))
      else
         this.folderStack[1] = set("directory")
      endif
   endif
   return



   function PopFolder
   * Pops folder from top of folderStack and
   * sets current directory to this folder
   local newFolder

   newFolder = this.folderStack[this.fstackLen]
   if not empty(newFolder)
      set directory to (newFolder)
   endif

   if this.fstackLen > 1
	   this.fstackLen = this.fstackLen - 1
      this.folderStack.resize(this.fstackLen)
   else
	   this.folderStack[1] = ""
   endif
   return


   

   function RunCopy
   // Searches current directory
   // and then if copyAllSubFolders is True,
   // iterates through subFolders, for each one,
   // it calls RunCopy() recursively
   // The pathway through the directory tree is
   // maintained on a LIFO stack by pushFolder and
   // popFolder.
   local currentPath, aSubFolders, numSubFolders, ctr, nextpath, currDestFolder
   if not this.cancelOperation
      ** save current directory
      currentPath = set("directory") + "\"
     //MsgBox("currentPath = "+currentPath)
      //this.userForm.DisplaySearchFolder( currentPath )

      ** Determine current destination folder
      this.relativePath = substr(currentPath, len(this.rootSrcFolder)+1 )
     //MsgBox("this.relativePath = "+this.relativePath)
      currDestFolder = this.rootDestFolder + this.relativePath
     //MsgBox("currDestFolder = "+currDestFolder) 
      ** Check if matching destination folder exists
      ** If not, create it
      this.odirpath.makedirtree( currDestFolder )
		
		//msgbox("copying to "+currDestFolder)

      this.oFileObj.srcFolder  = currentPath
      this.oFileObj.destFolder = currDestFolder


      ** search for and copy files in current directory
      this.CopyCurrentDirectory()


      if this.copyAllSubFolders
	      aSubFolders = new Array()

         numSubFolders = this.GetSubFolders( aSubFolders )
         if numSubFolders > 0
            // start with ctr=3 to skip over "." and ".." entries
            for ctr=3 to numSubFolders
               this.pushFolder()  // Save current directory onto stack

               nextpath = currentpath + aSubFolders[ctr,1]
               cd (nextpath)
		
               this.RunCopy()     // Copy files recursively down directory tree

               this.popFolder()   // Restore current directory from stack
            next
         endif
      endif
   endif
   return




   function GetSubFolders
   * Fills aFolder array with list of subdirectories within current directory
   * returns number of directories found or zero if none found
   parameters aFolder

   local numFolders, result

   numFolders = aFolder.dir('','D')
	//msgBox("GetSubFolders - numFolders = "+numFolders)
   if numFolders <= 2
      // No files in array - just default entries
      //   for "." and ".."
      numFolders = 0
   endif   
   return numFolders




   function CopyCurrentDirectory
   ** copy files matching skeletons this.FilesToCopy in current directory
   local fileSkeletons, commaPosition, numFiles,  ctr, cfilename
   cCurrent = SET("DIRECTORY")
	//msgBox("copying directory "+cCurrent)
   fileSkeletons = this.filesToCopy
   do while len(trim(fileSkeletons)) > 0
      //if this.CheckCancel()
      //   exit
      //endif

      commaPosition = at(',', fileSkeletons)

      currentSkeleton = iif( commaPosition > 0, substr(fileSkeletons, 1, commaPosition-1), trim(fileSkeletons))

      fileSkeletons   = iif( commaPosition > 0, substr(fileSkeletons, commaPosition+1), '')
   
      // Retrieve list of files and folders
      numFiles = this.dir( currentSkeleton )

      //if this.CheckCancel()
      //   exit
      //endif

      if numFiles > 0
         // Iterate through all files found matching currentSkeleton...
         for ctr = 1 TO numFiles
            // idle()
            //if this.CheckCancel()
            //   exit
            //endif

            cfilename = trim(this[ctr,1])
				cFileSource = this.oFileObj.srcFolder + cfilename
				cFileDest = this.oFileObj.destFolder + cfilename
            //? "Copying "+this.oFileObj.srcFolder + cfilename
				//KK- copy only if file does not exist in destination - for 9.0.0.0 06/10/2014
				if NOT FILE(this.oFileObj.destFolder + cfilename) 
               this.oFileObj.copy( cFileSource, cFileDest)
               this.numFilesCopied++
				else if ("local" $ lower(cFileDest) AND "designer" $ lower(cFileDest) AND "code" $ lower(cFileDest)) OR;
				     "dbase.api" $ lower(cFileDest)
				   //Msgbox("about to copy "+cFileSource+" to "+cFileDest)
					this.oFileObj.copy( cFileSource, cFileDest)
               this.numFilesCopied++
				endif	

            //if this.userForm <> NULL
            //this.userForm.DisplaySearchFile( this[ctr,1] )
            //this.userForm.DisplayNumFilesSearched( this.numFilesSearched )
            //endif
         next

      endif
   enddo

   return

ENDCLASS


