#!/usr/bin/python

import tokenize
import string

TABSONLY = 'TABSONLY'
SPACESONLY = 'SPACESONLY'
MIXED = 'MIXED'

class PyText:
    def __init__(self, fnm, optdict):
        self.optdict = optdict
        self.fnm = fnm
        self.txt = open(self.fnm, 'r').readlines()
        self.indents = [(0, 0, )]
        self.lnndx = 0
        self.indentndx = 0
    def getline(self):
        if self.lnndx < len(self.txt):
            txt = self.txt[self.lnndx]
            self.lnndx = self.lnndx + 1
        else:
            txt = ''
        return txt
    def tokeneater(self, type, token, start, end, line):
        if type == tokenize.INDENT:
            (lvl, s) = self.indents[-1]
            self.indents[-1] = (lvl, s, start[0]-1)
            self.indents.append((lvl+1, start[0]-1,))
        elif type == tokenize.DEDENT:
            (lvl, s) = self.indents[-1]
            self.indents[-1] = (lvl, s, start[0]-1)
            self.indents.append((lvl-1, start[0]-1,))
        elif type == tokenize.ENDMARKER:
            (lvl, s) = self.indents[-1]
            self.indents[-1] = (lvl, s, len(self.txt))
    def split(self, ln):
        content = string.lstrip(ln)
        if not content:
            return ('', '\n')
        lead = ln[:len(ln) - len(content)]
        lead = string.expandtabs(lead)
        return (lead, content)
        
    def process(self):
        style = self.optdict.get('style', TABSONLY)
        indent = string.atoi(self.optdict.get('indent', '4'))
        tabsz = string.atoi(self.optdict.get('tabs', '8'))
        print 'file %s -> style %s, tabsize %d, indent %d' % (self.fnm, style, tabsz, indent)
        tokenize.tokenize(self.getline, self.tokeneater)
        #import pprint
        #pprint.pprint(self.indents)
        new = []
        for (lvl, s, e) in self.indents:
            if s >= len(self.txt):
                break
            if s == e:
                continue
            oldlead, content = self.split(self.txt[s])
            #print "oldlead", len(oldlead), `oldlead`
            if style == TABSONLY:
                newlead = '\t'*lvl
            elif style == SPACESONLY:
                newlead = ' '*(indent*lvl)
            else:
                sz = indent*lvl
                t,spcs = divmod(sz, tabsz)
                newlead = '\t'*t + ' '*spcs
            new.append(newlead + content)
            for ln in self.txt[s+1:e]:
                lead, content = self.split(ln)
                #print "lead:", len(lead)
                new.append(newlead + lead[len(oldlead):] + content)
        self.save(new)
        #print "---", self.fnm
        #for ln in new:
        #    print ln,
        #print
        
    def save(self, txt):
        bakname = os.path.splitext(self.fnm)[0]+'.bak'
        print "backing up", self.fnm, "to", bakname
        #print os.getcwd()
        try:
            os.rename(self.fnm, bakname)
        except os.error:
            os.remove(bakname)
            os.rename(self.fnm, bakname)
        open(self.fnm, 'w').writelines(txt)
        
def test():
    tc = PyText('test1.py')
    tc.process()
    tc = PyText('test1.py')
    tc.process(style=TABSONLY)
    tc = PyText('test1.py')
    tc.process(style=MIXED, indent=4, tabs=8)
    tc = PyText('test1.py')
    tc.process(style=MIXED, indent=2, tabs=8)
    
def cleanfile(fnm, d):
    if os.path.isdir(fnm) and not os.path.islink(fnm):
        names = os.listdir(fnm)
        for name in names:
            fullnm = os.path.join(fnm, name)
            if (os.path.isdir(fullnm) and not os.path.islink(fullnm)) or \
                os.path.normcase(fullnm[-3:]) == ".py":
                cleanfile(fullnm, d)
        return
    tc = PyText(fnm, d)
    tc.process()
    
usage="""\
%s [options] [path...]
 options
  -T : reformat to TABS ONLY
  -S : reformat to SPACES ONLY ( -i option is important)
  -M : reformat to MIXED SPACES / TABS ( -t and -i options important)
  -t<n> : tab is worth <n> characters
  -i<n> : indents should be <n> characters 
  -h : print this text
 path is file or directory
"""
if __name__ == '__main__':
    import sys, getopt, os
    opts, args = getopt.getopt(sys.argv[1:], "TSMht:i:")
    d = {}
    print `opts`
    for opt in opts:
        if opt[0] == '-T':
            d['style'] = TABSONLY
        elif opt[0] == '-S':
            d['style'] = SPACESONLY
        elif opt[0] == '-M':
            d['style'] = MIXED
        elif opt[0] == '-t':
            d['tabs'] = opt[1]
        elif opt[0] == '-i':
            d['indent'] = opt[1]
        elif opt[0] == '-h':
            print usage % sys.argv[0]
            sys.exit(0)
    if not args:
        print usage % sys.argv[0]
    for arg in args:
        cleanfile(arg, d)
        
        
        
        
        
        
        
        
        
        
        
        
        
        
