#!/usr/bin/env python3
#
#####
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#####

# Run alternate voting scenarios: vary the number of seats, remove candidates,
# or do a run-off with only the specified candidates.  Candidate names can
# be specified using either their first name, last name, or full name without
# any spaces (independent of case).  Examples:
#
# Examples:
#   whatif.py ../Meetings/20110712/raw_board_votes.txt 10
#   whatif.py ../Meetings/20110712/raw_board_votes.txt -LawrenceRosen
#   whatif.py ../Meetings/20110712/raw_board_votes.txt 1 kulp noirin geir chris

import os.path
import sys
import re

sys.path.append(os.path.join(os.path.dirname(__file__), 'monitoring'))
import stv_tool

def usage():
  print('Usage: %s [-v] RAW_VOTES_FILE [seats] [-]name...' % scriptname)
  sys.exit(1)

if __name__ == '__main__':
  scriptname = sys.argv.pop(0)

  if sys.argv and sys.argv[0] == '-v':
    stv_tool.VERBOSE = True
    sys.argv.pop(0)

  # extract required vote file argument, and load votes from it
  if not sys.argv or not os.path.exists(sys.argv[0]): usage()
  votefile = sys.argv.pop(0)
  names, votes = stv_tool.load_votes(votefile)

  # extract optional number of seats argument
  if sys.argv and sys.argv[0].isdigit():
    seats = int(sys.argv.pop(0))
  else:
    seats = 9

  # extract an alias list of first, last, and joined names
  alias = {}
  for name in names:
    lname = re.sub(r'[^\w ]', '', name.lower())
    alias[lname.replace(' ', '')] = name
    for part in lname.split(' '):
      alias[part] = name

  # validate input
  for arg in sys.argv:
    if arg.lstrip('-').lower() not in alias:
      sys.stderr.write('invalid selection: %s\n' % arg)
      usage()

  if not sys.argv:
    # no changes to the candidates running
    pass
  elif sys.argv[0][0] == '-':
    # remove candidates from vote
    for name in sys.argv: names.remove(alias[name.lstrip('-').lower()])
  else:
    # only include specified candidates
    # NOTE: order is important, so sort the names for repeatability
    names = [ alias[n.lower()] for n in sorted(sys.argv) ]

  # Trim the raw votes based on cmdline params. Eliminate votes that
  # are not for one of the allowed names. Do not include voters who
  # did not vote for anybody [post-trimming].
  trimmed = [ ]
  for voteseq in votes:
    newseq = [ v for v in voteseq if v in names ]
    if newseq:
      trimmed.append(newseq)

  # run the vote
  candidates = stv_tool.run_stv(names, trimmed, seats)
  candidates.print_results()
  print('Done!')
