#https://docs.python.org/2/library/operator.html

# TODO try remove row if possible to only handle panels
# in a way a figure can be a panel of panels --> if so the I would just have one element --> in fact that would really simplify things like crazy
# pas mal mais du coup faudrait pas packer par defaut ou bien si sauf si l'utilisateur veut pas
# peut être plus flexible --> supress fig and row just keep panel and make it more flexible
# faire un stacker(horizontal or vertical)
# that may work in a way
# seule difference est que le panel ne doit contenir que des images de même taille alors que la row non mais en gros la row est un panel de panel
# puis je appliquer la regle des rows aux panels
# --> j'ai besoin d'une orientation des le depart
# est ce que ça peut marcher --> peut etre
# should I put a warning if they don't have the same size initially --> ? think about it
# should I have linear panel and 2D panel and give them different rules panel1D panel2D #dans panel2D ttes les images doivent avoir la meme taille. Panel1D --> c'est un peu une row en fait

# panel1D --> orientation --> hor/ver
# panel2D --> more stuff and same size required

from epyseg.draw.shapes.image2d import Image2D
from epyseg.draw.shapes.rect2d import Rect2D
from PyQt5.QtCore import QPointF, QRectF
# logger
from epyseg.tools.logger import TA_logger
logger = TA_logger()

# keep this in mind: https://stackoverflow.com/questions/34827132/changing-the-order-of-operation-for-add-mul-etc-methods-in-a-custom-c

# do rows and columns and no need to take images --> they just pack horiz or vertically and that's it each image or stuff handles itslef
# a row like that cannot be appended another row or can it --> yes in fact just add to it
class Row(Rect2D):

    def __init__(self, *args, space=3, width=None):
        self.images = []
        for img in args:
            # if isinstance(img, Row):
            #     self.images += img.images
            # else:
            self.images.append(img)
        # init super empty
        super(Rect2D, self).__init__()
        self.isSet = True # required to allow dragging
        self.space = space
        self.sameHeight(space=space)
        self.widthInPixel = width
        self.setToWidth(width)

    def __or__(self, other):
        if isinstance(other, Row):
            pos = self.get_P1()
            other_pos = other.get_P1()
            self.set_P1(other_pos)
            other.set_P1(pos)
        else:
            logger.error('swapping not implemented yet for ' + str(type(other)))

    def __add__(self, other):
        # from epyseg.figure.panel import Panel
        if isinstance(other, Image2D):
            self.images.append(other)
            self.sameHeight(space=self.space)
            self.setToWidth(self.widthInPixel)
        # elif isinstance(other, Panel):
        #     self.images.append(other)
        #     self.sameHeight(space=self.space)
        #     self.setToWidth(self.widthInPixel)
        elif isinstance(other, Row):
            # print(self.images)
            # print(len(self.images))
            # print(other.images)
            # print(len(other.images))
            self.images = self.images + other.images
            self.sameHeight(space=self.space)
            self.setToWidth(self.widthInPixel)
        return self

    def __sub__(self, other):
        if other in self.images:
            self.images.remove(other)
        self.setToWidth(self.widthInPixel)
        return self

    def is_empty(self):
        if self.images is None or not self.images:
            return True
        return False

    def __truediv__(self, other):
        from epyseg.figure.column import Column
        col = Column(self, other, space=self.space)
        # row.sameHeight(self.space)
        # row.setToWidth(self.widthInPixel)
        return col

    def __len__(self):
        if self.images is None:
            return 0
        return len(self.images)

    def setWidthInPixel(self, widthInPixel):
        self.widthInPixel = widthInPixel
        self.packX()

    def packX(self, space=3):
        last_x = 0
        last_y = 0

        for i in range(len(self.images)):
            img = self.images[i]
            if i != 0:
                last_x += space
            img.set_P1(last_x, img.get_P1().y())
            last_x = img.boundingRect().x() + img.boundingRect().width()

        self.updateBoudingRect()

    def packY(self, space=3):
        last_x = 0
        last_y = 0

        for i in range(len(self.images)):
            img = self.images[i]
            if i != 0:
                last_y += space
            img.set_P1(img.get_P1().x(), last_y)
            # get all the bounding boxes and pack them with desired space in between
            # get first point and last point in x
            x = img.boundingRect().x()
            y = img.boundingRect().y()
            last_x = img.boundingRect().x() + img.boundingRect().width()
            last_y = img.boundingRect().y() + img.boundingRect().height()
        self.updateBoudingRect()

    def updateBoudingRect(self):
        '''updates the image bounding rect depending on content'''
        x = None
        y = None
        x2 = None
        y2 = None
        for img in self:
            topLeft = img.get_P1()
            if x is None:
                x = topLeft.x()
            if y is None:
                y = topLeft.y()
            x = min(topLeft.x(), x)
            y = min(topLeft.y(), y)

            print(img, img.boundingRect(), type(img))
            print(img, img.boundingRect(), type(img), img.boundingRect().height())

            if x2 is None:
                x2 = topLeft.x() + img.boundingRect().width()
            if y2 is None:
                y2 = topLeft.y() + img.boundingRect().height()
            x2 = max(topLeft.x() + img.boundingRect().width(), x2)
            y2 = max(topLeft.y() + img.boundingRect().height(), y2)

        self.setX(x)
        self.setY(y)
        self.setWidth(x2 - x)
        self.setHeight(y2 - y)

    def setOrigin(self, *args):
        self.set_P1(*args)

    def set_P1(self, *args):
        curP1 = self.get_P1()
        Rect2D.set_P1(self, *args)
        newP1 = self.get_P1()
        for img in self:
            img.translate(newP1.x() - curP1.x(), newP1.y() - curP1.y())

        self.updateBoudingRect()

    def translate(self, *args):
        if len(args)==1:
            point = args[0]
            QRectF.translate(self, point.x(), point.y())
            for img in self:
                img.translate(point.x(), point.y())
        else:
            QRectF.translate(self, args[0], args[1])
            for img in self:
                img.translate(QPointF(args[0], args[1]))

    def draw(self, painter, draw=True):
        if draw:
            painter.save()
        if draw:
            for img in self:
                img.draw(painter, draw=draw)
            painter.restore()

    def fill(self, painter, draw=True):
        if self.fill_color is None:
            return
        if draw:
            painter.save()
        if draw:
            for img in self:
                img.fill(painter, draw=draw)
            painter.restore()

    def drawAndFill(self, painter):
        painter.save()
        self.draw(painter, draw=True)
        painter.restore()

    def __iter__(self):
        ''' Returns the Iterator object '''
        self._index = -1
        return self

    def __next__(self):
        '''' Returns the next image or panel in the row '''
        self._index += 1
        if self._index < len(self.images):
            return self.images[self._index]
        # End of Iteration
        raise StopIteration

    def __lshift__(self, other):
        # move image left with respect to self
        if isinstance(other, Image2D):
            # swap the position of the two images and repack
            if other in self.images:
                pos = self.images.index(other)
                if pos - 1 >= 0:
                    self.images[pos-1], self.images[pos] = self.images[pos], self.images[pos-1]
                else:
                    return self
                self.packX(self.space)
                return self
        else:
            logger.error('not implemented yet swapping two objects '+ str(type(other)))

    def __rshift__(self, other):
        # move image left with respect to self
        if isinstance(other, Image2D):
            # swap the position of the two images and repack
            if other in self.images:
                pos = self.images.index(other)
                if pos + 1 < len(self.images):
                    self.images[pos + 1], self.images[pos] = self.images[pos], self.images[pos + 1]
                else:
                    return self
                self.packX(self.space)
                return self
        else:
            logger.error('not implemented yet swapping two objects ' + str(type(other)))

    def sameHeight(self, space):
        if space is None:
            space = 0
        max_height = None
        for img in self:
            if max_height is None:
                # print('TUTU',img)
                # print('TUTA',img, img.boundingRect(), img.boundingRect().height)
                # print('TOTO',img, img.boundingRect(), img.boundingRect().height())
                max_height = img.boundingRect().height()
            max_height = max(img.boundingRect().height(), max_height)
        for img in self:
            img.setToHeight(max_height)

        self.packX(space)
        self.alignTop(updateBounds=False)
        self.updateBoudingRect()

    #Aligns objects within the block
    def arrangeRow(self):
        self.alignTop()

    # Align vectorial objects to the top
    # in fact should align in y
    def alignTop(self, updateBounds=False):
        first_left = None
        for img in self:
            cur_pos = img.get_P1()
            if first_left is None:
                first_left = cur_pos
            img.set_P1(cur_pos.x(), first_left.y())
        if updateBounds:
            self.updateMasterRect()

     # Forces the block to be of width (width_in_px)
    def setToWidth(self, width_in_px):
        if width_in_px is None:
            return
        nb_cols = len(self)
        pure_image_width = (self.boundingRect().width()) - (nb_cols - 1.) * self.space - self.getIncompressibleWidth()
        # print(width_in_px, self.getIncompressibleWidth(), (nb_cols - 1.) * self.space )
        width_in_px -= self.getIncompressibleWidth() + (nb_cols - 1.) * self.space
        ratio = width_in_px / pure_image_width
        for img in self:
                img.setToWidth(img.boundingRect().width() * ratio)
        self.packX(self.space)
        self.updateBoudingRect()

    def setToHeight(self, height_in_px):
        if height_in_px is None:
            return
        # nb_cols = len(self)
        pure_image_height = (self.boundingRect().height()) - self.getIncompressibleWidth()
        # print(width_in_px, self.getIncompressibleWidth(), (nb_cols - 1.) * self.space )
        height_in_px -= self.getIncompressibleWidth()
        ratio = height_in_px / pure_image_height
        for img in self:
                img.setToHeight(img.boundingRect().height() * ratio)
        self.packX(self.space)
        self.updateBoudingRect()

    # @return the block incompressible width
    def getIncompressibleWidth(self):
        extra_space = 0
        return extra_space

if __name__ == '__main__':

    img1 = Image2D('/media/D/Sample_images/sample_images_PA/trash_test_mem/counter/00.png')
    img2 = Image2D('/media/D/Sample_images/sample_images_PA/trash_test_mem/counter/01.png')
    img3 = Image2D('/media/D/Sample_images/sample_images_PA/trash_test_mem/counter/02.png')
    img4 = Image2D('/media/D/Sample_images/sample_images_PA/trash_test_mem/counter/03.png')
    result = img1 + img2

    print(result)

