#!/usr/bin/env python3
# Copyright (c) 2015 Andrew Ruder <andy@aeruder.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import readline
import re
import time
import sys
import tkinter as tk
import tkinter.ttk as ttk
import queue
import threading
from PIL import Image

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

class ThreadedTask(threading.Thread):
    def __init__(self, cont):
        threading.Thread.__init__(self)
        self.controller = cont
    def run(self):
        class ClickError(Exception):
            pass

        def ensure_switched(captcha):
            broke = False
            for i in range(0, 50):
                try:
                    time.sleep(0.25)
                    captcha.click()
                except:
                    broke = True
                    break
            if not broke:
                raise ClickError()

        players = [
            "Hosmer, E",
            "Rizzo, A",
            "Infante, O",
            "La Stella, T",
            "Escobar, A",
            "Castro, S",
            "Moustakas, M",
            "Bryant, K",
            "Perez, S",
            "Montero, M",
            "Morales, K",
            "Cain, L",
            "Gordon, A",
            "Rios, A",
            "Aoki, N",
            "Coghlan, C",
            "Fowler, D"
        ]
        buttons = {}

        while True:
            dob = self.controller.prompt_question("DOB: ")
            retest = re.match(r"""(\d{1,2})/(\d{1,2})/(\d{4})""", dob)
            if retest:
                dobmonth = int(retest.group(1), base=10)
                dobday = int(retest.group(2), base=10)
                dobyear = int(retest.group(3), base=10)
                break
            else:
                self.controller.set_status("Expected format: MM/DD/YYYY")
                time.sleep(2)
        zipcode = self.controller.prompt_question("Zip: ")

        while True:
            dcap = dict(DesiredCapabilities.PHANTOMJS)
            dcap["phantomjs.page.settings.userAgent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36"
            browser = webdriver.PhantomJS(desired_capabilities=dcap)
            browser.set_window_size(1900, 3000)

            self.controller.set_status("Loading MLB All-Star page")
            browser.get('http://www.mlb.com/mlb/events/all_star/y2015/ballot.jsp')
            self.controller.set_status("Loaded")
            email = self.controller.prompt_question("Email address: ")

            self.controller.set_status("Voting for players")

            for p in players:
                self.controller.set_status("Voting for %s" % p)
                xpath = '//*[text()[.="%s"]]/../../..//span[@class="selectBtn"]' % p
                voted_xpath = '//div[@class="playerSelectedInfo"]/*[text()[.="Hosmer, E"]][@class="playerName"]'
                WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.XPATH, xpath)))
                voting_happened = False
                while not voting_happened:
                    browser.find_element_by_xpath(xpath).click()
                    for i in range(0, 50):
                        try:
                            browser.find_element_by_xpath(voted_xpath)
                            voting_happened = True
                            break
                        except:
                            time.sleep(0.25)

            self.controller.set_status("Clicking vote")
            browser.find_element_by_id("vote-now").click()

            registration = browser.find_element_by_id("register_vote")

            # Fill in e-mail
            self.controller.set_status("Filling out form")
            registration.find_element_by_id("e").send_keys(email)
            webdriver.support.select.Select(registration.find_element_by_id("bd_m")).select_by_value("%s" % dobmonth)
            webdriver.support.select.Select(registration.find_element_by_id("bd_d")).select_by_value("%s" % dobday)
            webdriver.support.select.Select(registration.find_element_by_id("bd_y")).select_by_value("%s" % dobyear)
            registration.find_element_by_id("z").send_keys(zipcode)
            webdriver.support.select.Select(registration.find_element_by_id("ft1")).select_by_value("kc")

            spam = registration.find_element_by_id("on")
            if spam.is_selected():
                spam.click()

            times = 0

            while True:
                xpath = '//input[contains(@id, "v2-") and @name = "v2" and not(ancestor::div[contains(@style, "display: none")])]'
                captcha_xpath = '//input[contains(@id, "v2-") and @name = "v2" and not(ancestor::div[contains(@style, "display: none")])]/../../../..//img'
                captcha = browser.find_element_by_xpath(xpath)
                captcha.click()
                full_captcha = browser.find_element_by_xpath(captcha_xpath)
                loaded = False
                for i in range(0, 50):
                    size = full_captcha.size
                    if size['height'] == 0 or size['width'] == 0:
                        time.sleep(0.25)
                    else:
                        time.sleep(0.25)
                        loaded = True
                        break
                if loaded:
                    location = full_captcha.location
                    scrollX = int(browser.execute_script('return window.scrollX'))
                    scrollY = int(browser.execute_script('return window.scrollY'))
                    left = int(location['x']) - scrollX
                    top = int(location['y']) - scrollY
                    right = left + int(size['width'])
                    bottom = top + int(size['height'])
                    browser.save_screenshot('screenshot.png')

                    im = Image.open('screenshot.png')
                    im = im.crop((left, top, right, bottom))
                    im.save('captcha.gif')

                    res = self.controller.prompt_captcha("captcha.gif")

                    captcha.send_keys(res)
                button = browser.find_element_by_xpath('//a[contains(@id, "vote-now-button") and not(ancestor::div[contains(@style, "display: none")])]')
                browser.execute_script('window.vote_alert_text = ""; window.alert = function(t) { window.vote_alert_text = t };')
                self.controller.set_status("Voting")

                while True:
                    button.click()
                    try:
                        ensure_switched(captcha)
                    except ClickError:
                        continue
                    break