# -*- coding: utf-8 -*-
"""
Created on Thu Nov 23 10:21:54 2023

@author: u0072088
"""

from image_aesthetic_maps.decomposition.quad_tree import QuadTree
from image_aesthetic_maps.Patch import Patch

def test_quad_tree_split_even_length():
    """
    Using the split function with an even number shoud produce a width
    that is equal to the start of the second half
    """
    # Arrange
    test_length = 6
    expected_width = 3
    expected_start = 3
    
    # Act
    width, start = QuadTree.generate_interval_data(test_length)
    
    # Assert
    assert width == expected_width and start == expected_start

def test_quad_tree_split_uneven_length():
    """
    Using the split function with an ueven number should produce a width and a
    start that equals the width - 1
    """
    # Arrange
    test_length = 7
    expected_width = 4
    expected_start = 3
    
    # Act
    width, start = QuadTree.generate_interval_data(test_length)
    
    # Assert
    assert width == expected_width and start == expected_start

def test_quad_tree_equal_patch_sizes():
    """
    Decomposing a patch using the quad tree decomposition should produce
    four equal sized patches
    """
    # Arrange
    patch = Patch(20, 30, 40, 51)
    
    # Act
    quads = QuadTree.generate(patch)
    
    # Assert
    widths = []
    heights = []
    for quad in quads:
        widths.append(quad._width)
        heights.append(quad._height)
        
    assert len(set(widths)) == 1, "All widths should be the same"
    assert len(set(heights)) == 1, "All heights should be the same"
    
def test_quad_tree_stores_decomposition_type():
    """
    Patches generated by the QuadTree decomposition contain an attribute
    that stores the decomposition type
    """
    # Arrange
    patch = Patch(20, 30, 40, 51)
    
    # Act
    patches = QuadTree.generate(patch)
    
    # Assert
    for patch in patches:
        assert hasattr(patch, "_decomposition"), "Patch should have _decomposition attribute"
        assert patch._decomposition == "quad_tree", "Decomposition attribute should equal 'quad_tree'"
        
def test_quad_tree_stores_quadrant_information():
    """
    Patches generated by the QuadTree decomposition contain a _quadrant attribute
    with a unique value from [1, 2, 3, 4]
    """
    # Arrange
    patch = Patch(20, 30, 40, 51)
    
    # Act
    patches = QuadTree.generate(patch)
    
    # Assert
    quadrant_attribute_values = []
    for patch in patches:
        assert hasattr(patch, "_quadrant"), "Patch should have _quadrant attribute"
        quadrant_attribute_values.append(patch._quadrant)
        
    assert len(set(quadrant_attribute_values).intersection([1, 2, 3, 4])) == 4, "There should be four different quadrant attribute values"
    
def test_quad_tree_stores_grid_information():
    """
    Patches generated by the QuadTree decomposition contain a _grid attribute that contains
    the location of each patch in a grid structure.
    These locations are also unique for each of the four patches
    """
    # Arrange
    patch = Patch(20, 30, 40, 51)
    
    # Act
    patches = QuadTree.generate(patch)
    
    # Assert
    grid_attribute_values = []
    for patch in patches:
        assert hasattr(patch, "_grid"), "Patch should have a _grid attribute"
        assert 'row' in patch._grid, "Patch _grid attribute should have a row value"
        assert 'col' in patch._grid, "Patch _grid attribute should have a column value"
        assert 'depth' in patch._grid, "Patch _grid attribute should have depth value"
        grid_attribute_values.append((patch._grid['row'], patch._grid['col']))
        
    assert len(set(grid_attribute_values)) == 4, "Quad tree decomposition should produce four unique grid locations"
    
def test_quad_tree_grid_depth_values():
    """
    When generating a QuadTree, the grid level of the generated patches should
    be one higher than the grid level of the root node
    """
    
    # Arrange
    root_node = Patch(0, 0, 128, 128)
    
    # Act
    level_1_patches = root_node.decompose(QuadTree)
    level_2_patches = level_1_patches[0].decompose(QuadTree)
    
    level_1_depth = [patch._grid['depth'] for patch in level_1_patches]
    level_2_depth = [patch._grid['depth'] for patch in level_2_patches]
    
    # Assert
    assert len(set(level_1_depth)) == 1, "Decomposition should produce a single new depth"
    assert len(set(level_2_depth)) == 1, "Decomposition should produce a single new depth"
    
    assert level_1_depth[0] == level_2_depth[0] - 1, "Depth level should increase for QuadTree decompositions"