from itertools import count

import six

from pypugjs import Compiler as _Compiler


def process_param(key, value, terse=False):
    # Always render boolean True as presence-only attribute
    if value is True:
        return key
    if terse and (key == value):
        return key
    if isinstance(value, six.binary_type):
        value = value.decode('utf8')
    return '''%s="%s"''' % (key, value)


class Compiler(_Compiler):
    def __init__(self, *args, **kws):
        _Compiler.__init__(self, *args, **kws)
        self._i = count()

    def visitAssignment(self, assignment):
        self.buffer('<%% var %s = %s; %%>' % (assignment.name, assignment.val))

    def visitCode(self, code):
        if code.buffer:
            val = code.val.lstrip()
            self.buf.append('<%%%s %s %%>' % ('=' if code.escape else '-', val))
        else:
            self.buf.append('<%% %s' % code.val)  # for loop

        if code.block:
            self.buf.append(' { %>')  # for loop
            # if not code.buffer: self.buf.append('{')
            self.visit(code.block)
            # if not code.buffer: self.buf.append('}')

            if not code.buffer:
                codeTag = code.val.strip().split(' ', 1)[0]
                if codeTag in self.auto_close_code:
                    self.buf.append('<% } %>')
        elif not code.buffer:
            self.buf.append('; %>')  # for loop

    def visitEach(self, each):
        # self.buf.append('{%% for %s in %s %%}'%(','.join(each.keys),each.obj))
        __i = self._i.next()
        self.buf.append(
            '<%% for (_i_%s = 0, _len_%s = %s.length; _i_%s < _len_%s; _i_%s++) '
            '{ ' % (__i, __i, each.obj, __i, __i, __i)
        )
        if len(each.keys) > 1:
            for i, k in enumerate(each.keys):
                self.buf.append('%s = %s[_i_%s][%s];' % (k, each.obj, __i, i))
        else:
            for k in each.keys:
                self.buf.append('%s = %s[_i_%s];' % (k, each.obj, __i))
        self.buf.append(' %>')
        self.visit(each.block)
        self.buf.append('<% } %>')

    def _do_eval(self, value):
        if isinstance(value, six.string_types):
            value = value.encode('utf-8')
        try:
            value = eval(value, {}, {})
        except Exception:
            return "<%%= %s %%>" % value
        return value

    def _get_value(self, attr):
        value = attr['val']
        if attr['static']:
            return attr['val']
        if isinstance(value, six.string_types):
            return self._do_eval(value)
        else:
            return attr['name']

    def visitAttributes(self, attrs):
        classes = []
        params = []
        for attr in attrs:
            if attr['name'] == 'class':
                value = self._get_value(attr)
                if isinstance(value, list):
                    classes.extend(value)
                else:
                    classes.append(value)
            else:
                value = self._get_value(attr)
                if (value is not None) and (value is not False):
                    params.append((attr['name'], value))
        if classes:
            classes = [six.text_type(c) for c in classes]
            params.append(('class', " ".join(classes)))
        if params:
            self.buf.append(
                " " + " ".join([process_param(k, v, self.terse) for (k, v) in params])
            )

    def visitConditional(self, conditional):
        TYPE_CODE = {
            'if': lambda x: 'if (%s)' % x,
            'unless': lambda x: 'if (!%s)' % x,
            'elif': lambda x: '} else if (%s)' % x,
            'else': lambda x: '} else',
        }
        self.buf.append(
            '\n<%% %s { %%>' % TYPE_CODE[conditional.type](conditional.sentence)
        )
        if conditional.block:
            self.visit(conditional.block)
            for next in conditional.next:
                self.visitConditional(next)
        if conditional.type in ['if', 'unless']:
            self.buf.append('\n<% } %>\n')

    def interpolate(self, text, escape=True):
        return self._interpolate(text, lambda x: '<%%= %s %%>' % x)
