from tabulous._selection_model import SelectionModel
from ._utils import selection_equal

def _dummy_counter(i: int):
    return lambda: i

NUM = 10  # row count and column count

def test_move_only():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.move_to(0, 0)
    assert selection_equal(model.ranges, [(slice(0, 1), slice(0, 1))])
    model.move_to(2, 1)
    assert selection_equal(model.ranges, [(slice(2, 3), slice(1, 2))])
    # -1 means selection on row/column header
    model.move_to(-1, 1)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(1, 2))])
    model.move_to(-1, 3)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(3, 4))])
    model.move_to(1, -1)
    assert selection_equal(model.ranges, [(slice(1, 2), slice(0, NUM))])
    model.move_to(3, -1)
    assert selection_equal(model.ranges, [(slice(3, 4), slice(0, NUM))])


def test_jump_only():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.jump_to(0, 0)
    assert selection_equal(model.ranges, [(slice(0, 1), slice(0, 1))])
    model.jump_to(2, 1)
    assert selection_equal(model.ranges, [(slice(2, 3), slice(1, 2))])
    # -1 means selection on row/column header
    model.jump_to(-1, 1)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(1, 2))])
    model.jump_to(-1, 3)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(3, 4))])
    model.jump_to(1, -1)
    assert selection_equal(model.ranges, [(slice(1, 2), slice(0, NUM))])
    model.jump_to(3, -1)
    assert selection_equal(model.ranges, [(slice(3, 4), slice(0, NUM))])

def test_move_with_shift_on_off():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.move_to(2, 2)
    model.set_shift(True)
    model.move_to(3, 2)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.set_shift(False)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.set_shift(True)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.move_to(4, 2)
    assert selection_equal(model.ranges, [(slice(2, 5), slice(2, 3))])

def test_move_with_shift_on_move_off():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.move_to(2, 2)
    model.set_shift(True)
    model.move_to(3, 2)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.set_shift(False)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.move_to(4, 2)
    model.set_shift(True)
    assert selection_equal(model.ranges, [(slice(4, 5), slice(2, 3))])
    model.move_to(5, 2)
    assert selection_equal(model.ranges, [(slice(4, 6), slice(2, 3))])

def test_jump_with_shift_on_off():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.jump_to(2, 2)
    model.set_shift(True)
    model.jump_to(3, 2)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.set_shift(False)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.set_shift(True)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.jump_to(4, 2)
    assert selection_equal(model.ranges, [(slice(2, 5), slice(2, 3))])

def test_jump_with_shift_on_jump_off():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.jump_to(2, 2)
    model.set_shift(True)
    model.jump_to(3, 2)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.set_shift(False)
    assert selection_equal(model.ranges, [(slice(2, 4), slice(2, 3))])
    model.jump_to(4, 2)
    model.set_shift(True)
    assert selection_equal(model.ranges, [(slice(4, 5), slice(2, 3))])
    model.jump_to(5, 2)
    assert selection_equal(model.ranges, [(slice(4, 6), slice(2, 3))])

def test_drag_on_cells():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.move_to(0, 0)
    model.set_shift(True)
    model.move_to(2, 3)
    assert selection_equal(model.ranges, [(slice(0, 3), slice(0, 4))])
    model.move_to(4, 2)
    assert selection_equal(model.ranges, [(slice(0, 5), slice(0, 3))])
    model.set_shift(False)
    assert selection_equal(model.ranges, [(slice(0, 5), slice(0, 3))])
    model.move_to(6, 6)
    assert selection_equal(model.ranges, [(slice(6, 7), slice(6, 7))])
    model.set_shift(True)
    assert selection_equal(model.ranges, [(slice(6, 7), slice(6, 7))])
    model.move_to(4, 4)
    assert selection_equal(model.ranges, [(slice(4, 7), slice(4, 7))])

def test_drag_on_header():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.move_to(0, 0)
    model.set_shift(True)
    model.move_to(-1, 3)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(0, 4))])
    model.move_to(-1, 2)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(0, 3))])
    model.set_shift(False)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(0, 3))])
    model.move_to(6, 6)
    assert selection_equal(model.ranges, [(slice(6, 7), slice(6, 7))])
    model.set_shift(True)
    assert selection_equal(model.ranges, [(slice(6, 7), slice(6, 7))])
    model.move_to(4, -1)
    assert selection_equal(model.ranges, [(slice(4, 7), slice(0, NUM))])

def test_jump_with_ctrl():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.move_to(0, 0)
    model.jump_to(3, 3)
    assert selection_equal(model.ranges, [(slice(3, 4), slice(3, 4))])
    model.set_ctrl(True)
    model.jump_to(5, 5)
    assert selection_equal(model.ranges, [(slice(3, 4), slice(3, 4)), (slice(5, 6), slice(5, 6))])
    model.set_ctrl(False)
    assert selection_equal(model.ranges, [(slice(3, 4), slice(3, 4)), (slice(5, 6), slice(5, 6))])
    model.set_ctrl(True)
    assert selection_equal(model.ranges, [(slice(3, 4), slice(3, 4)), (slice(5, 6), slice(5, 6))])
    model.jump_to(7, 7)
    assert selection_equal(model.ranges, [(slice(3, 4), slice(3, 4)), (slice(5, 6), slice(5, 6)), (slice(7, 8), slice(7, 8))])
    model.set_ctrl(False)
    model.jump_to(0, 0)
    assert selection_equal(model.ranges, [(slice(0, 1), slice(0, 1))])
    model.set_ctrl(True)
    model.jump_to(1, 2)
    assert selection_equal(model.ranges, [(slice(0, 1), slice(0, 1)), (slice(1, 2), slice(2, 3))])

def test_ctrl_and_shift():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.move_to(0, 0)
    model.set_ctrl(True)
    model.jump_to(0, 2)
    model.set_shift(True)
    model.set_ctrl(False)
    model.jump_to(3, 2)
    assert selection_equal(model.ranges, [(slice(0, 1), slice(0, 1)), (slice(0, 4), slice(2, 3))])
    model.set_ctrl(True)
    model.set_shift(False)
    model.jump_to(5, 0)
    assert selection_equal(model.ranges, [(slice(0, 1), slice(0, 1)), (slice(0, 4), slice(2, 3)), (slice(5, 6), slice(0, 1))])
    model.set_ctrl(False)
    model.jump_to(0, 0)
    assert selection_equal(model.ranges, [(slice(0, 1), slice(0, 1))])

def test_ctrl_and_shift_on_header():
    model = SelectionModel(_dummy_counter(NUM), _dummy_counter(NUM))
    model.jump_to(-1, 0)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(0, 1))])
    model.set_ctrl(True)
    model.jump_to(-1, 2)
    model.jump_to(-1, 4)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(0, 1)), (slice(0, NUM), slice(2, 3)), (slice(0, NUM), slice(4, 5))])
    model.set_shift(True)
    model.jump_to(-1, 5)
    assert selection_equal(model.ranges, [(slice(0, NUM), slice(0, 1)), (slice(0, NUM), slice(2, 3)), (slice(0, NUM), slice(4, 6))])
