###
# Application: pyFind
# File:        match_files.py
# Description: File search function
# Copyright (c) 2001-2002   Andy Balcombe <kinematics _at_ ntlworld.com>
###
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#standard python modules
import os
import time
import stat
import pwd, grp

#project modules
import pathinfo
import file_srch_rep

"""
Function:    find_matching_files
Description: Returns a list of tuples of matched files.
Parameters:
    Main app window class       object (class of calling GUI)
    Search Path                 string
    Search Sub-directories      boolean
    Search Mounted Volumes      boolean
    File Spec                   string
    Case Sensitive              boolean
    Search by Previous Date     boolean
    Previous Date Type          string (min, day, week, month, year)
    Previous Date Number        integer
    Search File Contents        boolean
    Search Contents Case Sens   boolean
    Search File For             string
    Search by File Size         boolean
    File Size Type              string (<, >)
    File Size                   integer
    Search by Mod Date          boolean
    Min Date                    date
    Max Date                    date
    Search and Replace          boolean
    Replace - Search Text       string
    Replace - Replace Text      string
    Replace - Use Reg Exp       boolean
    Replace - Case Sensitive    boolean
    
Returns:
    List of files:
        Type
        Name
        Path
        Permission
        User
        Group
        Size
        Acc_time
        Mod_date
    Find command-line string
"""
def find_matching_files(
        pclsApp,
        psSearchPath,
        pbSearchSubDirs, 
        pbSearchMounted,
        psFileSpec, 
        pbCaseSensitive,
        pbSearchPrevDate,
        psPrevDateType,
        piPrevDateVal,
        pbSearchContents,
        pbContentsCaseSensitive,
        psSearchContentsFor,
        pbSearchSize,
        psSizeType,
        piSize,
        pbSearchModDate,
        pdatMinDate,
        pdatMaxDate,
        pbReplace,
        psRepSearch,
        psRepReplace,
        pbRepRE,
        pbRepCaseSensitive ):

    #init
    sFindCmd = ""
    sParam = ""
    sGrep = ""
    sGrepCmd = ""
    iVal = 0
    tFileInfo = ()
    lFindFiles = []     #files found in find command
    lFiles = []         #files matching all specified parameters
    lFileInfo = ["type","file","path","permission","user","group","size","acc_time","mod_date"]
    bFileMatch = 0      #true if file matches all criteria
    iNumFilesFound = 0  #number of matched files

    #setup GUI
    iProgress = 0.0
    #pclsApp.clstFiles.freeze() 
    pclsApp.apbMain.set_progress(iProgress)

    #search mounted volumes?
    if not pbSearchMounted:
         psSearchPath = '-x ' + psSearchPath

    #case sensitive file name search
    if pbCaseSensitive:
        sParam = ' -name "' #yes
    else:
        sParam = ' -iname "' #no
    sFindCmd = "find " + psSearchPath + sParam + psFileSpec + '"' 
    
    #search sub-directories
    if pbSearchSubDirs:
        sFindCmd = sFindCmd + " -maxdepth 1"
    
    #search previous days
    if pbSearchPrevDate:
        sParam = " -mtime -"
        iVal = piPrevDateVal
        if psPrevDateType == "Minutes":
            sParam = " -mmin -"
        elif psPrevDateType == "Weeks":
            iVal = iVal * 7
        elif psPrevDateType == "Months":
            iVal = iVal * 30
        elif psPrevDateType == "Years":
            iVal = iVal * 365
        # add mtime/mmin argument
        sFindCmd = "%s %s%i" % (sFindCmd, sParam, iVal)

    #output to command line
    sFindCmd = sFindCmd + " -print"
    
    #search contents?
    if pbSearchContents:       
        #case-sensitive contents
        if pbContentsCaseSensitive:
            sGrep = "grep " #yes
        else:
            sGrep = "grep -i " #no

    #search for files - execute find command
    for objFile in os.popen(sFindCmd).readlines():
        sFileName = objFile[:-1]
        bFileMatch = 0
        
        #check gtk / gnome events
        pclsApp.process_gtk_events()
        if pclsApp.bStopPressed:
            #stop pressed
            break

        #check contents of file?
        if pbSearchContents:
            sGrepCmd = sGrep + psSearchContentsFor + " " + sFileName
            #search contents of file...
            if len(os.popen(sGrepCmd).readlines()) > 0:
                #yep
                bFileMatch = 1
        else:
            #not checking contents, so add file to list anyway
            bFileMatch = 1

        #have we got an initial match
        if bFileMatch:
            #yes
            iNumFilesFound = iNumFilesFound + 1           
            #so, now do extra processing...
            bFileMatch = 1
            iFileSize    = os.path.getsize(sFileName)        #get file size
            datFileATime = os.path.getatime(sFileName)       #get acc time
            datFileMTime = os.path.getmtime(sFileName)       #get mod time
            tStat        = os.stat(sFileName)                #get stat info
            sPermissions = pathinfo.PathInfo(sFileName).permissions() #get permissions

            lFileInfo[0]=""                                  #type
            lFileInfo[1]=os.path.basename(sFileName)         #filename
            lFileInfo[2]=os.path.dirname(sFileName)          #directory
            lFileInfo[3]=sPermissions                        #permissions
            lFileInfo[4]=pwd.getpwuid(tStat[stat.ST_UID])[0] #user
            lFileInfo[5]=grp.getgrgid(tStat[stat.ST_GID])[0] #group
            lFileInfo[6]=str(iFileSize)                      #size
            lFileInfo[7]=time.ctime(datFileATime)            #acc time
            lFileInfo[8]=time.ctime(datFileMTime)            #mod time

            #check size
            if pbSearchSize:
                bFileMatch = 0
                if psSizeType == ">": # at least
                    bFileMatch = ( iFileSize > piSize )
                else:                  # at most
                    bFileMatch = ( iFileSize < piSize )
        
            #check file mod time
            if bFileMatch and pbSearchModDate:
                bFileMatch = 0
                if pdatMinDate != 0 and pdatMaxDate != 0:
                    if datFileMTime >= pdatMinDate and datFileMTime <= pdatMaxDate:
                        bFileMatch = 1
            
            #add the file to the results list
            if bFileMatch:
                #calc size
                fSize = float(lFileInfo[6]) / 1024
                if fSize < 10.0:
                    lFileInfo[6] = "%.1f" % fSize #convert size to (n.n)Kb
                else:
                    lFileInfo[6] = "%i" % fSize #convert size to (n)Kb
                    
                #copy file info to a tuple because its immutable!
                tFileInfo = tuple( lFileInfo ) 
                lFiles.append( tFileInfo )
                
                #search and replace?
                if pbReplace and psRepSearch != "":
                    #do it baby, yeah
                    #print "searching and replacing: ", sFileName
                    file_srch_rep.search_and_replace( 
                        psRepSearch, 
                        psRepReplace, 
                        sFileName, 
                        None, 
                        pbRepRE,
                        pbRepCaseSensitive )
                
                #update GUI
                iProgress = iProgress + 0.1
                if iProgress > 1.0:
                    iProgress = 0.0
                pclsApp.apbMain.set_progress( iProgress )
                pclsApp.clstFiles.append( tFileInfo )
                sFound = "%s %i %s" % ( "Found ", len(lFiles), " files.")
                pclsApp.apbMain.set_status( sFound )

    #done - GUI
    #pclsApp.clstFiles.thaw()
    if pclsApp.bStopPressed:
        sMsg = "Interrupted.  Found "
    else:
        sMsg = "Done.  Found "
    sFound = "%s %i %s" % ( sMsg, len(lFiles), " files.")
    pclsApp.apbMain.set_progress(0.0)
    pclsApp.apbMain.set_status( sFound )

    # done!
    #print "find_matching_files found", len(lFiles), "files"
    return lFiles, sFindCmd
    
