#! /usr/bin/env python

import os
from abjad.tools import iotools
from abjad.tools import mathtools


def _reindent_3_spaces_as_4():
    reindented = [ ]
    indented = [ ]
    skipped = [ ]
    for path, subdirectories, files in os.walk('.'):
        for file in files:
            if not file.startswith('__') and (file.endswith('.py') or file.endswith('.rst.raw')):
                _strip_trailing_whitespace(file, path)
                gcd = _find_indent_gcd(file, path)
                if gcd == 1:
                    inconsistencies = _find_inconsistent_indents(file, path)
                    skipped.append((os.path.join(path, file), inconsistencies))
                elif gcd == 4:
                    indented.append(os.path.join(path, file))
                elif gcd == 3:
                    _reindent(file, path)
                    reindented.append(os.path.join(path, file))
    _print_results(reindented, indented, skipped)


def _strip_trailing_whitespace(file, path):
    file_path = os.path.join(path, file)
    f = open(file_path, 'r')
    lines = f.read().split('\n')
    f.close()
    for i, line in enumerate(lines):
        lines[i] = line.rstrip()
    f = open(file_path, 'w')
    f.write('\n'.join(lines))
    f.close()


def _find_indent_gcd(file, path):
    indents = [ ]
    file_path = os.path.join(path, file)
    f = open(file_path, 'r')
    lines = f.read().split('\n')
    f.close()
    for i, line in enumerate(lines):
        if 0 < len(line.lstrip()):
            indent = len(line) - len(line.lstrip())
            if 0 < indent:
                indents.append(indent)
    if indents:
        return mathtools.greatest_common_divisor(*indents)
    else:
        return 4 # nothing indented, so ignore


def _find_inconsistent_indents(file, path):
    inconsistencies = [ ]
    file_path = os.path.join(path, file)
    f = open(file_path, 'r')
    lines = f.read().split('\n')
    f.close()
    for i, line in enumerate(lines):
        if 0 < len(line.lstrip()):
            indent = len(line) - len(line.lstrip())
            if 0 < indent:
                if 0 < (indent % 3):
                    inconsistencies.append(i)
    return inconsistencies


def _reindent(file, path):
    file_path = os.path.join(path, file)
    f = open(file_path, 'r')
    lines = f.read().split('\n')
    f.close()
    for i, line in enumerate(lines):
        indent = len(line) - len(line.lstrip())
        div, mod = divmod(indent, 3)
        if mod != 0:
            print 'Unexpected indent (%d, %d) in %s:%d' % (div, mod, file_path, mod)
            if 0 < i:
                print '%d:\t"%s"' % (i - 1, lines[i - 1])
            print '%d:\t"%s"' % (i, line)
            if line != lines[-1]:
                print '%d:\t"%s"' % (i + 1, lines[i + 1])
            raise Exception()
        lines[i] = lines[i].replace('   ' * div, '    ' * div)
    f = open(file_path, 'w')
    f.write('\n'.join(lines))
    f.close()


def _print_results(reindented, indented, skipped):
    print '%d FILE(S) REINDENTED.' % len(reindented)
    for x in reindented:
        print '\t%s' % x
    print '%d FILE(S) ALREADY INDENTED.' % len(indented)
    print '%d FILE(S) SKIPPED DUE TO INCONSISTENT INDENTATION.' % len(skipped)
    #for x in skipped:
    #    print '\t%s' % x[0]
    #    print '\t\t@ %s' % ', '.join([str(line_number + 1) for line_number in x[1]])


if __name__ == '__main__':
    iotools.clear_terminal()
    _reindent_3_spaces_as_4()
    print ''
