from threading import Thread
from django.core.urlresolvers import reverse
from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import now
from django.forms import ModelForm
from socket import create_connection
from contest.models import Slave
from json import loads, dumps
from queue import Queue


result_Q = Queue()

def get_alive_slaves():
    "No of slaves alive"
    slaves = Slave.objects.all()
    alive = [s for s in slaves if s.is_alive()]
    return alive


def assign_job(data, jobs={}):
    """
    Assign the job to some slave in the available list.
    """
    pk = data['pk']
    is_assigned = pk in jobs.keys()
    assignment_needed = False
    if is_assigned:
        slave = jobs[pk]
        if not slave.is_alive():
            assignment_needed = True
    else:
        assignment_needed = True

    if assignment_needed:
        slaves = get_alive_slaves()
        # if slaves: what if there are no slaves?
        assigned = False
        while not assigned:  # assign to first non busy slave
            for slave in slaves:
                if not slave.busy:
                    jobs[pk] = slave
                    assigned = True
    address = jobs[pk].get_address()
    return jobs[pk], address

def ask_check_server(data):
    """
    Ask the check server is the current attempt done?
    Returns None/True/False and comments.
    data is of type
        data = {
            'pk'        :primary key of attempt,
            'qno'       :question number pk,
            'source'    :source code,
            'name'      :name of file,
            'language'  :language pk,
            }
    """
    slave, address = assign_job(data)

    with slave:
        try:
            sock = create_connection(address)
        except:
            value, remarks = None, 'Connection error'
        else:
            data = dumps(data)
            sock.sendall(data.encode('utf-8'))
            resp = sock.recv(4096)
            resp, remarks = loads(resp.decode())
        finally:
            sock.close()

    if resp == 'Timeout':
        value, remarks = False, resp
    elif resp == 'Correct':
        value, remarks = True, resp
    elif resp == 'Incorrect':
        value, remarks = False, resp
    elif resp == 'Error':
        value, remarks = False, remarks
    global result_Q
    data = loads(data)
    result_Q.put((data['pk'], value, remarks))


class Profile(User):
    """
    A user profile.
    Stores scores and other data
    """
    last_solved = models.DateTimeField(default=now)

    def _get_score(self):
        "Get the user's current score"
        attempts = Attempt.objects.filter(player=self).filter(correct=True)
        score = attempts.aggregate(models.Sum('marks'))
        print(score, 'score')
        marks = score['marks__sum']
        return marks if marks is not None else 0
    score = property(_get_score)


class Language(models.Model):
    """A programming language which is available on the check server.
    """
    def __str__(self):
        return self.name
    name = models.CharField(max_length=100)
    details = models.TextField()
    wrapper = models.FileField(upload_to='wrappers')