import logging
import os
import traceback
import datetime
import sys
from time import sleep


class Log:
    def __init__(self, name_log):
        # init log file #

        self.exec_dir = os.path.dirname(sys.argv[0])       
        try:
            os.mkdir("{}/logs".format(self.exec_dir))    
        except FileExistsError as e:
            pass
        
        self.logfile = "{}/logs/{}_{}.log".format(
            self.exec_dir,
             datetime.datetime.now().strftime("%m_%d_%Y %H_%M_%S"),
             name_log
            )
        
        
        self.log = logging.getLogger("my_log")
        self.log.setLevel(logging.INFO)
        try:
            self.FH = logging.FileHandler(self.logfile, encoding='utf-8')
        except PermissionError as e:
            sleep(1)    
            self.FH = logging.FileHandler(self.logfile[:-4]+"perm_err.log", encoding='utf-8')    
        
        
        ## задаем базовый формат сообщения в логе
        self.basic_formater = logging.Formatter('%(asctime)s : [%(levelname)s] : %(message)s')
        self.FH.setFormatter(self.basic_formater)
        self.log.addHandler(self.FH)


        self.info("\n---- LOG START ---\n{}\n------------------".format(self.logfile))

    ## функция для записи в лог сообщений об ошибке
    def error(self, line_no):
        ## задаем формат ошибочных сообщений, добавляем номер строки
        err_formater = logging.Formatter('%(asctime)s : [%(levelname)s][LINE ' + line_no + '] : %(message)s')
        ## устанавливаем формат ошибок в логгер
        self.FH.setFormatter(err_formater)
        self.log.addHandler(self.FH)
        ## пишем сообщение error
        self.log.error(traceback.format_exc())
        ## возвращаем базовый формат сообщений
        self.FH.setFormatter(self.basic_formater)
        self.log.addHandler(self.FH)
        print("{} : [ERROR] : {}".format(self.get_current_time(), traceback.format_exc()))

    def get_current_time(self):
        return datetime.datetime.now().strftime("%m.%d.%Y %H:%M:%S.%f")[:-3]

    def info(self, msg, *args, **kwargs):
        print("{} : [INFO] : {}".format(self.get_current_time(),  msg))
        return self.log.info(msg, *args, **kwargs)

    def warn(self, msg, *args, **kwargs):
        print("{} : [WARN] : {}".format(self.get_current_time(),  msg))
        return self.log.warning(msg, *args, **kwargs)

    def get_logger(self):
        return self.log

    def get_line(self):
        frame = traceback.extract_tb(sys.exc_info()[2])
        return str(frame[0]).split()[4]




# EXAMPLE LOG ERROR
# A = [i for i in range(5)]
# log.info("start program")
# try:
#     for i in range(6):
#         log.warn(A[i] ** 2)
#         log.info("program calculate square " + str(A[i]))
# except:
#     ## вызываем функцию записи ошибки и передаем в нее номер строки с ошибкой
#     log.error(log.get_line())
