import sublime
import sublime_plugin

from ..core import oa_syntax, oa_setting, decorate_pkg_name, log
from ..core import packages_with_overrides, ReportGenerationThread
from ...lib.packages import PackageList


###----------------------------------------------------------------------------


class BulkDiffReportThread(ReportGenerationThread):
    """
    Perform a bulk diff of all overrides in either all packages or a single
    package, depending on the argument provided.

    This is invoked from OverrideAuditDiffOverride when you invoke that command
    with the bulk argument set to true.
    """
    def _process(self):
        package = self.args["package"]
        force_reuse = self.args["force_reuse"]

        pkg_list = PackageList(package)

        if package is not None:
            if package not in pkg_list:
                return log("Cannot diff package '%s'; not found" % package,
                            status=True, dialog=True)

            items = [package]
        else:
            items = packages_with_overrides(pkg_list)

        self._diff_packages(items, pkg_list, package is not None, force_reuse)

    def _diff_packages(self, names, pkg_list, single_package, force_reuse):
        context_lines = oa_setting("diff_context_lines")
        binary_patterns = oa_setting("binary_file_patterns")

        result = []
        title = "Override Diff Report: "
        description = "Bulk Diff Report for overrides in"
        report_type = ":bulk_all"
        expired_pkgs = []

        if len(names) == 1 and single_package:
            title += names[0]
            result.append(description + " {}\n".format(names[0]))
            report_type = names[0]
        elif len(names) == 0:
            title += "All Packages"
            result.append("No packages with overrides found to diff\n")
        else:
            title += "All Packages"
            result.append(description + " {} packages\n".format(len(names)))

        result.append(self._generation_time())

        for name in names:
            pkg_info = pkg_list[name]
            if binary_patterns is not None:
                pkg_info.set_binary_pattern(binary_patterns)

            result.append(decorate_pkg_name(pkg_info))
            self._perform_diff(pkg_info, context_lines, result,
                               expired_pkgs)

        self._set_content(title, result, report_type, oa_syntax("OA-Diff"),
                          {"override_audit_expired_pkgs": expired_pkgs})

    def _perform_diff(self, pkg_info, context_lines, result, expired_pkgs):
        override_list = pkg_info.override_files(simple=True)
        expired_list = pkg_info.expired_override_files(simple=True)
        empty_diff_hdr = oa_setting("diff_empty_hdr")

        if expired_list:
            expired_pkgs.append(pkg_info.name)

        for file in override_list:
            if file in expired_list:
                result.append("    [X] {}".format(file))
            else:
                result.append("    {}".format(file))

            diff = pkg_info.override_diff(file, context_lines,
                                          empty_result="No differences found",
                                          binary_result="<File is binary>",
                                          indent=8)

            if diff is None:
                content = (" " * 8) + ("Error opening or decoding file;"
                                       " is it UTF-8 or Binary?")
            else:
                prefix = diff.hdr if diff.is_empty and empty_diff_hdr else ""
                content = prefix + diff.result

            result.extend([content, ""])

        if len(override_list) == 0:
            if pkg_info.has_possible_overrides(simple=True):
                result.append("    <No simple overrides found>")
            else:
                reason = ("no sublime-package" if pkg_info.is_unpacked() else
                          "no unpacked files")
                result.append("    <No overrides possible; %s>" % reason)
        result.append("")


###----------------------------------------------------------------------------


class OverrideAuditDiffReportCommand(sublime_plugin.WindowCommand):
    """
    Perform a bulk diff of all overrides in either all packages or a single
    package, depending on the argument provided.

    This is invoked from OverrideAuditDiffOverride when you invoke that command
    with the bulk argument set to true.
    """
    def run(self, package=None, force_reuse=False):
        BulkDiffReportThread(self.window, "Generating Bulk Diff",
                             self.window.active_view(),
                             package=package, force_reuse=force_reuse).start()


###----------------------------------------------------------------------------

@@ -202,16 +202,36 @@
 kageList
+, OverrideDiffResult
 %0A%0A%0A###--
@@ -1528,16 +1528,43 @@
 kgs = %5B%5D
+%0A        unknown_files = %7B%7D
 %0A%0A      
@@ -2382,16 +2382,31 @@
 red_pkgs
+, unknown_files
 )%0A%0A     
@@ -2503,16 +2503,45 @@
        %7B
+%0A                            
 %22overrid
@@ -2575,16 +2575,122 @@
 red_pkgs
+,%0A                            %22override_audit_unknown_overrides%22: unknown_files%0A                          
 %7D)%0A%0A    
@@ -2758,18 +2758,82 @@
 red_pkgs
+, unknown_files):%0A        pkg_files = pkg_info.unpacked_contents(
 )
-:
 %0A       
@@ -2946,32 +2946,95 @@
 es(simple=True)%0A
+        unknown_overrides = pkg_info.unknown_override_files()%0A%0A
         empty_di
@@ -3157,201 +3157,637 @@
     
-for file in override_list:%0A            if file in expired_list:%0A                result.append(%22    %5BX%5D %7B%7D%22.format(file))%0A            else:%0A                result.append(%22    %7B%7D%22.format(file))%0A%0A
+if unknown_overrides:%0A            unknown_files%5Bpkg_info.name%5D = list(unknown_overrides)%0A%0A        for file in pkg_files:%0A            if file in expired_list:%0A                result.append(%22    %5BX%5D %7B%7D%22.format(file))%0A            elif file in unknown_overrides:%0A                result.append(%22    %5B?%5D %7B%7D%22.format(file))%0A            else:%0A                result.append(%22    %7B%7D%22.format(file))%0A%0A            if file in unknown_overrides:%0A                diff = OverrideDiffResult(None, None, (%22 %22 * 8) +%0A                                          %22%3CFile does not exist in the underlying package file; cannot diff%3E%22)%0A            else:%0A    
     
@@ -3845,16 +3845,20 @@
 _lines,%0A
+    
         
@@ -3966,24 +3966,28 @@
             
+    
 binary_resul
@@ -4008,16 +4008,20 @@
 nary%3E%22,%0A
+    
         

Extend the bulk diff report for unknown overrides