import sys
import bisect # Sorting of list
from enum import Enum
import i3_lemonbar_config as config
import i3_lemonbar_common as common

sr = config.sep_right
slr = config.sep_l_right
sl = config.sep_left
sll = config.sep_l_left

class LemonUnit:
    def __lt__(self, other):
        return self.order < other.order


class IconTextUnit(LemonUnit):
    def __init__(self, name, order, action = None, alt_scheme=None, external=None):
        self.name = name
        self.action = action
        self.order = order
        self.alt_scheme = alt_scheme # None means default
        self.external = external
        self.items = [] # List of tuples (icon, text)
        self.modes = [common.bar_mode.normal]

    def format(self):
        close = block(click='') if self.action is not None else ''

        b_color = self.alt_scheme.back_color
        i_color = self.alt_scheme.icon_color
        t_color = self.alt_scheme.text_color

        # Start with a major separator. Keep previous background color, set foreground color
        # of separator to background color of this unit
        blocks = []
        blocks.append(block(fg=b_color, append=sl))
        blocks.append(' ') # TODO perhaps more nice solution than manual spacing
        if len(self.items) >= 1:
            (icon, text) = self.items[0]
            blocks.append(block(click=self.action, fg=i_color, bg=b_color, font='2'
                , append=' ' + icon))
            blocks.append(' ')
            blocks.append(block(fg=t_color, font='1', append=text))
        if len(self.items) >= 2:
            for item in self.items[1:]:
                (icon, text) = item
                # Append minor separator
                blocks.append(' ')
                blocks.append(sll)

                blocks.append(block(fg=i_color, bg=b_color, font='2', append=' ' + icon))
                blocks.append(' ')
                blocks.append(block(fg=t_color, font='1', append=text))

        if len(self.items) >= 1:
            blocks.append(close)
        return ''.join(blocks)

class ButtonsUnit(LemonUnit):
    def __init__(self, name, order, alt_scheme=None, external=None):
        self.name = name
        self.order = order
        self.alt_scheme = alt_scheme # None means default
        self.external = external
        self.items = [] # List of tuples (icon, text, action)
        self.modes = [common.bar_mode.normal]

    def format(self):
        b_color = self.alt_scheme.back_color
        i_color = self.alt_scheme.icon_color
        t_color = self.alt_scheme.text_color

        # Start with a major separator. Keep previous background color, set foreground color
        # of separator to background color of this unit
        blocks = []
        blocks.append(block(fg=b_color, append=sl))
        blocks.append(' ')
        for item in self.items:
            (icon, text, action) = item
            close = block(click='') if action is not None else ''

            blocks.append(block(click=action, fg=i_color, bg=b_color, font='2'
                , append=' ' + icon))
            blocks.append(' ')
            blocks.append(block(fg=t_color, font='1', append=text))
            blocks.append(close)

        return ''.join(blocks)

class CustomUnit(LemonUnit):
    def __init__(self, name, format_function, order, action = None, alt_scheme=None, external=None):
        self.name = name
        self.action = action
        self.order = order
        self.alt_scheme = alt_scheme # None means default
        self.external = external
        self.format = format_function
        self.items = [] # List of tuples (icon, text)
        self.modes = [common.bar_mode.normal]

class LemonParser:
    # Handle parsing of units
    # Apply alternating colors
    # Contains list of units

    def __init__(self):
        self.units = []

    def register_unit(self, unit):
        # Keep the list sorted
        bisect.insort_left(self.units, unit)

    def remove_unit(self, unit):
        self.units.remove(unit)

    def format(self):
        formatted = ['%{l}'] # Start left-justified
        previously_left_justified = True
        # Iterate over all units. Apply alternating color schemes
        alt = 1
        for unit in self.units:
            # Show only units appropriate for the current mode
            if common.mode not in unit.modes:
                continue

            # Negative order means left justified, positive means right justified
            if previously_left_justified and unit.order > 0:
                # Switch to right justified
                formatted.append(block(fg='-', bg='-')) # Reset so the color doesn't fill
                formatted.append('%{r}')
                previously_left_justified = False

            if unit.alt_scheme is None:
                # Apply default color scheme, which is alternating
                unit.alt_scheme = COLOR_SCHEME.A1 if alt == 1 else COLOR_SCHEME.A2
            else:
                # Keep alternate color scheme
                # INA is a special case
                if unit.alt_scheme == COLOR_SCHEME.INA:
                    unit.alt_scheme = COLOR_SCHEME.A1_INA if alt == 1 else COLOR_SCHEME.A2_INA

            formatted.append(unit.format())
            alt = alt + 1 if alt + 1 <= 2 else 1

        formatted.append(block(fg='-', bg='-')) # Not sure if needed
        return ' '.join(formatted)

g_parser = LemonParser()

def block(fg = None, bg = None, font = None, click = None, append=''):
    # Remeber that clickable blocks need to be closed
    rtn = []
    if click is not None:
        if click == '':
            rtn.append('A')
        else:
            rtn.append('A:'+click+':')
    if fg is not None:
        rtn.append('F'+fg)
    if bg is not None:
        rtn.append('B'+bg)
    if font is not None:
        rtn.append('T'+font)
    return ''.join(['%{', ' '.join(rtn), '}', append])

class COLOR_SCHEME(Enum):
    A1 = (config.color_sec_b1, config.color_fore, config.color_icon)
    A2 = (config.color_sec_b2, config.color_fore, config.color_icon)
    INA = (None, None, None) # This one is special, dynamically changed to A1_INA or A2_INA
    A1_INA = (config.color_sec_b1, config.color_disable, config.color_disable)
    A2_INA = (config.color_sec_b2, config.color_disable, config.color_disable)
    CPU_ALERT= (config.color_cpu, config.color_back, config.color_back)
    NET_ALERT= (config.color_net, config.color_back, config.color_back)
    SPECIAL = (config.color_head, config.color_back, config.color_back)
    def __init__(self, back_color, text_color, icon_color):
        self.back_color = back_color
        self.text_color = text_color
        self.icon_color = icon_color

def format_line():
    return g_parser.format()

def parse_line(line_in):
    # Parse lines that external programs have written to fifo

    for unit in g_parser.units:
        if unit.external is not None:
            for key,func in unit.external.items():
                l = len(key)
                if line_in[:l] == key:
                    func(line_in[l:].split())
                    break

    formatted_line = format_line()
    return formatted_line

if __name__ == "__main__":
    for line in sys.stdin:
        print(parse_line(line))
