class Between(object):
    value = attr.ib() class Case(object):
    value = attr.ib()
    when_elses = attr.ib() class Condition(object):
    values = attr.ib() class Else(object):
    else_ = attr.ib()
    result = attr.ib()

    def __str__(self):
        return 'ELSE %s' % self.result class From(object):
    value = attr.ib()
    values = attr.ib() class Func(object):
    name = attr.ib()
    args = attr.ib()
    as_ = attr.ib(default=None)
    alias = attr.ib(default=None) class GroupBy(object):
    values = attr.ib()
    with_rollup = attr.ib(default=None) class Having(object):
    value = attr.ib()
    values = attr.ib() class Identifier(object):
    value = attr.ib()
    alias = attr.ib(default=None)
    as_ = attr.ib(default=None)
    sort = attr.ib(default=None)

    def __str__(self):
        return '%s' % self.value class Insert(object):
    insert = attr.ib()
    table = attr.ib()
    values = attr.ib(default=[])
    cols = attr.ib(default=[])
    select = attr.ib(default=[]) class InvalidSQL(Exception):
    pass class Is(object):
    value = attr.ib() class Join(object):
    value = attr.ib() class Limit(object):
    row_count = attr.ib()
    offset = attr.ib(default=None)
    offset_keyword = attr.ib(default=None) class Link(object):
    value = attr.ib() class Not(object):
    value = attr.ib() class Null(object):
    value = attr.ib() class Number(object):
    value = attr.ib()
    alias = attr.ib(default=None)
    as_ = attr.ib(default=None)
    sort = attr.ib(default=None)

    def __str__(self):
        return '%s' % self.value class On(object):
    value = attr.ib()
    values = attr.ib(default=[]) class Operator(object):
    value = attr.ib()

    def __str__(self):
        return '%s' % self.value.upper() class OrderBy(object):
    values = attr.ib() class Select(object):
    value = attr.ib()
    values = attr.ib() class Semicolon(object):
    value = attr.ib() class Str(object):
    value = attr.ib()
    alias = attr.ib(default=None)
    as_ = attr.ib(default=None)
    sort = attr.ib(default=None)

    def __str__(self):
        return '%s' % self.value class SubSelect(object):
    values = attr.ib() class When(object):
    when = attr.ib()
    condition = attr.ib()
    then = attr.ib()
    result = attr.ib()

    def __str__(self):
        return 'WHEN %s THEN %s' % (self.condition, self.result) class Where(object):
    value = attr.ib()
    conditions = attr.ib()
from format_sql.parser import (Between, Case, Condition, Else, From, Func,
                               GroupBy, Having, Identifier, Insert, InvalidSQL,
                               Is, Join, Limit, Link, Not, Null, Number, On,
                               Operator, OrderBy, Select, Semicolon, Str,
                               SubSelect, When, Where)
                    liner.add_to_line('AND ')
                    new_line = False

                elif isinstance(v, Condition):
                    for vv in v.values:
                        if isinstance(vv, Func):
                            _style_func(vv, liner, end_line=False)
                        elif isinstance(vv, Identifier):
                            liner.add_to_line('%s' % vv)
                        else:
                            liner.add_to_line(' %s ' % vv)

                    liner.end_line()
                    new_line = True

            i += 1

        liner.end_line()
        i += 1


def _style_group_by(group_by, liner, indent):
    liner.add_line('    ' * indent + 'GROUP BY')

    for i, value in enumerate(group_by.values):
        liner.add_to_line('    %s' % value)
        if i + 1 < len(group_by.values):
            liner.add_to_line(',')
        liner.end_line()

    if group_by.with_rollup:
        liner.add_line('    ' * (indent + 1) + 'WITH ROLLUP')


def _style_limit(limit, liner, indent):
    if all([limit.row_count, limit.offset, limit.offset_keyword]):
        line = 'LIMIT %s OFFSET %s' % (limit.row_count.value,
                                       limit.offset.value)
    elif all([limit.row_count, limit.offset]):
        line = 'LIMIT %s, %s' % (limit.offset.value, limit.row_count.value)
    else:
        line = 'LIMIT %s' % limit.row_count.value

    liner.add_line('    ' * indent + line)


def _style_order_by(order_by, liner, indent):
    liner.add_line('    ' * indent + 'ORDER BY')

    for i, value in enumerate(order_by.values):
        liner.add_to_line('    ' * (indent + 1) + '%s' % value)

        if value.sort:
            sort = value.sort.upper()
            liner.add_to_line(' %s' % sort)

        if i + 1 < len(order_by.values):
            liner.add_to_line(',')

        liner.end_line()


def _style_having(having, liner, indent):
    liner.add_line('    ' * indent + 'HAVING')

    i = 0
    while i < len(having.values):
        liner.add_to_line('    ' * (indent + 1))

        if isinstance(having.values[i], Link):
            liner.add_to_line('%s ' % having.values[i].value.upper())
            i += 1

        condition = having.values[i]

        if types_match(condition, [Identifier, Operator, Number]):
            liner.add_to_line(' '.join('%s' % x for x in condition.values))
            i += 1
            liner.end_line()

        if types_match(condition, [Not, Func, Operator, Number]):
            liner.add_to_line('NOT')
            liner.add_to_line(' ')
            _style_func(condition.values[1], liner, end_line=False)
            liner.add_to_line(' ')
            liner.add_to_line(condition.values[2])
            liner.add_to_line(' ')
            liner.add_to_line(condition.values[3])
            i += 1

    liner.end_line()


def _style_condition(condition, liner, indent):

    if len(condition.values) == 4 and isinstance(condition.values[0], Not):
        liner.add_to_line('NOT ')
        condition.values.pop(0)

    if types_match(condition, [(Identifier, Number, Str),
                               Operator,
                               (Identifier, Number, Str)]):

        liner.add_to_line(' '.join('%s' % x for x in condition.values))

    elif types_match(condition, [(Identifier, Number, Str),
                                 Between,
                                 (Identifier, Number, Str),
                                 Link,
                                 (Identifier, Number, Str)]):
        liner.add_to_line('%s BETWEEN %s AND %s' % (condition.values[0],
                                                    condition.values[2],
                                                    condition.values[4]))

    elif types_match(condition, [(Identifier, Number, Str), Is, Null]):
        liner.add_to_line('%s IS NULL' % condition.values[0])

    elif types_match(condition, [(Identifier, Number, Str), Is, Not, Null]):
        liner.add_to_line('%s IS NOT NULL' % condition.values[0])


    elif types_match(condition, [(Identifier, Number, Str), Operator, list]):