import icontract

@icontract.invariant(lambda self: self.magic_number_is_correct is True)
class Image:

    PGM_PIXEL_OFFSET = 2
    PGM_FILE_EXTENSION = ".pgm"

    def __init__(self):
        self.magic_number_is_correct = True
        self.pixels = [[]]

    @icontract.require(lambda pixels: len(pixels) >= 4)
    def set_pixels(self, pixels):
        self.pixels = pixels

    @icontract.require(lambda filename: filename.endswith(Image.PGM_FILE_EXTENSION), "provided filename should be in .pgm format")
    def read_from_file(self, filename):
        file = open(filename, "r")
        content = file.readlines()
        content = Image.remove_comments(content)
        lines = Image.trim_lines(content)

        self.magic_number_is_correct = Image.check_for_magic_number(lines)

        w_and_h = Image.extract_width_and_height(lines[1])

        self.pixels = [[0 for x in range(w_and_h[0])] for y in range(w_and_h[1])]
        #initalizing this way is from https://stackoverflow.com/questions/6667201/how-to-define-a-two-dimensional-array

        k = Image.PGM_PIXEL_OFFSET

        for i in range(len(self.pixels)):
            for j in range(len(self.pixels[0])):
                self.pixels[i][j] = lines[k]
                k = k + 1

        print(f"File {filename} has been read")

        return self.pixels

    @icontract.require(lambda filename: filename.endswith(Image.PGM_FILE_EXTENSION), "filename should end with .pgm")
    def write_to_file(self, filename):

        file = open(filename, "w")



        file.writelines(["P2\n", f"{len(self.pixels[0])} {len(self.pixels)}\n", "255\n"])

        for l in self.pixels:
            for p in l:
                file.write(str(p))
                file.write("\n")

    #initializes a new 2d matrix in which the filtered image gets stored
    #after this the method gets the pixel values by using the kernel method get_pixel_value
    @icontract.require(lambda output_filename: output_filename.endswith(Image.PGM_FILE_EXTENSION), "desired filename should end with .pgm")
    def convolve(self, kernel, border_behavior, output_filename):

        filtered_pixels = [[0 for x in range(len(self.pixels[0]))] for y in range(len(self.pixels))]


        for height, rows in enumerate(self.pixels):
            for width, p in enumerate(rows):
                temp = int(kernel.get_pixel_value(height, width, self.pixels, border_behavior))
                filtered_pixels[height][width] = Image.get_value_in_range(temp)



        test = Image()
        test.set_pixels(filtered_pixels)
        test.write_to_file(output_filename)
        print(f"File {output_filename} has been created!")


    @staticmethod
    def remove_comments(content):
        for e in content:
            if e.startswith("#"):
                content.remove(e)
        return content


    @staticmethod
    def trim_lines(lines):
        for i in range(len(lines)):
            lines[i] = lines[i].removesuffix('\n')
        return  lines

    @staticmethod
    def check_for_magic_number(lines):
        if lines[0] == "P2":
            return True
        return False

    @staticmethod
    def extract_width_and_height(string):
        temp = string.split()
        temp[0] = int(temp[0])
        temp[1] = int(temp[1])
        return temp

    @staticmethod
    def get_value_in_range(value):
        if value < 0:
            return 0
        if value > 255:
            return 255
        return value

'''        for width, rows in enumerate(self.pixels):
            for height, p in enumerate(rows):
                temp = int(kernel.get_pixel_value(height, width, self.pixels, border_behavior))
                filtered_pixels[width][height] = Image.get_value_in_range(temp)'''