# Copyright 2011 The Emscripten Authors.  All rights reserved.
# Emscripten is available under two separate licenses, the MIT license and the
# University of Illinois/NCSA Open Source License.  Both these licenses can be
# found in the LICENSE file.

"""Simple color-enabled diagnositics reporting functions.
"""

import ctypes
import logging
import os
import sys


WINDOWS = sys.platform.startswith('win')

logger = logging.getLogger('diagnostics')
color_enabled = sys.stderr.isatty()
tool_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]

# diagnostic levels
WARN = 1
ERROR = 2
FATAL = 3

# available colors
RED = 1
GREEN = 2
YELLOW = 3
BLUE = 4
MAGENTA = 5
CYAN = 6
WHITE = 7

# color for use for each diagnostic level
level_colors = {
    WARN: MAGENTA,
    ERROR: RED,
}

level_prefixes = {
    WARN: 'warning: ',
    ERROR: 'error: ',
}

# Constants from the Windows API
STD_OUTPUT_HANDLE = -11


def output_color_windows(color):
  # TODO(sbc): This code is duplicated in colored_logger.py.  Refactor.
  # wincon.h
  FOREGROUND_BLACK     = 0x0000 # noqa
  FOREGROUND_BLUE      = 0x0001 # noqa
  FOREGROUND_GREEN     = 0x0002 # noqa
  FOREGROUND_CYAN      = 0x0003 # noqa
  FOREGROUND_RED       = 0x0004 # noqa
  FOREGROUND_MAGENTA   = 0x0005 # noqa
  FOREGROUND_YELLOW    = 0x0006 # noqa
  FOREGROUND_GREY      = 0x0007 # noqa

  color_map = {
    RED: FOREGROUND_RED,
    GREEN: FOREGROUND_GREEN,
    YELLOW: FOREGROUND_YELLOW,
    BLUE: FOREGROUND_BLUE,
    MAGENTA: FOREGROUND_MAGENTA,
    CYAN: FOREGROUND_CYAN,
    WHITE: FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
  }

  sys.stderr.flush()
  hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
  ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, color_map[color])


def get_color_windows():
  SHORT = ctypes.c_short
  WORD = ctypes.c_ushort

  class COORD(ctypes.Structure):
    _fields_ = [
      ("X", SHORT),
      ("Y", SHORT)]

  class SMALL_RECT(ctypes.Structure):
    _fields_ = [
      ("Left", SHORT),
      ("Top", SHORT),
      ("Right", SHORT),
      ("Bottom", SHORT)]

  class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
    _fields_ = [
      ("dwSize", COORD),
      ("dwCursorPosition", COORD),
      ("wAttributes", WORD),
      ("srWindow", SMALL_RECT),
      ("dwMaximumWindowSize", COORD)]

  hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
  csbi = CONSOLE_SCREEN_BUFFER_INFO()
  ctypes.windll.kernel32.GetConsoleScreenBufferInfo(hdl, ctypes.byref(csbi))
  return csbi.wAttributes


def reset_color_windows():
  sys.stderr.flush()
  hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
  ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, default_color)


def output_color(color):
  if WINDOWS:
    return output_color_windows(color)
  return '\033[3%sm' % color


def reset_color():
  if WINDOWS:
    return reset_color_windows()
  return '\033[0m'


def diag(level, msg, *args):
  # Format output message as:
  # <tool>: <level>: msg
  # With the `<level>:` part being colored accordingly.
  sys.stderr.write(tool_name + ': ')

  if color_enabled:
    output = output_color(level_colors[level])
    if output:
      sys.stderr.write(output)

  sys.stderr.write(level_prefixes[level])

  if color_enabled:
    output = reset_color()
    if output:
      sys.stderr.write(output)

  if args:
    msg = msg % args
  sys.stderr.write(str(msg))
  sys.stderr.write('\n')


def error(msg, *args):
  diag(ERROR, msg, *args)
  sys.exit(1)


def warn(msg, *args):
  diag(WARN, msg, *args)


class WarningManager(object):
  warnings = {}

  def add_warning(self, name, enabled=True, part_of_all=True, shared=False, error=False):
    self.warnings[name] = {
      'enabled': enabled,
      'part_of_all': part_of_all,
      # True for flags that are shared with the underlying clang driver
      'shared': shared,
      'error': error,
    }

  def capture_warnings(self, cmd_args):
    for i in range(len(cmd_args)):
      if cmd_args[i] == '-w':
        for warning in self.warnings.values():
          warning['enabled'] = False
        continue

      if not cmd_args[i].startswith('-W'):
        continue

      if cmd_args[i] == '-Wall':
        for warning in self.warnings.values():
          if warning['part_of_all']:
            warning['enabled'] = True
        continue

      if cmd_args[i] == '-Werror':
        for warning in self.warnings.values():
          warning['error'] = True
        continue

      if cmd_args[i].startswith('-Werror=') or cmd_args[i].startswith('-Wno-error='):
        warning_name = cmd_args[i].split('=', 1)[1]
        if warning_name in self.warnings:
          enabled = not cmd_args[i].startswith('-Wno-')
          self.warnings[warning_name]['error'] = enabled
          if enabled:
            self.warnings[warning_name]['enabled'] = True
          cmd_args[i] = ''
          continue

      warning_name = cmd_args[i].replace('-Wno-', '').replace('-W', '')
      enabled = not cmd_args[i].startswith('-Wno-')

      # special case pre-existing warn-absolute-paths
      if warning_name == 'warn-absolute-paths':
        self.warnings['absolute-paths']['enabled'] = enabled
        cmd_args[i] = ''
        continue

      if warning_name in self.warnings:
        self.warnings[warning_name]['enabled'] = enabled
        if not self.warnings[warning_name]['shared']:
          cmd_args[i] = ''
        continue

    return cmd_args

  def warning(self, warning_type, message, *args):
    warning_info = self.warnings[warning_type]
    msg = (message % args) + ' [-W' + warning_type.lower().replace('_', '-') + ']'
    if warning_info['enabled']:
      if warning_info['error']:
        error(msg + ' [-Werror]')
      else:
        warn(msg)
    else:
      logger.debug('disabled warning: ' + msg)


def add_warning(name, enabled=True, part_of_all=True, shared=False, error=False):
  manager.add_warning(name, enabled, part_of_all, shared, error)


def enable_warning(name, as_error=False):
  manager.warnings[name]['enabled'] = True
  if as_error:
    manager.warnings[name]['error'] = True


def disable_warning(name):
  manager.warnings[name]['enabled'] = False


def warning(warning_type, message, *args):
  manager.warning(warning_type, message, *args)


def capture_warnings(argv):
  return manager.capture_warnings(argv)


if WINDOWS:
  default_color = get_color_windows()

manager = WarningManager()
