# -*- coding: UTF-8 -*-
import os
import sys
import inspect
from datetime import datetime


class logger(object):
        LOG_LEVEL_DEBUG = 0
        LOG_LEVEL_VERBS = 1
        LOG_LEVEL_INFO = 2
        LOG_LEVEL_WARN = 3
        LOG_LEVEL_ERROR = 4
        LOG_LEVEL_STDOUT = 5

        LOG_LEVEL_NAME_LIST = ['DEBUG', 'VERBS', 'INFO', 'WARN', 'ERROR', 'STDOUT']

        def __init__(self, level=0):
                self.logfile = None
                self.logPath = None
                self.verbose = True
                self.level = level

        def get_logger(self, path, clean=False):
            if clean and os.path.exists(path):
                os.remove(path)
            self.close()
            self.logPath = path
            self.logfile = open(path, "ab")

        def format_message(self, raw_message, level, verbose=False):

                timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')

                # explore stack frames to get real caller
                # format_message() can't be directly called from caller
                # it's always called indirectly so we go backwards to #2 frame
                if (verbose):
                    stack_frames = inspect.stack()
                    module = os.path.basename(stack_frames[2][1]).split('.')[0]
                    sub_module = ""
                    if sys.version_info[0] < 3:
                        if "self" in stack_frames[2][0].f_locals:
                                sub_module = stack_frames[2][0].f_locals["self"].__class__.__name__
                        func = stack_frames[2][3]
                    else:
                        func = stack_frames[2][3]
                    caller = '[{}:{}:{}]'.format(module, sub_module, func)

                if (not verbose):
                        message = '[{}] [{}] {}\n'.format(timestamp,
                                                          logger.LOG_LEVEL_NAME_LIST[level],
                                                          raw_message)
                else:
                        message = '[{}] [{}] {} {}\n'.format(timestamp,
                                                             logger.LOG_LEVEL_NAME_LIST[level],
                                                             caller,
                                                             raw_message)
                return message.encode('utf-8', 'ignore')

        def stdout(self, data, verbose=False):
                if self.level > logger.LOG_LEVEL_STDOUT:
                    return

                if (not verbose):
                        verbose = self.verbose

                sdata = self.format_message(data, logger.LOG_LEVEL_STDOUT, verbose)

                sys.stdout.write(str(sdata.rstrip()) + "\n")
                sys.stdout.flush()
                self.record(sdata)

        def info(self, data, verbose=False):
                if self.level > logger.LOG_LEVEL_INFO:
                    return

                if (not verbose):
                        verbose = self.verbose

                sdata = self.format_message(data, logger.LOG_LEVEL_INFO, verbose)

                self.record(sdata)

        def debug(self, data, verbose=False):
                if self.level > logger.LOG_LEVEL_DEBUG:
                    return

                if (not verbose):
                        verbose = self.verbose

                data = self.format_message(data, logger.LOG_LEVEL_DEBUG, verbose)

                self.record(data)

        def error(self, data, verbose=False):
                if self.level > logger.LOG_LEVEL_ERROR:
                    return

                if (not verbose):
                        verbose = self.verbose

                data = self.format_message(data, logger.LOG_LEVEL_ERROR, verbose)

                sys.stdout.write(str(data.rstrip()) + '\n')
                sys.stdout.flush()
                self.record(data)

        def warn(self, data, verbose=False):
                if self.level > logger.LOG_LEVEL_WARN:
                    return

                if (not verbose):
                        verbose = self.verbose

                data = self.format_message(data, logger.LOG_LEVEL_WARN, verbose)

                self.record(data)

        def verbs(self, data):
                if self.level > logger.LOG_LEVEL_VERBS:
                    return

                if (not self.verbose):
                        return

                data = self.format_message(data, logger.LOG_LEVEL_VERBS, verbose=True)
                self.record(data)

        def record(self, data):
                if (self.logfile):
                        self.logfile.write(data)
                        self.logfile.flush()

        def close(self):
                if (self.logfile):
                        self.logfile.flush()
                        self.logfile.close()
                        self.logfile = None

        def getLogLines(self, level):
                ret = []

                with open(self.logPath, 'rb') as f:
                        log_lines = f.readlines()
                        for l in log_lines:
                                if '] [{}] ['.format(logger.LOG_LEVEL_NAME_LIST[level]) in l:
                                        ret.append(l.rstrip())

                return ret
