''' Plugin provides fullscreen console '''
import logging
import sys
import traceback
import threading

from Aggregator import AggregatorPlugin, AggregateResultListener
from ConsoleScreen import Screen
from yandextank.core import AbstractPlugin


class ConsoleOnlinePlugin(AbstractPlugin, AggregateResultListener):
    ''' Console plugin '''
    SECTION = 'console'

    def __init__(self, core):
        AbstractPlugin.__init__(self, core)
        self.screen = None
        self.render_exception = None
        self.console_markup = None
        self.remote_translator = None
        self.info_panel_width = '33'
        self.short_only = 0
        # these three provide non-blocking console output
        self.__console_view = None
        self.__writer_thread = None
        self.__writer_event = None

    @staticmethod
    def get_key():
        return __file__

    def get_available_options(self):
        return ["info_panel_width", "short_only", "disable_all_colors", "disable_colors"]

    def configure(self):
        self.info_panel_width = self.get_option("info_panel_width", self.info_panel_width)
        self.short_only = int(self.get_option("short_only", '0'))
        if not int(self.get_option("disable_all_colors", '0')):
            self.console_markup = RealConsoleMarkup()
        else:
            self.console_markup = NoConsoleMarkup()
        for color in self.get_option("disable_colors", '').split(' '):
            self.console_markup.__dict__[color] = ''
        self.screen = Screen(self.info_panel_width, self.console_markup)

        try:
            aggregator = self.core.get_plugin_of_type(AggregatorPlugin)
            aggregator.add_result_listener(self)
        except KeyError:
            self.log.debug("No aggregator for console")
            self.screen.block_rows = []
            self.screen.info_panel_percent = 100

    def __console_writer(self):
        while True:
          self.__writer_event.wait()
          self.__writer_event.clear()

          if self.__console_view:
              if not self.short_only:
                  self.log.debug("Writing console view to STDOUT")
                  sys.stdout.write(self.console_markup.clear)
                  sys.stdout.write(self.__console_view)
                  sys.stdout.write(self.console_markup.TOTAL_RESET)

              if self.remote_translator:
                  self.remote_translator.send_console(self.__console_view)

    def is_test_finished(self):
        if not self.__writer_thread:
          self.__writer_event = threading.Event()
          self.__writer_thread = threading.Thread(target=self.__console_writer)
          self.__writer_thread.daemon = True
          self.__writer_thread.start()

        try:
            self.__console_view = self.screen.render_screen().encode('utf-8')
        except Exception, ex:
            self.log.warn("Exception inside render: %s", traceback.format_exc(ex))
            self.render_exception = ex
            self.__console_view = ""

        self.__writer_event.set()
        return -1


    def aggregate_second(self, second_aggregate_data):
        self.screen.add_second_data(second_aggregate_data)
        if self.short_only:
            tpl = "Time: %s\tExpected RPS: %s\tActual RPS: %s\tActive Threads: %s\tAvg RT: %s"
            ovr = second_aggregate_data.overall  # just to see the next line in IDE
            data = (second_aggregate_data.time, ovr.planned_requests, ovr.RPS,
                    ovr.active_threads, ovr.avg_response_time)
            self.log.info(tpl % data)


    def add_info_widget(self, widget):
        ''' add right panel widget '''
        if not self.screen:
            self.log.debug("No screen instance to add widget")
        else:
            self.screen.add_info_widget(widget)


# ======================================================


class RealConsoleMarkup(object):
    '''
    Took colors from here: https://www.siafoo.net/snippet/88
    '''
    WHITE_ON_BLACK = '\033[37;40m'
    TOTAL_RESET = '\033[0m'
    clear = "\x1b[2J\x1b[H"
    new_line = u"\n"

    YELLOW = '\033[1;33m'
    RED = '\033[1;31m'
    RED_DARK = '\033[31;3m'
    RESET = '\033[1;m'
    CYAN = "\033[1;36m"
    GREEN = "\033[1;32m"
    WHITE = "\033[1;37m"
    MAGENTA = '\033[1;35m'
    BG_MAGENTA = '\033[1;45m'
    BG_GREEN = '\033[1;42m'
    BG_BROWN = '\033[1;43m'
    BG_CYAN = '\033[1;46m'

    def clean_markup(self, orig_str):
        ''' clean markup from string '''
        for val in [self.YELLOW, self.RED, self.RESET,
                    self.CYAN, self.BG_MAGENTA, self.WHITE,
                    self.BG_GREEN, self.GREEN, self.BG_BROWN,
                    self.RED_DARK, self.MAGENTA, self.BG_CYAN]:
            orig_str = orig_str.replace(val, '')
        return orig_str


# ======================================================
# FIXME: 3 better way to have it?

class NoConsoleMarkup(RealConsoleMarkup):
    ''' all colors are disabled '''
    WHITE_ON_BLACK = ''
    TOTAL_RESET = ''
    clear = ""
    new_line = u"\n"

    YELLOW = ''
    RED = ''
    RED_DARK = ''
    RESET = ''
    CYAN = ""
    GREEN = ""
    WHITE = ""
    MAGENTA = ''
    BG_MAGENTA = ''
    BG_GREEN = ''
    BG_BROWN = ''
    BG_CYAN = ''


# ======================================================


class AbstractInfoWidget:
    ''' parent class for all right panel widgets '''

    def __init__(self):
        self.log = logging.getLogger(__name__)

    def render(self, screen):
        raise NotImplementedError()

    def get_index(self):
        ''' get vertical priority index '''
        return 0
