#   pyRCV2: Preferential vote counting
#   Copyright © 2020–2021  Lee Yingtong Li (RunasSudo)
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <https://www.gnu.org/licenses/>.

from pyRCV2 import constraints

class CounterStub:
	pass

def test_constraints_otten():
	"""Check constraints matrix is stabilised correctly, according to example by Otten J. Voting Matters 2001;13(3):4-7"""
	counter = CounterStub()
	counter._constraint_matrix = constraints.ConstraintMatrix([2, 3])
	cm = counter._constraint_matrix
	
	# Fill in details
	c = cm.get([0, 0]); c.max = 7; c.cands = 4
	c = cm.get([0, 1]); c.max = 6; c.cands = 11
	c = cm.get([0, 2]); c.max = 1; c.cands = 2
	c = cm.get([0, -1]); c.min = 7; c.max = 7; c.cands = 17
	
	c = cm.get([1, 0]); c.max = 7; c.cands = 7
	c = cm.get([1, 1]); c.max = 6; c.cands = 3
	c = cm.get([1, 2]); c.max = 1; c.cands = 1
	c = cm.get([1, -1]); c.min = 7; c.max = 7; c.cands = 11
	
	c = cm.get([-1, 0]); c.min = 7; c.max = 7; c.cands = 11
	c = cm.get([-1, 1]); c.min = 6; c.max = 6; c.cands = 14
	c = cm.get([-1, 2]); c.min = 1; c.max = 1; c.cands = 3
	c = cm.get([-1, -1]); c.min = 14; c.max = 14; c.cands = 28
	
	assert cm.get([0, 0]).max != 4
	assert cm.get([1, 1]).max != 3
	assert cm.get([0, 1]).min != 3
	assert cm.get([1, 0]).min != 3
	
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == True
	
	assert cm.get([0, 0]).max == 4
	assert cm.get([1, 1]).max == 3
	assert cm.get([0, 1]).min == 3
	assert cm.get([1, 0]).min == 3
	
	# Election of Welsh Man
	cm.get([0, 2]).elected += 1
	cm.get([-1, 2]).elected += 1
	cm.get([0, -1]).elected += 1
	
	assert cm.get([0, 2]).min != 1
	assert cm.get([0, 0]).max != 3
	assert cm.get([1, 0]).min != 4
	assert cm.get([1, 2]).max != 0
	
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == True
	
	assert cm.get([0, 2]).min == 1
	assert cm.get([0, 0]).max == 3
	assert cm.get([1, 0]).min == 4
	assert cm.get([1, 2]).max == 0
	
	# Welsh Man and Welsh Woman are doomed
	assert cm.get([0, 2]).elected == cm.get([0, 2]).max
	assert cm.get([1, 2]).elected == cm.get([1, 2]).max
	cm.get([0, 2]).cands = 1
	cm.get([1, 2]).cands = 0
	
	# Election of 2 English Men
	cm.get([0, 0]).elected += 2
	cm.get([-1, 0]).elected += 2
	cm.get([0, -1]).elected += 2
	
	# Election of 2 English Women
	cm.get([1, 0]).elected += 2
	cm.get([-1, 0]).elected += 2
	cm.get([1, -1]).elected += 2
	
	# Exclusion of Scottish Woman
	cm.get([1, 1]).cands -= 1
	cm.get([-1, 1]).cands -= 1
	cm.get([1, -1]).cands -= 1
	
	assert cm.get([0, 0]).min != 2
	assert cm.get([1, 1]).max != 2
	assert cm.get([0, 1]).min != 4
	assert cm.get([1, 0]).min != 5
	assert cm.get([0, 0]).max != 2
	assert cm.get([0, 1]).max != 4
	assert cm.get([1, 1]).min != 2
	assert cm.get([1, 0]).max != 5
	
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == False
	assert constraints.step_matrix(counter) == True
	
	assert cm.get([0, 0]).min == 2
	assert cm.get([1, 1]).max == 2
	assert cm.get([0, 1]).min == 4
	assert cm.get([1, 0]).min == 5
	assert cm.get([0, 0]).max == 2
	assert cm.get([0, 1]).max == 4
	assert cm.get([1, 1]).min == 2
	assert cm.get([1, 0]).max == 5
	
	# English Men doomed
	assert cm.get([0, 0]).elected == cm.get([0, 0]).max
	# Scottish Women guarded
	assert cm.get([1, 1]).cands == cm.get([1, 1]).min
