
import fnmatch
import os
import re
import string
import sys
import types

from dirwalker import DirWalker
from isumake import IsUmakeFile

class FindMatchesWalker(DirWalker):
    def __init__(self, opts):
        self.opts = opts

        if opts.has_key('filemasks'):
            self.skipMasks = []
            self.doMasks = opts['filemasks']
        else:
            self.skipMasks = ['*.pyc', '*.o', '*.obj', '*.a', '*.lib', '*.exe']
            self.doMasks = ['*']

        self.RE = re.compile(opts['pattern'])
        self.matches = {}

    def MatchJoin(self, m):
        if isinstance(m, types.StringType):
            if self.opts.has_key('whitespace-compress'):
                return re.sub(r'\s+', ' ', m)
            return m

        joinStr = ' '
        if self.opts.has_key('join'): joinStr = self.opts['join']

        if self.opts.has_key('whitespace-compress'):
            return string.join(map(lambda x:re.sub(r'\s+', ' ', x), m),
                               joinStr)
        return string.join(m, joinStr)
        
    def DoFile(self, inFname):
        if self.opts.has_key('verbose'): print "# DoFile(%s)" % inFname

        try:
            inFile = open(inFname)
        except IOError, e:
            print "# ERROR: File error on %s" % inFname
            return

        inFile.seek(0)
        lines = string.join(inFile.readlines())
        inFile.close()
        if len(lines) == 0: return

        # Ought to check for binary files in here somehow
        if not self.opts.has_key('binary'):
            if re.search(r'\0', lines):
                if self.opts.has_key('verbose'):
                    print "# binary file check matched %s" % (inFname)
                return

        matches = self.RE.findall(lines, re.DOTALL)
        if len(matches) > 0:
            for m in matches:
                matchName = self.MatchJoin(m)
                if self.opts.has_key('filename-only'):
                    print inFname
                    return
                elif self.opts.has_key('no-unique'):
                    self.PrintMatch(matchName, inFname)
                elif self.matches.has_key(matchName):
                    self.matches[matchName].append(inFname)
                else:
                    self.matches[matchName] = [inFname]

    def Visit(self, f):
        if self.opts.has_key('verbose'): print "# Visit(%s)" % f

        fpath = os.path.join(self.baseDir, self.subDir, f)
        if self.opts.has_key('umake-files') and IsUmakeFile(fpath, self.opts):
            self.DoFile(fpath)
            return
        
        for mask in self.skipMasks:
            if fnmatch.fnmatch(f, mask):
                if self.opts.has_key('verbose'):
                    print "# skipMask(%s) matched %s" % (mask, f)
                return

        for mask in self.doMasks:
            if fnmatch.fnmatch(f, mask):
                if self.opts.has_key('verbose'):
                    print "# doMask(%s) matched %s" % (mask, f)

                inFname = os.path.join(self.baseDir, self.subDir, f)
                if os.path.isfile(inFname): self.DoFile(fpath)
    
    def PrintMatch(self, key, f):
        if self.opts.has_key('no-filenames'): print key
        else: print "%s : %s" % (key, f)

    def PrintMatches(self):
        keyList = self.matches.keys()
        keyList.sort()
        for key in keyList:
            self.PrintMatch(key, string.join(self.matches[key]))
