import sublime
import sublime_plugin
import os
import re
import sys
#import subprocess

basicTasks = [
    ["lint", "Validate files with JSHint.", "Grunt default tasks"],
    ["qunit", "Run QUnit unit tests in a headless PhantomJS instance.", "Grunt default tasks"],
    ["min", "Minify files with UglifyJS.", "Grunt default tasks"],
    ["watch", "Run predefined tasks whenever watched files change.", "Grunt default tasks"],
    ["server", "Start a static web server.", "Grunt default tasks"],
    ["concat", "Concatenate files.", "Grunt default tasks"],
    ["test", "Run unit tests with nodeunit.", "Grunt default tasks"],
    ["init", "Generate project scaffolding from a predefined template.", "Grunt default tasks"]
]

rFiles = re.compile(r'loadNpmTasks\(\'(.*)\'\)', re.M | re.I)
rSingle = re.compile(r'registerTask.*\(.*\'(.*)\'.*,.*\'(.*)\'.*\)', re.M | re.I)
rMulti = re.compile(r'registerMultiTask.*\(.*\'(.*)\'.*,.*\'(.*)\'.*,', re.M | re.I)
rFunc = re.compile(r'registerMultiTask.*\(.*\'(.*)\'.*,.*\'(.*)\'.*,.*function\((.*)\).*{', re.M | re.I)


class GruntConsole(object):
    def __init__(self, window):
        self.window = window

    @property
    def view(self):
        v = self.window.new_file()
        v.set_name("Grunt")
        v.set_scratch(True)
        return v


class GruntfileParser(object):
    def __init__(self, window):
        self.window = window
        self.grunt_files = []
        self.folders = []
        for f in self.window.folders():
            self.folders.append(f)
            if os.path.exists(os.path.join(f, "grunt.js")):
                self.grunt_files.append(os.path.join(f, "grunt.js"))
            elif os.path.exists(os.path.join(f, "Gruntfile.js")):
                self.grunt_files.append(os.path.join(f, "Gruntfile.js"))
        if len(self.grunt_files) > 0:
            if len(self.grunt_files) == 1:
                self.choose_file(0)
            else:
                self.window.show_quick_panel(self.grunt_files, self.choose_file)
        else:
            sublime.error_message("Gruntfile not found!")

    def extractTasks(self, file, source):
        tasks = []
        try:
            f = open(file, "r")
            for line in f:
                # Single Tasks
                matchSingle = rSingle.search(line)
                matchFunc = rFunc.search(line)
                matchMulti = rMulti.search(line)
                if matchSingle:
                    l = list(matchSingle.groups())
                    l.append(source)
                    tasks.append(l)
                    print(l)
                # Function Tasks
                elif matchFunc:
                    l = list(matchFunc.groups())
                    l.append(source)
                    l[0] = l[0] + ' *'
                    tasks.append(l)
                    print(l)
                # Multi Tasks
                elif matchMulti:
                    l = list(matchMulti.groups())
                    l.append(source)
                    l[0] = l[0] + ' **'
                    tasks.append(l)
                    print(l)
                #match = rMulti.search(line)
                #if match:
                #    self.tasks.append(list(match.groups()))
                #    print(list(match.groups()))
            f.close()
        except IOError:
            sys.stderr.write("[sublime-grunt] - Error: Could not open %s\n" % (file))
            sys.exit(-1)
        except:
            sys.stderr.write("[sublime-grunt] - Error =( \n")
            sys.exit(-1)
        return tasks

    def extractNpmFiles(self, file):
        files = []
        try:
            f = open(file, "r")
            for line in f:
                match = rFiles.search(line)
                if match:
                    files.append(match.groups()[0])
        except IOError:
            sys.stderr.write("[sublime-grunt] - Error: Could not open %s\n" % (file))
            sys.exit(-1)
        finally:
            f.close()
        return files

    def choose_file(self, file):
        self.wd = os.path.dirname(self.grunt_files[file])
        npmTasks = []

        files = self.extractNpmFiles(self.grunt_files[file])
        for f in files:
            taskFiles = [tf for tf in os.listdir(os.path.join(self.wd, "node_modules", f, "tasks")) if tf.lower().endswith('.js')]
            for tf in taskFiles:
                npmTasks = npmTasks + self.extractTasks(os.path.join(self.wd, "node_modules", f, "tasks", tf), "Module: %s" % f)
        self.tasks = self.extractTasks(self.grunt_files[file], self.grunt_files[file]) + npmTasks + basicTasks
        self.window.show_quick_panel(self.tasks, self.on_done)
        #self.window.show_quick_panel(files, self.on_done)

    def on_done(self, task):
        if task > -1:
            exec_args = settings().get('exec_args')
            exec_args.update({'cmd': u"grunt --no-color " + self.tasks[task][0], 'shell': True, 'working_dir': self.folders[0]})
            self.window.run_command("exec", exec_args)


def settings():
    return sublime.load_settings('SublimeGrunt.sublime-settings')


class GruntCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.window = self.view.window()
        GruntfileParser(self.window)
