# -*- 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

from sirilic.lib.constantes import BGCOLOR1
from sirilic.lib.constantes import IMAGE, OFFSET, DARK, FLAT, DFLAT, NB_IODF
from sirilic.lib import tools

# ==============================================================================
TEXT_CENTER = wx.TE_CENTER


# ==============================================================================
class CProcessus():
    def __init__(self, canvas, db_iodf):

        self.canvas = canvas
        self.db = db_iodf
        self.curSelect = None
        self.c_bg = BGCOLOR1
        self.c_fg = "#719ECE"
        self.c_op = "#F48120"
        self.dc = None

        # ----------------------------------------------------------------------
        # parametre de dimension et de placement des objets graphiques
        self.grid = [20.0, 20.0]
        szFile = [3.0, 4.0]
        C = [2.5]  # colonne de reference pour positionner les objets graphiques
        IC = 2
        for ii in range(1, 5):
            C.append(C[ii - 1] + szFile[0] + IC)
        C.append(C[4] + szFile[0])  # derniere colonne
        # ligne de reference  pour positionner les objets graphiques
        L = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
        L[0] = 4.0
        L[1] = L[0] + 4.0
        L[2] = L[0] + 9.0
        L[3] = L[2] + 5.0
        L[4] = L[3] + 5.0
        L[5] = L[4] + 6.0
        L[6] = L[5] + 3.0  # derniere ligne
        # biais pour decaler les objets graphiques par rapport a une ligne ou colonne
        B = [1.75]
        self.C = C
        self.L = L
        self.IC = IC

        self.w_img = C[5] * self.grid[0]  # self.getCol(4)[1]+self.grid[0]/2.0
        self.h_img = L[6] * self.grid[0]

        try:
            path_abs = os.path.dirname(
                os.path.dirname(os.path.abspath(__file__)))
            self.cp_img = wx.Bitmap(tools.resource_path(os.path.join(
                ".", "icon", "cp-neg.gif"), pathabs=path_abs), wx.BITMAP_TYPE_GIF)
        except Exception as e:   # pylint: disable=broad-except
            print("Warning CProcessus() :" + str(e))
            self.cp_img = None

        self.canvas.SetBackgroundColour(BGCOLOR1)

        # ----------------------------------------------------------------------
        # creation des objets du process sauf les fleches
        self.inst = []
        for ii in range(0, 10):
            self.inst.append(CFichier(self.canvas, self.grid))
        self.ope = []
        for ii in range(0, 14):
            self.ope.append(COperation(self.canvas, self.grid))

        self.inst[0].configure(
            [C[0], L[0]], szFile, "IMAGES\n \n \n", "#DECCE4", self.c_fg, 5, self.cp_img)
        self.inst[1].configure([C[1], L[0]], szFile, _(
            "BIASES") + "\n \n \n", "#B1B2B2", self.c_fg, 5)
        self.inst[2].configure([C[2], L[0]], szFile,
                               "DARKS\n \n \n", "#000000", self.c_fg, 5)
        self.inst[3].configure([C[3], L[0]], szFile,
                               "FLATS\n \n \n", "#FFFFFF", self.c_fg, 5)
        self.inst[4].configure([C[4], L[0]], szFile,
                               "DARK\nFLATS\n \n", "#D1D2D2", self.c_fg, 5)
        self.inst[5].configure([C[1], L[2]], szFile, _(
            "BIASES") + "\n" + _("MASTER"), "#B1B2B2", self.c_fg)
        self.inst[6].configure([C[1], L[3]], szFile,
                               "DARK\n" + _("MASTER"), "#000000", self.c_fg)
        self.inst[7].configure(
            [C[4], L[4]], szFile, "DARK\nFLAT\n" + _("MASTER"), "#D1D2D2", self.c_fg)
        self.inst[8].configure([C[1], L[4]], szFile,
                               "FLAT\n" + _("MASTER"), "#FFFFFF", self.c_fg)
        self.inst[9].configure([C[3], L[5]], szFile, "IMAGE\n \n \n./" +
                               _("results"), "#88C665", self.c_fg, 0, self.cp_img)

        self.ope[0].configure([C[1], L[1]], "S")
        self.ope[1].configure([C[2], L[3]], "S")
        self.ope[2].configure([C[4], L[3]], "S")
        self.ope[3].configure([C[2], L[5]], "S")
        self.ope[4].configure([C[0], L[2]], "-")
        self.ope[5].configure([C[4], L[2] + B[0]], "-")
        self.ope[6].configure([C[3], L[2]], "-")
        self.ope[7].configure([C[3], L[4]], "-")
        self.ope[8].configure([C[2], L[2] - B[0]], "-")
        self.ope[9].configure([C[0], L[3]], "-")
        self.ope[10].configure([C[0], L[4]], "/")
        self.ope[11].configure([C[0], L[5]], "*")
        self.ope[12].configure([C[1], L[5]], "*")
        self.ope[13].configure([C[2], L[4]], "S")

        self.canvas.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, _event):
        dc = wx.PaintDC(self.canvas)
        self.DoDrawing(dc)

    def DoDrawing(self, dc=None):
        if dc is None:
            dc = wx.ClientDC(self.canvas)
        self.dc = dc
        dc.Clear()
        self.drawing()
        self.dc = None
        del dc
    # --------------------------------------------------------------------------

    def SetCurrentImage(self, KeyStr):
        self.curSelect = KeyStr
    # --------------------------------------------------------------------------

    def getCol(self, num):
        w = self.C[1] - self.C[0]
        return [(self.C[num] - w / 2.0 + 0.5) * self.grid[0],
                (self.C[num] + w / 2.0) * self.grid[0]]
    # --------------------------------------------------------------------------

    def show_grid(self):
        dc = self.dc
        for x in range(0, int(self.w_img), int(self.grid[0] * 2.0)):
            DrawRect(dc, x, 0, x + int(self.grid[0]), int(self.h_img))
        for y in range(0, int(self.h_img), int(self.grid[1] * 2)):
            DrawRect(dc, 0, y, int(self.w_img), y + int(self.grid[1]))

    # --------------------------------------------------------------------------
    def p_offsets(self, ena_offset, lib_offset, couche):
        dc = self.dc
        if (ena_offset == '0') | (lib_offset is True):
            return
        c_fleche = "#ADC5E7"
        [x0, x1] = self.getCol(1)
        y = (self.ope[0].GetXY('s'))[1] + self.grid[1]
        DrawRect(dc, x0, self.grid[1] / 2.0, x1, y,
                 fill="#87D1D1", outline=self.c_fg)
        DrawText(dc, self.C[1] * self.grid[0], self.grid[1],
                 text="./" + couche + "-offsets", justify=TEXT_CENTER)

        f1 = CFleche(self.canvas, self.grid)
        f1.configure(self.inst[1].GetXY('s'), self.ope[0].GetXY('n'), c_fleche)
        f1.draw(dc)
        f1.configure(self.ope[0].GetXY('s'), self.inst[5].GetXY('n'), c_fleche)
        f1.draw(dc)

        self.ope[0].draw(dc)
        self.inst[1].draw(dc)

    # --------------------------------------------------------------------------
    def p_darks(self, ena_dark, lib_dark, sub_offset, ena_offset, couche):
        dc = self.dc
        if (ena_dark == '0') | (lib_dark is True):
            return
        c_fleche = "#00B5BC"
        f1 = CFleche(self.canvas, self.grid)

        [x0, x1] = self.getCol(2)
        y = (self.inst[6].GetXY('s'))[1] + self.grid[1] / 2.0
        DrawRect(dc, x0, self.grid[1] / 2.0, x1, y,
                 fill="#C2E0AE", outline=self.c_fg)
        DrawText(dc, self.C[2] * self.grid[0], self.grid[1],
                 text="./" + couche + "-darks", justify=TEXT_CENTER)
        self.inst[2].draw(dc)
        self.ope[1].draw(dc)

        if (ena_offset == '1') & (sub_offset is True):
            x1 = (self.inst[5].GetXY('e'))[0]
            y1 = (self.ope[8].GetXY('w'))[1]
            f1.configure([x1, y1], self.ope[8].GetXY('w'), c_fleche)
            f1.draw(dc)
            f1.configure(self.inst[2].GetXY('s'),
                         self.ope[8].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[8].GetXY('s'),
                         self.ope[1].GetXY('n'), c_fleche)
            f1.draw(dc)
            self.ope[8].draw(dc)
        else:
            f1.configure(self.inst[2].GetXY('s'),
                         self.ope[1].GetXY('n'), c_fleche)
            f1.draw(dc)

        f1.configure(self.ope[1].GetXY('w'), self.inst[6].GetXY('e'), c_fleche)
        f1.draw(dc)

        x = self.C[2] * self.grid[0]
        y = (self.ope[1].GetXY('s'))[1] + self.grid[1] / 2.0
        DrawText(dc, x, y, text=_("Stack"), justify=TEXT_CENTER)

    # --------------------------------------------------------------------------
    def p_flats(self, ena_flat, lib_flat, sub_offset, ena_offset, ena_darkflat, couche):
        dc = self.dc
        if (ena_flat == '0') | (lib_flat is True):
            return
        c_fleche = "#719ECE"
        f1 = CFleche(self.canvas, self.grid)

        [x0, x1] = self.getCol(3)
        x2 = self.getCol(2)[0]
        y0 = self.grid[1] / 2.0
        y1 = (self.inst[8].GetXY('n'))[1]
        y2 = (self.inst[8].GetXY('s'))[1] + self.grid[1]
        DrawPolygon(dc, [x0, y0, x1, y0, x1, y2, x2, y2, x2,
                    y1, x0, y1], fill="#E0EFD4", outline=self.c_fg)
        DrawText(dc, self.C[3] * self.grid[0], self.grid[1],
                 text="./" + couche + "-flats", justify=TEXT_CENTER)
        self.inst[3].draw(dc)
        self.ope[13].draw(dc)

        if (ena_offset == '1') & (sub_offset is True):
            x1 = (self.inst[5].GetXY('e'))[0]
            y1 = (self.ope[6].GetXY('w'))[1]
            f1.configure([x1, y1], self.ope[6].GetXY('w'), c_fleche)
            f1.draw(dc)
            f1.configure(self.inst[3].GetXY('s'),
                         self.ope[6].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[6].GetXY('s'),
                         self.ope[7].GetXY('n'), c_fleche)
            f1.draw(dc)
            self.ope[6].draw(dc)
        else:
            f1.configure(self.inst[3].GetXY('s'),
                         self.ope[7].GetXY('n'), c_fleche)
            f1.draw(dc)

        if ena_darkflat == "1":
            self.ope[7].draw(dc)
            f1.configure(self.inst[7].GetXY('w'),
                         self.ope[7].GetXY('e'), c_fleche)
            f1.draw(dc)
        else:
            w = f1.w
            r_op = self.ope[7].rayon * self.grid[0]
            x = self.C[3] * self.grid[0]
            y = self.L[4] * self.grid[1]
            DrawPolygon(dc, [x + w, y - r_op, x + w, y + w, x - r_op, y + w, x - r_op, y - w,
                             x - w, y - w, x - w, y - r_op], fill=c_fleche, outline=self.c_fg)

        f1.configure(self.ope[7].GetXY('w'), self.ope[13].GetXY('e'), c_fleche)
        f1.draw(dc)
        f1.configure(self.ope[13].GetXY('w'),
                     self.inst[8].GetXY('e'), c_fleche)
        f1.draw(dc)
        x = self.C[2] * self.grid[0]
        y = (self.ope[13].GetXY('s'))[1] + self.grid[1] / 2.0
        DrawText(dc, x, y, text=_("Stack"), justify=TEXT_CENTER)

    # --------------------------------------------------------------------------
    def p_darkflats(self, ena_darkflat, lib_darkflat, sub_offset, ena_offset, couche):
        dc = self.dc
        if (ena_darkflat == '0') | (lib_darkflat is True):
            return
        c_fleche = "#408080"
        f1 = CFleche(self.canvas, self.grid)

        [x0, x1] = self.getCol(4)
        y1 = (self.ope[2].GetXY('s'))[1] + self.grid[1]
        DrawRect(dc, x0, self.grid[1] / 2.0, x1, y1,
                 fill="#ffe9d2", outline=self.c_fg)
        DrawText(dc, self.C[4] * self.grid[0], self.grid[1],
                 text="./" + couche + "-darkflats", justify=TEXT_CENTER)
        self.inst[4].draw(dc)
        self.ope[2].draw(dc)

        f1.configure(self.ope[2].GetXY('s'), self.inst[7].GetXY('n'), c_fleche)
        f1.draw(dc)

        if (ena_offset == '1') & (sub_offset is True):
            x1 = (self.inst[5].GetXY('e'))[0]
            y1 = (self.ope[5].GetXY('w'))[1]
            f1.configure([x1, y1], self.ope[5].GetXY('w'), c_fleche)
            f1.draw(dc)
            f1.configure(self.inst[4].GetXY('s'),
                         self.ope[5].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[5].GetXY('s'),
                         self.ope[2].GetXY('n'), c_fleche)
            f1.draw(dc)
            self.ope[5].draw(dc)
        else:
            f1.configure(self.inst[4].GetXY('s'),
                         self.ope[2].GetXY('n'), c_fleche)
            f1.draw(dc)

    # --------------------------------------------------------------------------
    def p_lights(self, ena_offset, sub_offset, ena_dark, ena_flat, ena_light, ena_stack, couche, cosmetic):
        dc = self.dc
        if ena_light == '0':
            return
        condition = '1' if (ena_offset == '1') & (sub_offset is True) else '0'
        condition += ena_dark + ena_flat
        c_fleche = "#DECCE4"

        [x0, x1] = self.getCol(0)
        [x2, x3] = self.getCol(2)
        y0 = self.grid[1] / 2.0
        y1 = (self.inst[9].GetXY('n'))[1] - self.grid[1] / 2.0
        y2 = (self.inst[9].GetXY('s'))[1] + self.grid[1] / 2.0
        DrawPolygon(dc, [x0, y0, x1, y0, x1, y1, x3, y1, x3,
                    y2, x0, y2], fill="#FEFACB", outline=self.c_fg)

        if ena_stack == "1":
            [x1, x2] = self.getCol(3)
            x2 = x2 - self.grid[1] / 2.0
            DrawRect(dc, x1, y1, x2, y2, fill="#e9ccb3", outline=self.c_fg)

        x = self.C[0] * self.grid[0]
        y = (self.inst[0].GetXY('n'))[1] - self.grid[1] / 2.0
        DrawText(dc, x, y, text="./" + couche + "-lights", justify=TEXT_CENTER)

        f1 = CFleche(self.canvas, self.grid)

        self.inst[0].draw(dc)
        if ena_stack == "1":
            self.inst[9].draw(dc)

        if (ena_offset == '1') & (sub_offset is True):
            f1.configure(self.inst[5].GetXY('w'),
                         self.ope[4].GetXY('e'), c_fleche)
            f1.draw(dc)
            self.ope[4].draw(dc)
        if ena_dark == '1':
            f1.configure(self.inst[6].GetXY('w'),
                         self.ope[9].GetXY('e'), c_fleche)
            f1.draw(dc)
            self.ope[9].draw(dc)
        if ena_flat == '1':
            f1.configure(self.inst[8].GetXY('w'),
                         self.ope[10].GetXY('e'), c_fleche)
            f1.draw(dc)
            self.ope[10].draw(dc)

        if cosmetic == "1":
            self.ope[11].draw(dc)
            x = self.C[0] * self.grid[0]
            y = (self.ope[11].GetXY('s'))[1] + self.grid[1] / 2.0
            DrawText(dc, x, y, text="Cosmetic", justify=TEXT_CENTER)
        else:
            w = f1.w
            r_op = self.ope[11].rayon * self.grid[0]
            x = self.C[0] * self.grid[0]
            y = self.L[5] * self.grid[1]
            DrawPolygon(dc, [x - w, y - r_op, x - w, y + w, x + r_op, y + w, x + r_op, y - w,
                             x + w, y - w, x + w, y - r_op], fill=c_fleche, outline=self.c_fg)

        f1.configure(self.ope[11].GetXY('e'),
                     self.ope[12].GetXY('w'), c_fleche)
        f1.draw(dc)
        if ena_stack == "1":
            f1.configure(self.ope[12].GetXY('e'),
                         self.ope[3].GetXY('w'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[3].GetXY('e'),
                         self.inst[9].GetXY('w'), "#88C665")
            f1.draw(dc)
        self.ope[12].draw(dc)
        x = self.C[1] * self.grid[0]
        y = (self.ope[11].GetXY('s'))[1] + self.grid[1] / 2.0
        DrawText(dc, x, y, text=_("Register"), justify=TEXT_CENTER)

        if ena_stack == "1":
            self.ope[3].draw(dc)
            x = self.C[2] * self.grid[0]
            y = (self.ope[3].GetXY('s'))[1] + self.grid[1] / 2.0
            DrawText(dc, x, y, text=_("Stack"), justify=TEXT_CENTER)

        # ---------------------------------------------------------------------
        # Affichage des fleches en fonction des operations
        if condition == '000':  # pas d'offset, de dark et de flat
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)

        if condition == '111':  # offset, dark et flat present
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[4].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[4].GetXY('s'),
                         self.ope[9].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[9].GetXY('s'),
                         self.ope[10].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[10].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)

        if condition == '011':  # pas d'offset uniquement
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[9].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[9].GetXY('s'),
                         self.ope[10].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[10].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)

        if condition == '101':  # pas de dark uniquement
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[4].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[4].GetXY('s'),
                         self.ope[10].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[10].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)

        if condition == '110':  # pas de flat uniquement
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[4].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[4].GetXY('s'),
                         self.ope[9].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[9].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)

        if condition == '001':  # pas d'offset et de dark
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[10].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[10].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)

        if condition == '010':  # pas d'offset et de flat
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[9].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[9].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)

        if condition == '100':  # pas de dark et de flat
            f1.configure(self.inst[0].GetXY('s'),
                         self.ope[4].GetXY('n'), c_fleche)
            f1.draw(dc)
            f1.configure(self.ope[4].GetXY('s'),
                         self.ope[11].GetXY('n'), c_fleche)
            f1.draw(dc)
        #
        # ----------------------------------------------------------------------

    # --------------------------------------------------------------------------
    def p_masters(self, ena_offset, ena_dark, ena_darkflat, ena_flat, couche):
        dc = self.dc
        condition = ena_offset + ena_dark + ena_flat
        if condition == "000":
            return

        [x1, x2] = self.getCol(1)
        y1 = (self.inst[5].GetXY('n'))[1] - self.grid[1] / 2.0
        y2 = (self.inst[8].GetXY('s'))[1] + self.grid[1]

        DrawRect(dc, x1, y1, x2, y2, fill="#E3D200", outline=self.c_fg)
        DrawText(dc, self.C[1] * self.grid[0], y2 - self.grid[1] / 2.0,
                 text="./" + couche + "-master", justify=TEXT_CENTER)

        if ena_offset == "1":
            self.inst[5].draw(dc)
        if ena_dark == "1":
            self.inst[6].draw(dc)
        if ena_flat == "1":
            self.inst[8].draw(dc)

        if ena_darkflat == "1":
            [x1, x2] = self.getCol(4)
            y1 = (self.inst[7].GetXY('n'))[1] - self.grid[1] / 2.0
            y2 = (self.inst[7].GetXY('s'))[1] + self.grid[1]
            DrawRect(dc, x1, y1, x2, y2, fill="#E3D200", outline=self.c_fg)
            DrawText(dc, self.C[4] * self.grid[0], y2 - self.grid[1] / 2.0,
                     text="./" + couche + "-master", justify=TEXT_CENTER)
            self.inst[7].draw(dc)

    # --------------------------------------------------------------------------
    def drawing(self):
        if not self.db:
            return
        if not self.curSelect:
            return

        iodf = self.db.GetItemDb(self.curSelect)
        if not iodf:
            return

        couche = iodf['LayerName']

        ena = ["1"] * NB_IODF
        obj = [None] * NB_IODF
        data = [None] * NB_IODF
        for ii in range(NB_IODF):
            obj[ii] = iodf['Images'][ii]
            data[ii] = obj[ii].GetData()
            if obj[ii].IsInitialised() == "":
                ena[ii] = "0"

        cosmetic = "1" if data[IMAGE]["cosmetic"] else "0"   # pylint: disable=E1136

        self.p_masters(ena[OFFSET], ena[DARK], ena[DFLAT], ena[FLAT], couche)
        self.p_lights(ena[OFFSET], data[IMAGE]['pp']["suboffset"], ena[DARK], ena[FLAT],  # pylint: disable=E1136
                      ena[IMAGE], "1", couche, cosmetic)
        self.p_offsets(ena[OFFSET], obj[OFFSET].IsLib(), couche)
        self.p_darks(ena[DARK], obj[DARK].IsLib(), data[DARK]  # pylint: disable=E1136
                     ['pp']["suboffset"], ena[OFFSET], couche)
        self.p_flats(ena[FLAT], obj[FLAT].IsLib(), data[FLAT]  # pylint: disable=E1136
                     ['pp']["suboffset"], ena[OFFSET], ena[DFLAT], couche)
        self.p_darkflats(ena[DFLAT], obj[DFLAT].IsLib(),
                         data[DFLAT]['pp']["suboffset"], ena[OFFSET], couche)  # pylint: disable=E1136

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


class CObjet:
    def __init__(self, canvas, grid):
        self.canvas = canvas
        self.grid = grid
        self.xy = [0, 0]
        self.rect = [0, 0, 0, 0]
        self.texte = ""
        self.cfill = "#000000"
        self.coutline = BGCOLOR1
        self.rayon = 1
        self.multiple = 0

    def GetXY(self, position="c", marge=0.1):
        x = self.xy[0] * self.grid[0]
        y = self.xy[1] * self.grid[1]
        if position.lower() == 'n':  # North
            y = self.rect[1] * self.grid[1] - 2 * \
                self.multiple - marge * self.grid[1]
        if position.lower() == 's':  # South
            y = self.rect[3] * self.grid[1] + marge * self.grid[1]
        if position.lower() == 'w':  # West
            x = self.rect[0] * self.grid[0] - marge * self.grid[0]
        if position.lower() == 'e':  # East
            x = self.rect[2] * self.grid[0] + 2 * \
                self.multiple + marge * self.grid[0]
        return [x, y]

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


class CFleche(CObjet):
    def __init__(self, canvas, grid):
        CObjet.__init__(self, canvas, grid)
        self.cfill = "#F48120"
        self.w = 6

    def configure(self, xys, xyd, cfill):
        self.xy = [(xys[0] + xyd[0]) / 2.0, (xys[1] + xyd[1]) / 2.0]
        self.rect = [xys[0], xys[1], xyd[0], xyd[1]]
        self.cfill = cfill

    def draw(self, dc):
        w = self.w
        [x0, y0, x1, y1] = self.rect
        if (x0 == x1) & (y1 > y0):  # Horizontal, pointe vers le bas
            DrawPolygon(dc, [x0 + w, y0, x0 + w, y1 - w, x0 + 2 * w, y1 - w, x1, y1, x0 - 2.0 * w,
                        y1 - w, x0 - w, y1 - w, x0 - w, y0], fill=self.cfill, outline=self.coutline)
        if (x0 == x1) & (y1 < y0):
            DrawPolygon(dc, [x0 + w, y0, x0 + w, y1 + w, x0 + 2 * w, y1 + w, x1, y1, x0 - 2.0 * w,
                        y1 + w, x0 - w, y1 + w, x0 - w, y0], fill=self.cfill, outline=self.coutline)
        if (y0 == y1) & (x1 > x0):
            DrawPolygon(dc, [x0, y0 + w, x1 - w, y0 + w, x1 - w, y0 + 2 * w, x1, y1, x1 - w, y0 -
                        2.0 * w, x1 - w, y0 - w, x0, y0 - w], fill=self.cfill, outline=self.coutline)
        if (y0 == y1) & (x1 < x0):
            DrawPolygon(dc, [x0, y0 + w, x1 + w, y0 + w, x1 + w, y0 + 2 * w, x1, y1, x1 + w, y0 -
                        2.0 * w, x1 + w, y0 - w, x0, y0 - w], fill=self.cfill, outline=self.coutline)

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


class COperation(CObjet):
    def __init__(self, canvas, grid):
        CObjet.__init__(self, canvas, grid)
        self.cfill = "#F48120"

    def configure(self, xy, texte):
        r = self.rayon
        self.xy = xy
        self.rect = [xy[0] - r, xy[1] - r, xy[0] + r, xy[1] + r]
        self.texte = texte

    def draw(self, dc):
        r0 = self.rayon * self.grid[0]
        x0 = self.xy[0] * self.grid[0]
        y0 = self.xy[1] * self.grid[1]
        DrawCircle(dc, x0, y0, r0, fill=self.cfill, outline=self.coutline)
        epaisseur = 3
        flag = True
        if self.texte == '-':
            DrawLine(dc, x0 - r0 / 2.0, y0, x0 + r0 / 2.0, y0, width=epaisseur)
            flag = False
        if self.texte == '/':
            DrawLine(dc, x0 - r0 / 2.0, y0, x0 + r0 / 2.0, y0, width=epaisseur)
            DrawCircle(dc, x0, y0 - r0 / 2.0, 2.0, fill="#000000")
            DrawCircle(dc, x0, y0 + r0 / 2.0, 2.0, fill="#000000")
            flag = False
        if self.texte == '*':
            DrawLine(dc, x0 - r0 / 2.0, y0, x0 + r0 / 2.0, y0, width=epaisseur)
            DrawLine(dc, x0, y0 - r0 / 2.0, x0, y0 + r0 / 2.0, width=epaisseur)
            rr0 = 0.707 * r0 / 2.0
            DrawLine(dc, x0 - rr0, y0 - rr0, x0 + rr0, y0 + rr0, width=epaisseur)
            DrawLine(dc, x0 + rr0, y0 - rr0, x0 - rr0, y0 + rr0, width=epaisseur)
            DrawCircle(dc, x0, y0, 7.0, fill="#000000")
            DrawCircle(dc, x0, y0, 3.0, fill=self.cfill)
            flag = False
        if self.texte == 'S':
            DrawLines(dc, [x0 + r0 / 2.0, y0 - r0 / 2.0, x0 - r0 / 2.0, y0 - r0 / 2.0, x0, y0,
                      x0 - r0 / 2.0, y0 + r0 / 2.0, x0 + r0 / 2.0, y0 + r0 / 2.0], width=epaisseur)
            flag = False
        if flag is True:
            DrawText(dc, x0, y0, text=self.texte, justify=TEXT_CENTER)

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


class CFichier(CObjet):
    def __init__(self, canvas, grid):
        CObjet.__init__(self, canvas, grid)
        self.img = None
        self.cfill = "#719ECE"

    def configure(self, xy, wh, texte, cfill, coutline, multiple=0, img=None):
        self.xy = xy
        self.rect = [xy[0] - wh[0] / 2.0, xy[1] - wh[1] /
                     2.0, xy[0] + wh[0] / 2.0, xy[1] + wh[1] / 2.0]
        self.img = img
        self.texte = texte
        self.cfill = cfill
        self.coutline = coutline
        self.multiple = multiple

    def draw(self, dc):
        k = self.multiple
        x0 = self.rect[0] * self.grid[0]
        x1 = self.rect[2] * self.grid[0]
        y0 = self.rect[1] * self.grid[1]
        y1 = self.rect[3] * self.grid[1]
        if k > 0:
            DrawRect(dc, x0 + 2.0 * k, y0 - 2.0 * k, x1 + 2.0 * k, y1 - 2.0 *
                     k, fill=self.cfill, outline=self.coutline)
            DrawRect(dc, x0 + 1.0 * k, y0 - 1.0 * k, x1 + 1.0 * k, y1 - 1.0 *
                     k, fill=self.cfill, outline=self.coutline)
        DrawRect(dc, x0, y0, x1, y1, fill=self.cfill, outline=self.coutline)
        if self.img is not None:
            DrawImage(dc, (x0 + x1) / 2.0, (y0 + y1) / 2.0, image=self.img)
        fgcolor = "#000000"
        if self.cfill == "#000000":
            fgcolor = "#FFFFFF"
        DrawText(dc, (x0 + x1) / 2.0, (y0 + y1) / 2.0, text=self.texte,
                 justify=TEXT_CENTER, fill=fgcolor)
# ==============================================================================


def DrawRect(dc, x0, y0, x1, y1, fill=wx.TRANSPARENT, outline=wx.BLACK):  # pylint: disable=no-member
    w = x1 - x0
    h = y1 - y0
    dc.SetPen(wx.Pen(outline))
    dc.SetBrush(wx.Brush(fill))
    dc.DrawRectangle(int(x0), int(y0), int(w), int(h))


def DrawPolygon(dc, points, fill=wx.TRANSPARENT, outline=wx.BLACK):  # pylint: disable=no-member
    xy_points = [(int(points[2 * ii]), int(points[2 * ii + 1]))
                 for ii in range(int(len(points) / 2))]
    dc.SetPen(wx.Pen(outline))
    dc.SetBrush(wx.Brush(fill))
    dc.DrawPolygon(xy_points)


def DrawLine(dc, x0, y0, x1, y1, color=wx.BLACK, width=4):
    dc.SetPen(wx.Pen(color, width))
    dc.DrawLine(int(x0), int(y0), int(x1), int(y1))


def DrawLines(dc, points, color=wx.BLACK, width=4):
    xy_points = [(int(points[2 * ii]), int(points[2 * ii + 1]))
                 for ii in range(int(len(points) / 2))]
    dc.SetPen(wx.Pen(color, width))
    dc.DrawLines(xy_points)


def DrawCircle(dc, x0, y0, radius, fill=wx.TRANSPARENT, outline=wx.BLACK):  # pylint: disable=no-member
    dc.SetPen(wx.Pen(outline))
    dc.SetBrush(wx.Brush(fill))
    dc.DrawCircle(int(x0), int(y0), int(radius))


def DrawText(dc, x0, y0, text, fill=wx.BLACK, justify=TEXT_CENTER):
    if not text:
        return
    dc.SetTextForeground(fill)
    if justify == TEXT_CENTER:
        multiline = text.split("\n")
        nbline = len(multiline)
        w, h = dc.GetTextExtent(multiline[0])
        y0 = y0 - int(h * nbline / 2)
        for line in multiline:
            w, h = dc.GetTextExtent(line)
            dc.DrawText(line, int(x0 - int(w / 2)), int(y0))
            y0 = y0 + h
    else:
        dc.DrawText(text, int(x0), int(y0))


def DrawImage(dc, x0, y0, image):
    x0 = x0 - int(image.GetWidth() / 2)
    y0 = y0 - int(image.GetHeight() / 2)
    dc.DrawBitmap(image, int(x0), int(y0))
