#
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys

import pager

COLORS = {None: -1,
          'normal': -1,
          'black': 0,
          'red': 1,
          'green': 2,
          'yellow': 3,
          'blue': 4,
          'magenta': 5,
          'cyan': 6,
          'white': 7}

ATTRS = {None: -1,
         'bold': 1,
         'dim': 2,
         'ul': 4,
         'blink': 5,
         'reverse': 7}

RESET = "\033[m"  # pylint: disable=W1401
# backslash is not anomalous

def is_color(s):
    return s in COLORS


def is_attr(s):
    return s in ATTRS


def _Color(fg=None, bg=None, attr=None):
    fg = COLORS[fg]
    bg = COLORS[bg]
    attr = ATTRS[attr]

    if attr >= 0 or fg >= 0 or bg >= 0:
        need_sep = False
        code = "\033["  #pylint: disable=W1401

        if attr >= 0:
            code += chr(ord('0') + attr)
            need_sep = True

        if fg >= 0:
            if need_sep:
                code += ';'
            need_sep = True

            if fg < 8:
                code += '3%c' % (ord('0') + fg)
            else:
                code += '38;5;%d' % fg

        if bg >= 0:
            if need_sep:
                code += ';'
            need_sep = True

            if bg < 8:
                code += '4%c' % (ord('0') + bg)
            else:
                code += '48;5;%d' % bg
        code += 'm'
    else:
        code = ''
    return code


class Coloring(object):
    def __init__(self, config, section_type):
        self._section = 'color.%s' % section_type
        self._config = config
        self._out = sys.stdout

        on = self._config.GetString(self._section)
        if on is None:
            on = self._config.GetString('color.ui')

        if on == 'auto':
            if pager.active or os.isatty(1):
                self._on = True
            else:
                self._on = False
        elif on in ('true', 'always'):
            self._on = True
        else:
            self._on = False

    def redirect(self, out):
        self._out = out

    @property
    def is_on(self):
        return self._on

    def write(self, fmt, *args):
        self._out.write(fmt % args)

    def flush(self):
        self._out.flush()

    def nl(self):
        self._out.write('\n')

    def printer(self, opt=None, fg=None, bg=None, attr=None):
        s = self
        c = self.colorer(opt, fg, bg, attr)

        def f(fmt, *args):
            s._out.write(c(fmt, *args))

        return f

    def colorer(self, opt=None, fg=None, bg=None, attr=None):
        if self._on:
            c = self._parse(opt, fg, bg, attr)

            def f(fmt, *args):
                output = fmt % args
                return ''.join([c, output, RESET])

            return f
        else:
            def f(fmt, *args):
                return fmt % args

            return f

    def _parse(self, opt, fg, bg, attr):
        if not opt:
            return _Color(fg, bg, attr)

        v = self._config.GetString('%s.%s' % (self._section, opt))
        if v is None:
            return _Color(fg, bg, attr)

        v = v.strip().lower()
        if v == "reset":
            return RESET
        elif v == '':
            return _Color(fg, bg, attr)

        have_fg = False
        for a in v.split(' '):
            if is_color(a):
                if have_fg:
                    bg = a
                else:
                    fg = a
            elif is_attr(a):
                attr = a

        return _Color(fg, bg, attr)
