# Adapted from http://djangosnippets.org/snippets/1762/

import ast
import os
import sys

from django.core.management.base import BaseCommand
from pyflakes import checker, messages

from orchestra.utils.paths import get_orchestra_root


# BlackHole, PySyntaxError and checking based on
# https://github.com/patrys/gedit-pyflakes-plugin.git
class BlackHole(object):
    write = flush = lambda *args, **kwargs: None
    
    def __enter__(self):
        self.stderr, sys.stderr = sys.stderr, self
    
    def __exit__(self, *args, **kwargs):
        sys.stderr = self.stderr


class PySyntaxError(messages.Message):
    message = 'syntax error in line %d: %s'
    
    def __init__(self, filename, e):
        super(PySyntaxError, self).__init__(filename, e)
        self.message_args = (e.offset, e.text)


def check(codeString, filename):
    """
    Check the Python source given by C{codeString} for flakes.
    
    @param codeString: The Python source to check.
    @type codeString: C{str}
    
    @param filename: The name of the file the source came from, used to report errors.
    @type filename: C{str}
    
    @return: The number of warnings emitted.
    @rtype: C{int}
    """
    try:
        with BlackHole():
            tree = ast.parse(codeString, filename)
    except SyntaxError, e:
        return [PySyntaxError(filename, e)]
    else:
        # Okay, it's syntactically valid.  Now parse it into an ast and check it
        w = checker.Checker(tree, filename)
        
        lines = codeString.split('\n')
        # honour pyflakes: ignore comments
        messages = [message for message in w.messages
                    if lines[message.lineno-1].find('pyflakes:ignore') < 0]
        messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
        return messages


def checkPath(filename):
    """
    Check the given path, printing out any warnings detected.
    @return: the number of warnings printed
    """
    try:
        return check(file(filename, 'U').read() + '\n', filename)
    except IOError, msg:
        return ["%s: %s" % (filename, msg.args[1])]
    except TypeError:
        pass


def checkPaths(filenames):
    warnings = []
    for arg in filenames:
        if os.path.isdir(arg):
            for dirpath, dirnames, filenames in os.walk(arg):
                for filename in filenames:
                    if filename.endswith('.py'):
                        warnings.extend(checkPath(os.path.join(dirpath, filename)))
        else:
            warnings.extend(checkPath(arg))
    return warnings
#### pyflakes.scripts.pyflakes ends.


class Command(BaseCommand):
    help = "Run pyflakes syntax checks."
    args = '[filename [filename [...]]]'
    
    def handle(self, *filenames, **options):
        if not filenames:
            filenames = [get_orchestra_root(), '.']
        warnings = checkPaths(filenames)
        for warning in warnings:
            print warning
        if warnings:
            print 'Total warnings: %d' % len(warnings)
            raise SystemExit(1)
