#!/usr/bin/env python3

from .streamtools import Stream
from .rainbow import msg


class Image:
    """
    An Image has a width a height and a Boolean pixmap (matrix).
    All parameters are optional.

    You can specify the width and the height without pixmap.
    If you give a pixmap only, the Image will be auto-sized even if the sizes
    are not equal.

    Keyword arguments:
    width -- Image width (default None)
    height -- Image height (default None)
    pixmap -- matrix of binary data (default None)
    """

    def __init__(self, width=None, height=None, pixmap=None):
        self.width = width
        self.height = height
        self.pixmap = pixmap  # pixmap as matrix

        if width is None and height is None and pixmap is None:
            self.width = 0
            self.height = 0
            self.blank()

        elif width is not None and height is not None and pixmap is not None:
            self.resize(width, height)

        elif self.pixmap is not None:
            self.is_pixmap(self.pixmap)
            self.auto_size()

        elif self.width is not None or self.height is not None:
            self.blank()

        # Size check
        else:
            if not self.check_width(self.pixmap):
                self.fill_width()
            if not self.check_height(self.pixmap):
                self.fill_height()

    def is_pixmap(self, pixmap):
        """
        Check if the given pixmap has a pixmap format.
        Tell you what is wrong and kill the program if it is not the case.
        """
        if type(pixmap) is list:
            if type(pixmap[0]) is list:
                for i in pixmap:
                    for j in i:
                        if j != 0 and j != 1:
                            msg("pixmap wrong data !(1|0)", 3, "Image", j, i)
            else:
                msg("pixmap is not a matrix", 3, "Image", type(pixmap[0]))
        else:
            msg("pixmap is not a matrix", 3, "Image", type(pixmap))

    def auto_size(self):
        """Auto fill width and height"""
        self.width = max([len(i) for i in self.pixmap])
        self.height = len(self.pixmap)
        self.fill_width()
        self.fill_height()

    def check_width(self, pixmap):
        """
        Check if the width of the image is the same as the width of the pixmap
        """
        return all(len(i) == self.width for i in pixmap)

    def get_pixmap_width(self, pixmap):
        """Get the width of a pixmap"""
        return max(len(i) for i in pixmap)

    def fill_width(self):
        """Fills the remaining width of the pixmap with 0"""
        self.pixmap = [
            i[:self.width] + [0] * (self.width - len(i)) for i in self.pixmap
        ]

    def check_height(self, pixmap):
        """
        Check if the height of the image is the same as the height of the
        pixmap
        """
        return len(pixmap) == self.height

    def get_pixmap_height(self, pixmap):
        """Get the height of a pixmap"""
        return len(pixmap)

    def fill_height(self):
        """Fills the remaining height of the pixmap with 0"""
        if len(self.pixmap) < self.height:
            self.pixmap = (
                self.pixmap +
                [[0] * self.width] * (self.height - len(self.pixmap)))
        else:
            self.pixmap = self.pixmap[0:self.height]

    def resize(self, width, height):
        """Resize Image"""
        self.auto_size()
        # Height
        if height < self.height:
            self.pixmap = self.pixmap[0:height]
        elif height > self.height:
            while len(self.pixmap) < height:
                self.pixmap.append([0] * self.width)
        # Width
        if width < self.width:
            self.pixmap = [i[:width] for i in self.pixmap]
        elif width > self.width:
            self.pixmap = [i + [0] * (width - self.width) for i in self.pixmap]

        self.height = height
        self.width = width

    def __str__(self):
        return str(self.pixmap)

    def __repr__(self):
        data = ['Image(', self.width, ',', self.height, ',', self.pixmap, ')']
        return str(''.join(map(str, data)))

    def get_pixmap(self):
        """Get the Image data"""
        return self.pixmap

    def set_pixmap(self, pixmap):
        """Set a new pixmap and check for width and height"""
        self.is_pixmap(pixmap)
        pixmap_height = self.get_pixmap_height(pixmap)
        pixmap_width = self.get_pixmap_width(pixmap)
        if pixmap_height > self.height:
            msg("pixmap too high", 2, "Image.set_pixmap()", pixmap_height)
        if pixmap_width > self.width:
            msg("pixmap too large", 2, "Image.set_pixmap()", pixmap_width)
        self.pixmap = pixmap
        self.resize(self.width, self.height)

    def blank(self):
        """Clear the Image"""
        self.pixmap = [
            [0 for j in range(self.width)] for i in range(self.height)
        ]

    def fill(self):
        """Fill the Image"""
        self.pixmap = [
            [1 for j in range(self.width)] for i in range(self.height)
        ]

    def paste(self, image, x=0, y=0, mode='fill'):
        """
        Paste an Image over another, can take an image or a pixmap.

        Keyword arguments:
        image -- Image
        x -- x location (default 0)
        y -- y location (default 0)
        mode -- paste mode (default 'fill')
            ['fill', 'replace', 'invert', 'modulo']
        """
        if mode == 'fill':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    if i < self.height and j < self.width:
                        if i >= 0 and j >= 0:
                            self.pixmap[i][j] |= image.get_pixmap()[i-y][j-x]

        elif mode == 'replace':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    if i < self.height and j < self.width:
                        if i >= 0 and j >= 0:
                            self.pixmap[i][j] = image.get_pixmap()[i-y][j-x]

        elif mode == 'invert':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    if i < self.height and j < self.width:
                        if i >= 0 and j >= 0:
                            self.pixmap[i][j] ^= image.get_pixmap()[i-y][j-x]

        elif mode == 'modulo':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    self.pixmap[i % self.height][j % self.width] |= (
                        image.get_pixmap()[i-y][j-x])

        else:
            msg("no such paste mode", 2, "Image.paste()", mode)

    def screen_data(self):
        """Used by Screen to access the image that needs to be added
        """
        return self

#!/usr/bin/env python3

from .streamtools import Stream
from .rainbow import msg


class Image:
    """
    An Image has a width a height and a Boolean pixmap (matrix).
    All parameters are optional.

    You can specify the width and the height without pixmap.
    If you give a pixmap only, the Image will be auto-sized even if the sizes
    are not equal.

    Keyword arguments:
    width -- Image width (default None)
    height -- Image height (default None)
    pixmap -- matrix of binary data (default None)
    """

    def __init__(self, width=None, height=None, pixmap=None):
        self.width = width
        self.height = height
        self.pixmap = pixmap  # pixmap as matrix

        if width is None and height is None and pixmap is None:
            self.width = 0
            self.height = 0
            self.blank()

        elif width is not None and height is not None and pixmap is not None:
            self.resize(width, height)

        elif self.pixmap is not None:
            self.is_pixmap(self.pixmap)
            self.auto_size()

        elif self.width is not None or self.height is not None:
            self.blank()

        # Size check
        else:
            if not self.check_width(self.pixmap):
                self.fill_width()
            if not self.check_height(self.pixmap):
                self.fill_height()

    def is_pixmap(self, pixmap):
        """
        Check if the given pixmap has a pixmap format.
        Tell you what is wrong and kill the program if it is not the case.
        """
        if type(pixmap) is list:
            if type(pixmap[0]) is list:
                for i in pixmap:
                    for j in i:
                        if j != 0 and j != 1:
                            msg("pixmap wrong data !(1|0)", 3, "Image", j, i)
            else:
                msg("pixmap is not a matrix", 3, "Image", type(pixmap[0]))
        else:
            msg("pixmap is not a matrix", 3, "Image", type(pixmap))

    def auto_size(self):
        """Auto fill width and height"""
        self.width = max([len(i) for i in self.pixmap])
        self.height = len(self.pixmap)
        self.fill_width()
        self.fill_height()

    def check_width(self, pixmap):
        """
        Check if the width of the image is the same as the width of the pixmap
        """
        return all(len(i) == self.width for i in pixmap)

    def get_pixmap_width(self, pixmap):
        """Get the width of a pixmap"""
        return max(len(i) for i in pixmap)

    def fill_width(self):
        """Fills the remaining width of the pixmap with 0"""
        self.pixmap = [
            i[:self.width] + [0] * (self.width - len(i)) for i in self.pixmap
        ]

    def check_height(self, pixmap):
        """
        Check if the height of the image is the same as the height of the
        pixmap
        """
        return len(pixmap) == self.height

    def get_pixmap_height(self, pixmap):
        """Get the height of a pixmap"""
        return len(pixmap)

    def fill_height(self):
        """Fills the remaining height of the pixmap with 0"""
        if len(self.pixmap) < self.height:
            self.pixmap = (
                self.pixmap +
                [[0] * self.width] * (self.height - len(self.pixmap)))
        else:
            self.pixmap = self.pixmap[0:self.height]

    def resize(self, width, height):
        """Resize Image"""
        self.auto_size()
        # Height
        if height < self.height:
            self.pixmap = self.pixmap[0:height]
        elif height > self.height:
            while len(self.pixmap) < height:
                self.pixmap.append([0] * self.width)
        # Width
        if width < self.width:
            self.pixmap = [i[:width] for i in self.pixmap]
        elif width > self.width:
            self.pixmap = [i + [0] * (width - self.width) for i in self.pixmap]

        self.height = height
        self.width = width

    def __str__(self):
        return str(self.pixmap)

    def __repr__(self):
        data = ['Image(', self.width, ',', self.height, ',', self.pixmap, ')']
        return str(''.join(map(str, data)))

    def get_pixmap(self):
        """Get the Image data"""
        return self.pixmap

    def set_pixmap(self, pixmap):
        """Set a new pixmap and check for width and height"""
        self.is_pixmap(pixmap)
        pixmap_height = self.get_pixmap_height(pixmap)
        pixmap_width = self.get_pixmap_width(pixmap)
        if pixmap_height > self.height:
            msg("pixmap too high", 2, "Image.set_pixmap()", pixmap_height)
        if pixmap_width > self.width:
            msg("pixmap too large", 2, "Image.set_pixmap()", pixmap_width)
        self.pixmap = pixmap
        self.resize(self.width, self.height)

    def blank(self):
        """Clear the Image"""
        self.pixmap = [
            [0 for j in range(self.width)] for i in range(self.height)
        ]

    def fill(self):
        """Fill the Image"""
        self.pixmap = [
            [1 for j in range(self.width)] for i in range(self.height)
        ]

    def paste(self, image, x=0, y=0, mode='fill'):
        """
        Paste an Image over another, can take an image or a pixmap.

        Keyword arguments:
        image -- Image
        x -- x location (default 0)
        y -- y location (default 0)
        mode -- paste mode (default 'fill')
            ['fill', 'replace', 'invert', 'modulo']
        """
        if mode == 'fill':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    if i < self.height and j < self.width:
                        if i >= 0 and j >= 0:
                            self.pixmap[i][j] |= image.get_pixmap()[i-y][j-x]

        elif mode == 'replace':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    if i < self.height and j < self.width:
                        if i >= 0 and j >= 0:
                            self.pixmap[i][j] = image.get_pixmap()[i-y][j-x]

        elif mode == 'invert':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    if i < self.height and j < self.width:
                        if i >= 0 and j >= 0:
                            self.pixmap[i][j] ^= image.get_pixmap()[i-y][j-x]

        elif mode == 'modulo':
            for i in range(y, image.height + y):
                for j in range(x, image.width + x):
                    self.pixmap[i % self.height][j % self.width] |= (
                        image.get_pixmap()[i-y][j-x])

        else:
            msg("no such paste mode", 2, "Image.paste()", mode)

    def screen_data(self):
        """Used by Screen to access the image that needs to be added
        """
        return self

#!/usr/bin/env python3 An Image has a width a height and a Boolean pixmap (matrix).     All parameters are optional.      You can specify the width and the height without pixmap.     If you give a pixmap only, the Image will be auto-sized even if the sizes     are not equal.      Keyword arguments:     width -- Image width (default None)     height -- Image height (default None)     pixmap -- matrix of binary data (default None) # pixmap as matrix # Size check Check if the given pixmap has a pixmap format.         Tell you what is wrong and kill the program if it is not the case. Auto fill width and height Check if the width of the image is the same as the width of the pixmap Get the width of a pixmap Fills the remaining width of the pixmap with 0 Check if the height of the image is the same as the height of the         pixmap Get the height of a pixmap Fills the remaining height of the pixmap with 0 Resize Image # Height # Width Get the Image data Set a new pixmap and check for width and height Clear the Image Fill the Image Paste an Image over another, can take an image or a pixmap.          Keyword arguments:         image -- Image         x -- x location (default 0)         y -- y location (default 0)         mode -- paste mode (default 'fill')             ['fill', 'replace', 'invert', 'modulo'] Used by Screen to access the image that needs to be added