# Usage:
#   - python this_script path_to_image
#
# Purpose:  This script generates random test points using Mitchel's Best Candidate-II
#           algorithm. These points are displayed on the input image.
#
#           The user can also designate rectangles for those random points to be
#           generated within.
#
#           We use this utility to create random points within areas of a building we
#           have mapped.

import sys
from sys import argv, stderr, exit
from PIL import Image, ImageTk
from random import random
import Tkinter
import requests
from requests.exceptions import HTTPError
import json
import os
import math
from server_interface import ServerInterface

APP = {}  # contains global information needed by tkinter functions
NUM_POINTS = 2  # number of vertices in a rectangle
NUM_TEST_POINTS = 20  # Number of test points we want
NUM_CANDIDATES = 20  # Number of attempts per test point chosen
SERVER_URL = "http://mapbuilder.herokuapp.com/"
FID = -1 # Floor ID

SERVER = None
FLOOR_NAME = None

class Point(object):

    """ Point Object """

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def save(self, fid, c):
        """Given a floor id and counter will create a point in the database"""
        n = c()
        name = '{} TEST: {}'.format(FLOOR_NAME, n)

        data = {
            'x_coordinate': self.x,
            'y_coordinate': self.y,
            'short_name': n,
            'verbose_name': name,
            'direction': 0,
            'floor': FID
        }

        try:
            SERVER.post(ServerInterface.LOCATION, data)
            print('Saved {} at ({},{})'.format(name, self.x, self.y))
        except HTTPError, e:
            print >> sys.stderr, e
            print >> sys.stderr, 'Unable to save {}'.format(name)


class Rectangle(object):

    """ Rectangle Object """

    def __init__(self, corners):
        if len(corners) != 2:
            stderr.write("not enough corners.\n")
            exit()

        p1 = corners[0]
        p2 = corners[1]

        self.XL = min(p1.x, p2.x)
        self.XR = max(p1.x, p2.x)
        self.YT = min(p1.y, p2.y)
        self.YB = max(p1.y, p2.y)

    def corners(self):
        return [Point(self.XL, self.YT),
                Point(self.XR, self.YT),
                Point(self.XR, self.YB),
                Point(self.XL, self.YB)]

    def contains(self, point):
        """ Checks whether the given rectangle contains the given point """
        if ((self.XL <= point.x <= self.XR) and
                (self.YT <= point.y <= self.YB)):
            return True
        else:
            return False


def getRandomPoints():
    """ Gets and returns a list of random Points """
    test_points = []
    while len(test_points) < NUM_TEST_POINTS:
        new_point = bestCandidate(test_points)
        test_points.append(new_point)
    return test_points


def bestCandidate(test_points):
    """ Runs Mitchell's Best-Candidate II Algorithm to generate a dispersed random Point """
    if len(test_points) == 0:
        return getCandidatePoint()
    bestDistance = 0
    for i in range(NUM_CANDIDATES):
        c = getCandidatePoint()
        d = distance(findClosest(test_points, c), c)
        if d > bestDistance:
            best = c
            bestDistance = d
    return best


def getCandidatePoint():
    """ Returns a random Point in the image within at least one of the rectangles """
    global APP
    if APP['rectangles'] == []:
        return RandomPoint()

    attempts = 0  # Caps total number of tries allowed