from .file import File
from sublime_plugin import EventListener, WindowCommand, TextCommand
from sublime import load_settings, save_settings, load_resource, packages_path

def clear_cache(force = False):
  """
  If the folder exists, and has more than 5MB of icons in the cache, delete
  it to clear all the icons then recreate it.
  """
  from os.path import getsize, join, isfile, exists
  from os import makedirs, listdir
  from sublime import cache_path
  from shutil import rmtree

  # The icon cache path
  icon_path = join(cache_path(), "GutterColor")

  # The maximum amount of space to take up
  limit = 5242880 # 5 MB

  if exists(icon_path):
    size = sum(getsize(join(icon_path, f)) for f in listdir(icon_path) if isfile(join(icon_path, f)))
    if force or (size > limit): rmtree(icon_path)

  if not exists(icon_path): makedirs(icon_path)

def plugin_loaded():
  clear_cache()
  fix_schemes_in_windows()

class GutterColorClearCacheCommand(WindowCommand):
  def run(self):
    clear_cache(True)

class GutterColorEventListener(EventListener):
  """Scan the view when it gains focus, and when it is saved."""

  def on_activated_async(self, view):
    """Scan file when it gets focus"""
    if syntax(view) in settings().get('supported_syntax'):
      fix_scheme_in_view(view)
      File(view)

  def on_modified(self, view):
    """Scan file when it is modified"""
    if syntax(view) in settings().get('supported_syntax'):
      File(view, 'update')

  def on_pre_save_async(self, view):
    """Scan file before it is saved"""
    if syntax(view) in settings().get('supported_syntax'):
      File(view, 'update')

def settings():
  """Shortcut to the settings"""
  return load_settings("GutterColor.sublime-settings")

def syntax(view):
  """Return the view syntax"""
  syntax = view.settings().get('syntax')
  return syntax.split('/')[-1].split('.')[0].lower() if syntax is not None else "plain text"

def current_directory(full=False):
  """Return the name of the directory containing this plugin"""
  from os.path import dirname, realpath, split
  if full:
    return dirname(realpath(__file__))
  else:
    return split(dirname(realpath(__file__)))[1]

def fix_schemes_in_windows():
  """Change color schemes for all current views in the supported syntax list"""
  from sublime import windows
  for window in windows():
    for view in window.views():
      if syntax(view) in settings().get('supported_syntax'):
        fix_scheme_in_view(view)

def fix_scheme_in_view(view, regenerate=False, ignore_flags=False):
  """Change color scheme in settings relevant to current view"""
  fix_flag = settings().get("fix_color_schemes", False)
  (fix_syntax, fix_global, fix_custom) = (False, False, False)
  custom_files = []
  if fix_flag == True:
    (fix_syntax, fix_global) = (True, True)
  elif isinstance(fix_flag, list):
    for label in fix_flag:
      if label in ("syntax", "syntax-specific"):
        fix_syntax = True
      if label in ("user", "global", "preferences"):
        fix_global = True
      if ".sublime-settings" in label:
        fix_custom = True
        custom_files.append(label)
  elif ignore_flags:
    pass # otherwise we might quit when we want to force a check contrary to user prefs
  else:
    return # setting is false, nonexistant, or malformed, so exit

  current_scheme = view.settings().get("color_scheme")
  modified_marker = ".gcfix."
  if modified_marker in current_scheme:
    if regenerate:
      new_scheme = current_scheme
    else:
      return # this view already has a fixed scheme and we aren't regenerating, so exit
  else:
    new_scheme =  "Packages/"+current_directory()+"/"+current_scheme.split("/")[-1].split(".")[0]+\
                  modified_marker + current_scheme.split(".")[-1]

  if fix_custom:
    for custom_filename in custom_files:
      if fix_scheme_in_settings(custom_filename, current_scheme, new_scheme):
        return
  if fix_syntax or ignore_flags:
    syntax_filename = view.settings().get('syntax').split('/')[-1].split('.')[0] + ".sublime-settings"
    if fix_scheme_in_settings(syntax_filename, current_scheme, new_scheme):
      return
  if fix_global or ignore_flags:
    if fix_scheme_in_settings("Preferences.sublime-settings", current_scheme, new_scheme):
      return
  print("Could not find or access the settings file where current color_scheme ("+current_scheme+") is set.")

def fix_scheme_in_settings(settings_file,current_scheme, new_scheme, regenerate=False):
  """Change the color scheme in the given Settings to a background-corrected one"""
  from os.path import join, normpath, isfile

  settings = load_settings(settings_file)
  settings_scheme = settings.get("color_scheme")
  if current_scheme == settings_scheme:
    new_scheme_path =  join(packages_path(), normpath(new_scheme[len("Packages/"):]))
    if isfile(new_scheme_path) and not regenerate:
      settings.set("color_scheme", new_scheme)
    else:
      generate_scheme_fix(current_scheme, new_scheme_path)
      settings.set("color_scheme", new_scheme)
    save_settings(settings_file)
    return True
  return False

def generate_scheme_fix(old_scheme, new_scheme_path):
  """Appends background-correction XML to a color scheme file"""
  from os.path import join
  from re import sub
  UUID_REGEX = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}'

  with open(join(packages_path(),current_directory(),'background_fix.xml')) as f:
    xml = f.read()
  scheme_data = load_resource(old_scheme) # only valid for ST3 API!

  insertion_point = scheme_data.rfind("</array>")
  new_scheme_data = scheme_data[:insertion_point] + xml + scheme_data[insertion_point:]

  def uuid_gen(args):
    from uuid import uuid4
    return str(uuid4())
  new_scheme_data = sub(UUID_REGEX, uuid_gen, new_scheme_data)

  with open(new_scheme_path, "wb") as f:
    f.write(new_scheme_data.encode("utf-8"))

class GutterColorFixCurrentScheme(TextCommand):
  def run(self, args):
    fix_scheme_in_view(self.view, True, True)