#!/bin/python

import re
import os

class FileEditor(object):

    """A generic text file editor based on regular expressions.  This class
       is aimed at being able to edit small configuration files."""

    def __init__(self, file=None):
        """Init the class with an optional file name."""

        self._file = None       # File name.  Used in save()
        self._data = ""         # In memory file 
        self._flags = [True, True]

        if file:
            self.loadFile(file)
            
            
    def flags(self, multiline=None, regexs=None):
        """Change behavior of class.
           
           multiline defaults to True.  If True the re engine is run in
              multi-line mode.  See the Python docs for the re engine.
              
           regexs defaults to True.  If False all patterns given to this
              module are considered static strings.  True means they are
              treated as full REs.
        """
        
        if not multiline == None:
            self._flags[0] = multiline
        if not regexs == None:
            self._flags[1] = regexs


    def _parse(self, patt):
        # Do any internal work we need to do on the RE
        if not self._flags[1]:
            return re.escape(patt)
        else:
            return patt
            
            
    def _reflags(self):
        if self._flags[0]:
            return re.M
        else:
             return 0
             
                
    def loadFile(self, file):
        """Load the contents of file into the FileEditor object."""

        fd = open(file)
        # XXX: What do we do about exceptions?
        self._data = fd.read()
        fd.close()


    def loadString(self, string):
        """Load the contents of string into the FileEditor object."""

        self._data = string


    def save(self, file=None):
        if not file:
            file = self._file
        
        fd = open(file, "w")
        fd.write(file)
        fd.close()


    def __str__(self):
        return self._data


    def read(self, n):
        # be compatible with file object?
        pass


    def write(self, str):
        pass


    def grep(self, patt):
        """Returns a list of lines that match patt."""

        patt = self._parse(patt)
        regex = re.compile(patt)
        ret = []
        for line in self._data.split("\n"):
            if regex.search(line):
                ret.append(line)

        return ret

     
    def replace(self, patt, newpatt, n=0):
        """Replace n occurances of patt with newpatt.  If n is 0 replace
           all occurances of patt."""

        patt = self._parse(patt)
        # newpatt isn't a real RE really...but it does support groups
        
        r = re.compile(patt, self._reflags())
        self._data, subs = re.subn(r, newpatt, self._data, n)
        
        return subs


    def insert(self, patt, newpatt):
        """Insert newpatt directly after patt."""

        patt = self._parse(patt)
        
        r = re.compile(patt, self._reflags())
        m = r.search(self._data)
        if m:
            s = m.expand(newpatt)
            self._data = m.string[:m.end()] + s + m.string[m.end():]
        
            return 1
        
        return 0 # no match


    def insertBefore(self, patt, newpatt):
        """Insert newpatt directly before patt."""

        patt = self._parse(patt)
        
        r = re.compile(patt, self._reflags())
        m = r.search(self._data)
        if m:
            s = m.expand(newpatt)
            self._data = m.string[:m.start()] + s + m.string[m.start():]
        
            return 1
        
        return 0 # no match


    def appendUnique(self, s):
        """Appends s to file if patt does not occur in file."""

        r = re.compile(re.escape(s), self._reflags())
        m = r.search(self._data)
        
        if not m:
            # no match
            self.append(s)
            return 1
        else:
            return 0
            
            
    def append(self, s):
        """Appends s to the file"""
        
        self._data = self._data + s
        



        
