#!/usr/bin/python -u
#
# CS3700, Spring 2015
# Project 2 Starter Code
#

import sys
import socket
import time
import datetime
import select
import json

MSG_SIZE = 1500
DATA_SIZE = 500
TIMEOUT = 30
SEQUENCE = 0

# Bind to localhost and an ephemeral port
IP_PORT = sys.argv[1]
UDP_IP = IP_PORT[0:IP_PORT.find(":")]
UDP_PORT = int(IP_PORT[IP_PORT.find(":")+1:])
dest = (UDP_IP, UDP_PORT)

# Set up the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
sock.settimeout(TIMEOUT)

#################################################################
SENT_PACKETS = {}

def log(string):
  sys.stderr.write(datetime.datetime.now().strftime("%H:%M:%S.%f") + " " + string + "\n")

def send_next_packet():
  global SEQUENCE
  data = sys.stdin.read(DATA_SIZE)
  if (len(data) > 0):
    msg = json.dumps({"sequence": SEQUENCE, "data": data, "ack": False, "eof": False})
    SENT_PACKETS[SEQUENCE] = msg
    SEQUENCE += len(data)
    log("[added packet to send] " + str(SEQUENCE) + " (" + str(len(data)) + ")")
    return True
  else:
    LAST_SEQ = SEQUENCE
    return False

def build_packets_to_send():
  loop = send_next_packet()
  while loop:
    loop = send_next_packet()

build_packets_to_send()

######################################################################
def send_packet(msg):
  if sock.sendto(msg, dest) < len(msg):
      log("[error] unable to fully send packet")

def send_packets():
  values = SENT_PACKETS.values()
  for i in range(len(values)):
    send_packet(values[i])

for i in range(14):
  send_packets()

# Now read in data, send packets
while True:
  log("ABOUT TO SLEEP")
  result = sock.recvfrom(MSG_SIZE)
  if result:
    (data, addr) = result
    try:
      decoded = json.loads(data)
      if decoded['ack']:
        log("[recv ack] " + str(SEQUENCE))
        if decoded['ack'] == SEQUENCE:
          # if last in SEQUENCE, break
          break
        else: 
          continue
        

    except (ValueError, KeyError, TypeError):
      log("[recv corrupt packet]")
  else:
    log("[error] timeout")
    sys.exit(-1)

sock.sendto(json.dumps({"eof": True, "data": "", "sequence": SEQUENCE, "ack": False}), dest)
sys.exit(0)
