"""
Test the voting implementation with a single authority.
"""
import os
import subprocess
import time
import random
import shutil


NUM_AUTHORITIES = 1
NUM_VOTERS = 5


def wait_for_after(ts):
  now = time.time()
  if now < ts:
    print "waiting", ts - now, "seconds"
    time.sleep(ts - now)
  else:
    print "not waiting"

def get_config(section, option, filename=None, expand=False):
  args = ["gnunet-config"]
  if filename is not None:
    args.extend(["-c", filename])
  args.extend(["-s", section])
  args.extend(["-o", option])
  if expand:
    args.extend(["-f"])
  return subprocess.check_output(args).strip()


def create_identity(name, config=None):
  args = ["gnunet-identity", "-C", name]
  if config is not None:
    args.extend(["-c", config])
  subprocess.check_call(args)

def get_identity_pubkey(name, config=None):
  args = ["gnunet-identity", "-d", name]
  if config is not None:
    args.extend(["-c", config])
  out = subprocess.check_output(args)
  components = out.split("-")
  return components[-1].strip()

testdir = subprocess.check_output(["mktemp", "-d", "test-voting-XXXXXXXXXX.d", "--tmpdir"])
testdir = testdir.strip()
ballot = os.path.join(testdir, "ballot")
print "testdir", testdir


testbed_conf = "test_voting.conf"
env = os.environ.copy()
env["GNUNET_TESTING_PREFIX"] = testdir
testbed = subprocess.Popen(["gnunet-testbed-profiler", "-n", "-c", testbed_conf, "-p", "1"], env=env)

ballot_filename = os.path.join(testdir, "ballot")

conf = []
conf.append(os.path.join(testdir, "0", "config"))

for c in conf:
  while not os.path.exists(c):
    print "waiting for creation of", c
    time.sleep(0.1)

print "test dir:", testdir


# start authority
# FIXME: using gnunet-arm for this might be nicer,
auth = subprocess.Popen(["gnunet-daemon-ballot-tally", "-c", conf[0]])

private_key_filename = get_config("peer", "private_key", conf[0], expand=True)

public_key = subprocess.check_output(["gnunet-ecc", "--print-public-key", private_key_filename]).strip()

print "public key", public_key

for vi in range(NUM_VOTERS):
  create_identity("voter"+str(vi), conf[0])

create_identity("issuer", conf[0])
create_identity("groupca", conf[0])

print "created identities"

ballot = open(ballot_filename, "w")

now = int(time.time())
TS_KEYGEN_START = now + 5
TS_KEYGEN_END = now + 10
TS_START = now + 15
TS_CLOSING = now + 20
TS_CONCLUDE = now + 25
TS_QUERY = now + 35
TS_END = now + 40

ballot.write("[authorities]\n")
ballot.write("auth0 = %s\n" % public_key)
ballot.write("[election]\n")
ballot.write("TOPIC = mytopic\n")
ballot.write("THRESHOLD = 1\n")
ballot.write("CHOICES = yes//no//maybe\n")
ballot.write("GROUP = mygroup\n")
ballot.write("CA_PUB = %s\n" % get_identity_pubkey("groupca", conf[0]))
ballot.write("TIMESTAMP_KEYGEN_START = %s\n" % TS_KEYGEN_START)
ballot.write("TIMESTAMP_KEYGEN_END = %s\n" % TS_KEYGEN_END)
ballot.write("TIMESTAMP_START = %s\n" % TS_START)
ballot.write("TIMESTAMP_CLOSING = %s\n" % TS_CLOSING)
ballot.write("TIMESTAMP_CONCLUDE = %s\n" % TS_CONCLUDE)
ballot.write("TIMESTAMP_QUERY = %s\n" % TS_QUERY)
ballot.write("TIMESTAMP_END = %s\n" % TS_END)

ballot.close()

# create group certs for all voters
for vi in range(NUM_VOTERS):
  groupcert_filename = os.path.join(testdir, "v"+str(vi)+"-cert")
  groupcert_file = open(groupcert_filename, "w")

  v_pub = get_identity_pubkey("voter"+str(vi), conf[0])

  subprocess.check_call(["gnunet-ballot-group-certify", "-c", conf[0],
    "-g", "mygroup", "-e", "groupca", "-m", v_pub], stdout=groupcert_file)

  groupcert_file.close()

# register the ballot with authorities
subprocess.check_call(["gnunet-ballot", "-LINFO", "-i", ballot_filename, "-e", "issuer", "-c", conf[0]])

# register the ballot with authorities
subprocess.check_call(["gnunet-ballot", "-LINFO", "-r", ballot_filename, "-c", conf[0]])

wait_for_after(TS_KEYGEN_END)

print "getting threshold public key"

# get the threshold public key
subprocess.check_call(["gnunet-ballot", "-LDEBUG", "-k", ballot_filename, "-c", conf[0]])

print "threshold public key retrieved"

# actually vote
for vi in range(NUM_VOTERS):
  voter_ballot_filename = os.path.join(testdir, "v"+str(vi)+"-ballot")
  shutil.copy(ballot_filename, voter_ballot_filename)
  groupcert_filename = os.path.join(testdir, "v"+str(vi)+"-cert")
  # add voter's group information
  subprocess.check_call(["gnunet-ballot", "-g", groupcert_filename, voter_ballot_filename, "-c", conf[0]])

  ch = random.choice(["yes", "no", "maybe"])

  # actually vote ...
  subprocess.check_call(["gnunet-ballot", "-x", ch, voter_ballot_filename, "-e", "voter"+str(vi), "-c", conf[0]])

wait_for_after(TS_START)

for vi in range(NUM_VOTERS):
  voter_ballot_filename = os.path.join(testdir, "v"+str(vi)+"-ballot")
  # submit the ballot with the vote
  subprocess.check_call(["gnunet-ballot", "-s", voter_ballot_filename, "-c", conf[0]])

wait_for_after(TS_QUERY)

# query the result
subprocess.check_call(["gnunet-ballot", "-q", ballot_filename, "-c", conf[0]])

# FIXME: cleanup

