# -*- coding: utf-8 -*-

# Copyright (c) 2003 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a simple Python syntax checker.
"""

import sys
import os
import types

from qt import *

from SyntaxCheckerForm import SyntaxCheckerForm
import Utilities

class SyntaxCheckerDialog(SyntaxCheckerForm):
    """
    Class implementing a dialog to display the results of a syntax check run.
    """
    def __init__(self, viewmanager, parent = None):
        """
        Constructor
        
        Arguments
        
            viewmanager -- reference to the viewmanager object
            
            parent -- parent widget (QWidget)
        """
        SyntaxCheckerForm.__init__(self, parent)
        
        self.vm = viewmanager
        self.noResults = 1
        self.cancelled = 0
        
    def start(self, fn):
        """
        Public slot to start the syntax check.
        
        Arguments
        
            fn -- file or list of files or directory to be checked
                (string or list of strings)
        """
        if type(fn) is types.ListType:
            files = fn
        elif os.path.isdir(fn):
            files = Utilities.direntries(fn, 1, '*.py', 0)
        else:
            files = [fn]
        
        self.checkProgress.setTotalSteps(len(files))
        qApp.processEvents()
        
        # now go through all the files
        progress = 0
        for file in files:
            if self.cancelled:
                return
            
            ok, fname, line, code, error = self.compile(file)
            if ok:
                self.noResults = 0
                itm = QListViewItem(self.resultList,
                    fname, line, error, code)
            progress += 1
            self.checkProgress.setProgress(progress)
            qApp.processEvents()
                    
        self.finish()
        
    def finish(self):
        """
        Private slot called when the syntax check finished or the user pressed the button.
        """
        self.cancelled = 1
        self.cancelButton.setText(self.trUtf8('OK'))
        self.cancelButton.setDefault(1)
        
        if self.noResults:
            itm = QListViewItem(self.resultList,
                self.trUtf8('No syntax errors found.'))
        
    def buttonPressed(self):
        """
        Private slot connected to the button clicked signal.
        """
        if self.cancelled:
            self.close()
        else:
            self.finish()
            
    def openFile(self, itm):
        """
        Private slot to handle the doubleClicked signal of the result list.
        """
        if self.noResults:
            return
            
        fn = Utilities.normabspath(str(itm.text(0)))
        lineno = int(str(itm.text(1)))
        
        self.vm.handlePythonFile(fn, lineno)
        
    def compile(self, file):
        """
        Private method to compile one Python source file to Python bytecode.
        
        Arguments
        
            file -- source filename (string)
            
        Returns
        
            A tuple indicating status (1 = an error was found), the
            filename, the linenumber, the code string and the error message
            (boolean, string, string, string, string). The values are only
            valid, if the status equals 1.
        """
        import __builtin__
        f = open(file)
        codestring = f.read()
        # If parsing from a string, line breaks are \n (see parsetok.c:tok_nextc)
        # Replace will return original string if pattern is not found, so
        # we don't need to check whether it is found first.
        codestring = codestring.replace("\r\n","\n")
        codestring = codestring.replace("\r","\n")
        f.close()
        if codestring and codestring[-1] != '\n':
            codestring = codestring + '\n'
            
        try:
            codeobject = __builtin__.compile(codestring, file, 'exec')
        except SyntaxError, detail:
            import traceback, re
            lines = traceback.format_exception_only(SyntaxError, detail)
            match = re.match('\s*File "(.+)", line (\d+)', 
                lines[0].replace('<string>', '%s' % file))
            fn, line = match.group(1, 2)
            code = re.match('(.+)', lines[1]).group(1)
            error = re.match('SyntaxError: (.+)', lines[3]).group(1)
            return (1, fn, line, code, error)
            
        return (0, None, None, None, None)
    
