# -*- coding: UTF-8 -*-
'''
================================================================================
Project: SiriL-ic ( SiriL Image Companion )

This script structures the SiriL work folder into a subfolder, copies the
astronomical images into the subfolders, and builds the associated SiriL
script. It can also group scripts.
================================================================================
   Author:  M27trognondepomme <pebe92 (at) gmail.com>

This program is provided without any guarantee.

The license is  LGPL-v3
For details, see GNU General Public License, version 3 or later.
                       "https://www.gnu.org/licenses/gpl.html"
================================================================================
'''
import wx
import os
import time
import queue as Queue
import re


# ==============================================================================
class LogConsole:

    def __init__(self, uilog, tlog, lProgressSiril, lTraitementenCours, gBarreEnCours, cb_siril):
        self.uilog = uilog
        self.text = tlog
        self.traitementEnCours = lTraitementenCours
        self.progresSiril = lProgressSiril
        self.progressBar = gBarreEnCours
        self.fileRxLog = Queue.Queue()
        self.fileRxProg = Queue.Queue()
        self.fileRxBarProg = Queue.Queue()
        self.running = True
        self.duree = 500
        self.fdlog = None
        self.stepNumber = 1
        self.timerLog = wx.Timer()
        self.timerProg = wx.Timer()
        self.timerBarProg = wx.Timer()
        self.timerLog.Bind(wx.EVT_TIMER, self.periodicCallRxLog, self.timerLog)
        self.timerProg.Bind(
            wx.EVT_TIMER, self.periodicCallRxProg, self.timerProg)
        self.timerBarProg.Bind(
            wx.EVT_TIMER, self.periodicCallRxBarProg, self.timerBarProg)
        self.timerLog.Start(int(self.duree / 2))
        self.timerProg.Start(self.duree)
        self.timerBarProg.Start(self.duree)
        font = wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL, False, 'Console')  # pylint: disable=no-member
        self.style = []
        self.style.append(wx.TextAttr("black", "white", font))
        self.style.append(wx.TextAttr("#008080", "white", font.Bold()))
        self.style.append(wx.TextAttr("maroon", "white", font.Bold()))
        self.style.append(wx.TextAttr("red", "white", font.Bold()))
        self.style.append(wx.TextAttr("orange", "white", font.Bold()))
        self.translation = "".maketrans("������", "eeecau")

        self.uilog.bclear.Bind(wx.EVT_BUTTON, self.CB_clearlog)
        self.uilog.bsearchnext.Bind(wx.EVT_BUTTON, self.CB_searchnext)
        self.uilog.bsearchprev.Bind(wx.EVT_BUTTON, self.CB_searchprev)
        self.uilog.bSiril.Bind(wx.EVT_BUTTON, cb_siril)
        self.oldpos = -1
        self.wordlen = 0

        size = self.uilog.esearch.GetSizeFromTextSize(
            self.uilog.esearch.GetTextExtent('X' * 20))
        self.uilog.esearch.SetMinSize(size)

    def CB_clearlog(self, _event=None):
        self.oldpos = -1
        self.wordlen = 0
        self.clear()

    def CB_searchnext(self, _event=None):
        chaine = self.uilog.esearch.GetValue()
        if len(chaine) == 0:
            return
        self.unhighlightText(self.oldpos, self.wordlen)
        poscur = self.text.GetInsertionPoint()
        pos_found = self.find_str(chaine, self.text.GetValue(), poscur, +1)
        self.highlightText(pos_found, pos_found + len(chaine))

    def CB_searchprev(self, _event=None):
        chaine = self.uilog.esearch.GetValue()
        if len(chaine) == 0:
            return
        self.unhighlightText(self.oldpos, self.wordlen)
        poscur = self.text.GetInsertionPoint()
        pos_found = self.find_str(chaine, self.text.GetValue(), poscur, -1)
        self.highlightText(pos_found, pos_found + len(chaine))

    def highlightText(self, pos, size):
        if pos < 0:
            return
        if size <= 0:
            return
        self.text.SetInsertionPoint(pos)
        self.text.SetStyle(pos, size, wx.TextAttr("black", "turquoise"))
        self.oldpos = pos
        self.wordlen = size

    def unhighlightText(self, pos, size):
        if pos < 0:
            return
        if size <= 0:
            return
        self.text.SetInsertionPoint(pos)
        self.text.SetStyle(pos, size, wx.TextAttr("black", "white"))
        self.oldpos = -1
        self.wordlen = 0

    def find_str(self, substr, text, poscur, sens):
        pos_founds = [m.start() for m in re.finditer(substr, text)]
        if len(pos_founds) == 0:
            return -1
        if sens < 0:
            pos_founds.reverse()
            for pos in pos_founds:
                if pos < poscur:
                    return pos
            return pos_founds[0]
        else:
            for pos in pos_founds:
                if pos > poscur:
                    return pos
            return pos_founds[0]

    def SetStepNumber(self, value):
        self.stepNumber = max(1, int(value))

    def SetFinishBar(self):
        self.fileRxBarProg.put("100")

    def SetProgressBar(self, value):
        pourcent = int(value / self.stepNumber * 100.0 + 0.5)
        self.fileRxBarProg.put(str(pourcent))

    def LogTrace(self, enable, workdir=""):
        if enable:
            if self.fdlog is not None:
                try:
                    self.fdlog.close()
                except Exception:   # pylint: disable=broad-except
                    self.fdlog = None
            logfilename = os.path.join(workdir, 'sirilic.log')
            try:
                self.fdlog = open(logfilename, "w", encoding="utf-8")
            except Exception as e:   # pylint: disable=broad-except
                print("*** Error open logfile :", logfilename + "\n")
                print("*** LogConsole::LogTrace() error :" + str(e))
                self.fdlog = None
        else:
            if self.fdlog is not None:
                try:
                    self.fdlog.close()
                except Exception:   # pylint: disable=broad-except
                    pass
            self.fdlog = None

    def stop(self):
        self.timerLog.Stop()
        self.timerProg.Stop()

    def start(self):
        self.timerLog.Start(self.duree)
        self.timerProg.Start(self.duree / 2)

    def insert(self, texte_insert):
        self.fileRxLog.put(texte_insert)

    def addProgress(self, texte):
        if self.fileRxProg.empty():
            self.fileRxProg.put(texte)

    def print_ligne(self, caract):
        self.insert(caract * 80 + '\n')

    def print_titre(self, caract, titre):
        length = int((80 - (len(titre) + 2)) / 2)
        length = max(0, length)
        if int(len(titre)) & 1 == 1:
            titre += ' '
        self.insert(caract + ' ' * length + titre + ' ' * length + caract + '\n')

    def update(self):
        self.text.Update()
        self.text.Refresh()

    def clear(self):
        self.text.Clear()
        self.progresSiril.Clear()
        self.traitementEnCours.Clear()
        self.SetProgressBar(0)
        self.stepNumber = 1

    def SetStatus(self, txt=" "):
        self.progresSiril.Clear()
        self.progresSiril.write(txt)

    def AbortMsg(self, txt="... Aborted ..."):
        self.print_ligne('.')
        self.insert('\n' + txt + '\n')
        self.print_ligne('.')
        self.progresSiril.Clear()
        self.progresSiril.write(txt)
        self.traitementEnCours.Clear()
        self.SetProgressBar(0)
        self.stepNumber = 1

    def periodicCallRxLog(self, _event):
        try:
            buffer = ""
            debut = time.time()
            while self.fileRxLog.qsize():
                try:
                    msg = self.fileRxLog.get(0)
                    if msg[0:12] == "log: #TAG#{ "[0:12]:
                        stepNoMsg = msg[13:-1].split('] ')
                        self.SetProgressBar(int(stepNoMsg[0]))
                        self.traitementEnCours.Clear()
                        self.traitementEnCours.write(stepNoMsg[1])
                    buffer = buffer + msg
                except Queue.Empty:
                    pass
                if (time.time() - debut) > self.duree:
                    break

            if buffer != "":
                # suppression des accents du log
                buffer = buffer.translate(self.translation)
                for line in buffer.split('\n'):
                    if len(line) == 0:
                        self.text.AppendText('\n')
                        continue
                    if (line[0] == "#") or (line[0:6] == "log: #"):
                        num_style = 1
                    elif (line[0] == ".") or (line[0] == "-"):
                        num_style = 2
                    elif line[0] == "*":
                        num_style = 3
                    elif line[0] == "~":
                        num_style = 4
                    else:
                        num_style = 0
                    self.text.SetDefaultStyle(self.style[num_style])
                    self.text.AppendText(line + '\n')

                self.fdlog.write(buffer)
                self.fdlog.flush()

            if not self.running:
                msg = "\n**" + _("Finished") + "**\n"
                self.text.write(msg)
                self.fdlog.write(msg)
                self.fdlog.flush()
                return
        except Exception as e:   # pylint: disable=broad-except
            print(" abort LogConsole::periodicCallRxLog : " + str(e) + '\n')

    def periodicCallRxProg(self, _event):
        try:
            buffer = ""
            debut = time.time()
            while self.fileRxProg.qsize():
                try:
                    msg = self.fileRxProg.get(0)
                    buffer = msg
                except Queue.Empty:
                    pass
                if (time.time() - debut) > self.duree / 3:
                    break

            if buffer != "":
                self.SetStatus(buffer)

        except Exception as e:   # pylint: disable=broad-except
            print(" abort LogConsole::periodicCallRxProg : " + str(e) + '\n')

    def periodicCallRxBarProg(self, _event):
        try:
            buffer = ""
            debut = time.time()
            while self.fileRxBarProg.qsize():
                try:
                    msg = self.fileRxBarProg.get(0)
                    buffer = msg
                except Queue.Empty:
                    pass
                if (time.time() - debut) > self.duree:
                    break

            if buffer != "":
                value = max(0, min(100, int(buffer)))
                self.progressBar.SetValue(value)
        except Exception as e:   # pylint: disable=broad-except
            print(" abort LogConsole::periodicCallRxBarProg : " + str(e) + '\n')
