from typing import Callable
from yarnover.exceptions import PatternException

def not_negative(i : int):
    if i < 0:
        raise PatternException(f"Expecting a non-negative number, got {i}")
    return i

def positive(i : int):
    if i <= 0:
        raise PatternException(f"Expecting a positive number, got {i}")
    return i

def half(i): 
    result, remainder = divmod(i, 2)
    if remainder:
        raise PatternException(f"Expecting an even number, got {i}")
    else:
        return result

def decrease_pattern(from_stitches : int,
                     to_stitches : int,
                     over_rows,
                     odd_row_placement : str = "even"):
    decreases = from_stitches - to_stitches
    if decreases < 0:
        raise PatternException()
    decrease_pairs = half(decreases)
    return split_number(over_rows, decrease_pairs, odd_row_placement)

def decrease(from_stitches : int,
             to_stitches : int,
             row_count : int,
             f : Callable[[float], float]):
    decreases = from_stitches - to_stitches
    for i in range(row_count):
        stitches = int(f(float(i) / decreases))
        print(stitches)
    



def centered_split(total : int,
                   group_count : int,
                   group_size : int = 1,
                   ):
    total_to_divide = total - group_count*group_size
    space_count = group_count + 1
    space_size, remainder = divmod(total_to_divide, space_count)
    a = remainder // 2
    b = remainder - a
    return a, space_count-1, space_size, space_size+b

"""
split n into a groups of (m+1) then b groups of m
a+b = g
"""

def uncentered_split(total : int,
                     group_count : int,
                     group_size : int = 1,
                     ):
    total_to_divide = total - group_count*group_size
    space_count = group_count
    space_size, remainder = divmod(total_to_divide, space_count)
    large_spaces = remainder
    small_spaces = space_count - remainder 
    return large_spaces, space_size+1, small_spaces, space_size


def split_number(number : int,
                 group_count : int,
                 remainder_placement : str = "even"):
    if number < 0:
        raise PatternException()
    group_size, remainder = divmod(number, group_count)
    groups = [group_size] * group_count
    if remainder_placement == "top":
        groups[0] += remainder
    elif remainder_placement == "bottom":
        groups[-1] += remainder
    elif remainder_placement == "even":
        for block_number in range(remainder):
            groups[block_number] += 1
    return groups

if __name__=="__main__":
    w1 = 90
    w2 = 46
    rows = 116
    decrease_pairs = half(w1-w2)
    head, repeats, width, tail = centered_split(rows, decrease_pairs)
    # print(f"{head} rows, then {repeats} times [{width} rows + decrease] + {tail}")
    # print(decrease_pattern(w1, w2, rows))
    # print(uncentered_split(rows, decrease_pairs))
    decrease(100, 50, lambda x: 1.0-x)