import click

from prefect import config
from prefect.utilities.configuration import set_temporary_config
from prefect.utilities.serialization import from_qualified_name

_agents = {
    "fargate": "prefect.agent.fargate.FargateAgent",
    "local": "prefect.agent.local.LocalAgent",
    "kubernetes": "prefect.agent.kubernetes.KubernetesAgent",
    "nomad": "prefect.agent.nomad.NomadAgent",
}

@click.group(hidden=True)
def agent():
    """
    Manage Prefect agents.

    \b
    Usage:
        $ prefect agent [COMMAND]

    \b
    Arguments:
        start       Start a Prefect agent
        install     Output platform-specific agent installation configs

    \b
    Examples:
        $ prefect agent start
        ...agent begins running in process...

    \b
        $ prefect agent start kubernetes --token MY_TOKEN
        ...agent begins running in process...

    \b
        $ prefect agent install --token MY_TOKEN --namespace metrics
        ...k8s yaml output...
    """
    pass

@agent.command(
    hidden=True,
    context_settings=dict(ignore_unknown_options=True, allow_extra_args=True,),
)
@click.argument("agent-option", default="local")
@click.option(
    "--token", "-t", required=False, help="A Prefect Cloud API token.", hidden=True
)
@click.option(
    "--name",
    "-n",
    required=False,
    help="A name to use for the agent",
    hidden=True,
    default=None,
)
@click.option(
    "--verbose", "-v", is_flag=True, help="Enable verbose agent logs.", hidden=True
)
@click.option(
    "--label",
    "-l",
    multiple=True,
    help="Labels the agent will use to query for flow runs.",
    hidden=True,
)
@click.option("--no-pull", is_flag=True, help="Pull images flag.", hidden=True)
@click.option("--base-url", "-b", help="Docker daemon base URL.", hidden=True)
@click.pass_context
def start(ctx, agent_option, token, name, verbose, label, no_pull, base_url):
    """
    Start an agent.

    \b
    Arguments:
        agent-option    TEXT    The name of an agent to start (e.g. `local`, `kubernetes`, `fargate`, `nomad`)
                                Defaults to `local`

    \b
    Options:
        --token, -t     TEXT    A Prefect Cloud API token with RUNNER scope
        --name, -n      TEXT    A name to use for the agent
        --verbose, -v           Enable verbose agent DEBUG logs
                                Defaults to INFO level logging
        --label, -l     TEXT    Labels the agent will use to query for flow runs
                                Multiple values supported e.g. `-l label1 -l label2`

    \b
    Local Agent Options:
        --base-url, -b  TEXT    A Docker daemon host URL for a LocalAgent
        --no-pull               Pull images for a LocalAgent
                                Defaults to pulling if not provided

    \b
    Fargate Agent Options:
        Any of the configuration options outlined in the docs can be provided here
        https://docs.prefect.io/cloud/agent/fargate.html#configuration
    """

    # Split context
    kwargs = dict()
    for item in ctx.args:
        item = item.replace("--", "")
        kwargs.update([item.split("=")])

    tmp_config = {"cloud.agent.auth_token": token or config.cloud.agent.auth_token}
    if verbose:
        tmp_config["cloud.agent.level"] = "DEBUG"

    with set_temporary_config(tmp_config):
        retrieved_agent = _agents.get(agent_option, None)

        if not retrieved_agent:
            click.secho("{} is not a valid agent".format(agent_option), fg="red")
            return

        _agent = from_qualified_name(retrieved_agent)

        if agent_option == "local":
            from_qualified_name(retrieved_agent)(
                name=name, labels=list(label), base_url=base_url, no_pull=no_pull,
            ).start()
        elif agent_option == "fargate":
            from_qualified_name(retrieved_agent)(
                name=name, labels=list(label), **kwargs
            ).start()
        else:
            from_qualified_name(retrieved_agent)(name=name, labels=list(label)).start()

@agent.command(hidden=True)
@click.argument("name", default="kubernetes")
@click.option(
    "--token", "-t", required=False, help="A Prefect Cloud API token.", hidden=True
)
@click.option(
    "--api", "-a", required=False, help="A Prefect Cloud API URL.", hidden=True
)
@click.option(
    "--namespace",
    "-n",
    required=False,
    help="Agent namespace to launch workloads.",
    hidden=True,
)
@click.option(
    "--image-pull-secrets",
    "-i",
    required=False,
    help="Name of image pull secrets to use for workloads.",
    hidden=True,
)
@click.option(
    "--resource-manager", is_flag=True, help="Enable resource manager.", hidden=True
)
@click.option(
    "--label",
    "-l",
    multiple=True,
    help="Labels the agent will use to query for flow runs.",
    hidden=True,
)
def install(name, token, api, namespace, image_pull_secrets, resource_manager, label):
    """
    Install an agent. Outputs configuration text which can be used to install on various
    platforms. The Prefect image version will default to your local `prefect.__version__`

    \b
    Arguments:
        name                        TEXT    The name of an agent to start (e.g. `kubernetes`)
                                            Defaults to `kubernetes`

    \b
    Options:
        --token, -t                 TEXT    A Prefect Cloud API token
        --api, -a                   TEXT    A Prefect Cloud API URL
        --namespace, -n             TEXT    Agent namespace to launch workloads
        --image-pull-secrets, -i    TEXT    Name of image pull secrets to use for workloads
        --resource-manager                  Enable resource manager on install
        --label, -l                 TEXT    Labels the agent will use to query for flow runs
                                            Multiple values supported e.g. `-l label1 -l label2`
    """

    supported_agents = {"kubernetes": "prefect.agent.kubernetes.KubernetesAgent"}

    retrieved_agent = supported_agents.get(name, None)

    if not retrieved_agent:
        click.secho("{} is not a supported agent for `install`".format(name), fg="red")
        return

    deployment = from_qualified_name(retrieved_agent).generate_deployment_yaml(
        token=token,
        api=api,
        namespace=namespace,
        image_pull_secrets=image_pull_secrets,
        resource_manager_enabled=resource_manager,
        labels=list(label),
    )
    click.echo(deployment)


# Each of the Python sort functions operate on a list of integers and uses a "swap"
# function to exchange the position of two items in a list.

def swap(lyst, original, exchange):
    """Exchanges the items at positions original and exchange"""
    # You could say lyst[original], lyst[exchange]=lyst[exchange], lyst[original]
    # but the following code shows what is really going on
    temp=lyst[original]

    lyst[original]=lyst[exchange]

    lyst[exchange]=temp

def test_swap():
    testList=[69,0,0,0,"x"]
    print(testList)

    first=0
    last=(len(testList)-1)

    swap(testList,first,last)
    print(testList)

def main():
    test_swap()

if __name__=="__main__":
    main()


#!/usr/bin/env python
###############################################################################
 #  Copyright (c) 2015 Tencent Inc.
 #  Distributed under the MIT license
 #  (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 #
 #  Project: Cloud Image Migration Tool
 #  Filename: oss_slave.py
 #  Version: 2.0
 #  Author: Jamis Hoo
 #  E-mail: hoojamis@gmail.com
 #  Date: Sep  7, 2015
 #  Time: 14:29:44
###############################################################################

from __future__ import print_function
from base_slave import BaseSlave
import urlparse
import oss2

class OssSlave(BaseSlave):
    """
    Derived class of BaseSlave.
    Retrieve a resource from Oss and send it along with file id to uploader.

	Attributes:
        mandatory_options: Configuration options required by this class. This is
            a list of tuples each of which contains two strings, section name and
            property name, both of which are case-insensitive.
    """

    mandatory_options = [
        ("oss", "oss.accesskey"),
        ("oss", "oss.secretkey"),
        ("oss", "oss.bucket"),
        ("oss", "oss.endpoint"),
        ("oss", "oss.iscname"),
                        ]
    """
    Attributes:
        uploader_class: uploader class instance
    """
    def __init__(self, config, UploaderClass):
        """
        Initialize base class and uploader class instance.

        Args:
            config: configuration dict
            UploaderClass: uploader class
        """
        super(OssSlave, self).__init__(config)
        self.uploader_class = UploaderClass(config)

    @staticmethod
    def check_config(config):
        """
        Check whether all required options are provided.
        Also check the validity of some options.

        Args:
            config: configuration dict

        Returns:
            Returns string containing error message if there are some errors.
            Returns none otherwise.
        """

        for section, option in OssSlave.mandatory_options:
            if section not in config or option not in config[section]:
                return "Error: Option %s.%s is required. " % (section, option)

        if config["oss"]["oss.iscname"].lower() not in [ "true", "false", "0", "1", "t", "f", "yes", "no", "y", "n" ]:
            return "Error: Invalid oss.oss.iscname. "

    def do_job(self, job):
        """
        Implementation of abstract method.
        Download the file and send the downloaded data along with file id to uploader.

        Args:
            job: a tuple of (index, fileid, old_status, source)
                index: integer, serial number of the job
                fileid: string, file id of the job
                old_status: integer, old status of the job. 0 -- new submitted, 1 -- successful, 2 -- failed
                source: string, source of the job

        Returns:
            log: a tuple of (index, fileid, old_status, new_status, log)
                index: keep the same with that in argument job
                fileid: string, new file id of the job, could be same or different
                    with that in argument
                old_status: keep the same with that in argument
                new_status: integer, new status of the job
                log: log in string

        Raises:
            DO NOT raise any exception in this function.
        """

        access_key = self.config["oss"]["oss.accesskey"]
        secret_key = self.config["oss"]["oss.secretkey"]
        bucket_name = self.config["oss"]["oss.bucket"]
        endpoint = self.config["oss"]["oss.endpoint"]
        is_cname = self.config["oss"]["oss.iscname"].lower() in [ "true", "1", "t", "yes", "y" ]
        if "oss" in self.config and "oss.referer" in self.config["oss"]:
            referer = self.config["oss"]["oss.referer"]
        else:
            referer = None

        auth = oss2.Auth(access_key, secret_key)
        mybucket = oss2.Bucket(auth, endpoint, bucket_name, is_cname)

        serial = job[0]
        fileid = job[1]
        old_status = job[2]

        # read source
        status, log = None, None
        try:
            header=None
            if referer:
                header = {'Referer': referer}

            result = mybucket.get_object(fileid, headers=header)
            src = result.read()
        except Exception as e:
            status = 2
            log = str(e)

        if not status and not log:
            (new_fileid, status, log) = self.uploader_class.upload((fileid, src))
        else:
            new_fileid = fileid

        return (serial, new_fileid, old_status, status, log)


from cerberus import Validator

class TaskValidator:
    schema = {
        'id': {
            'type': 'integer',
            'empty': True,
            'nullable': False
        },
        'description': {
            'type': 'string',
            'empty': False,
            'nullable': False,
            'maxlength': 128
        },
        'finished_at': {
            'type': 'datetime',
            'empty': False,
            'nullable': True
        },
        'is_finished': {
            'type': 'boolean',
            'empty': False,
            'nullable': False
        }
    }

    def __init__(self, data):
        self.validator = Validator()
        self.data = data
        self.schema = self.__class__.schema

    def validate(self):
        return self.validator.validate(self.data, self.schema)

    def errors(self):
        return self.validator.errors


#############################################
from __future__ import print_function
from tkinter import *
import re
import sys
import json
import requests
import intrinio_sdk
from intrinio_sdk.rest import ApiException
import pyowm
import geocoder
import random
from os import path, environ, system
from PIL import Image, ImageTk
from subprocess import run
import face_recognition
import cv2
import numpy as np
import serial
from time import strftime, sleep
#############################################

state = "SLEEP" # SLEEP, RECOG, ACTIVE_NORMAL, ACTIVE_AF
temp, ldr, ir = 0, "L", 0
degree_sign = u'\N{DEGREE SIGN}'

def serial_temp_reader():
    temperature = 0
    while temperature < 15 or temperature > 30:
        try:
            with serial.Serial('/dev/ttyUSB0', 115200, timeout=1) as ser:
                temp, _, _ = ser.readline().decode("utf-8").split(',')
                temperature = float(temp)

        except ValueError:
            pass

        except (serial.SerialException, serial.SerialTimeoutException):
            pass

        except (Warning, Exception) as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(e, exc_type, fname, exc_tb.tb_lineno)

    return temperature

def get_weather(lat, lng):
   owm = pyowm.OWM(environ["PYOWM_API_KEY"])
   observation = owm.weather_at_coords(lat, lng)
   w = observation.get_weather()
   temp = w.get_temperature('celsius')
   humidity = w.get_humidity()
   return humidity, temp['temp']

def get_location():
    g = geocoder.ip('me')
    return g.lat, g.lng, g.address

def get_mails():
    filePath = "/home/team1/Mail/mail"
    if not path.isfile(filePath):
        return ["NO MAILS FOUND"]
    else:
        # Returns Sender, Date, Subject of last 5 emails
        regexstr_sender = r'From: .*<(.*)>'
        regexstr_subject = r'Subject: (.*)'
        with open(filePath, "r") as mail_file:
            text = mail_file.read()
        senders = re.findall(regexstr_sender, text)
        subjects = re.findall(regexstr_subject, text)
        sender_subject = list()
        for sender, subject in zip(senders, subjects):
            sender_subject.append(sender + " : " + subject)
        return sender_subject[-5:]

def NewsFromBBC():
    main_url = " https://newsapi.org/v1/articles?source=bbc-news&sortBy=top&apiKey=" + environ["NEWS_API_KEY"]
    open_bbc_page = requests.get(main_url).json()
    if 'articles' in open_bbc_page:
        articles = open_bbc_page["articles"]
    else:
        articles = []
    result = []
    for article in articles:
        if article is not None:
            result.append(article["title"])
    if len(result) > 5:
        return result[0:5]
    else:
        return result

def get_stonks():
    intrinio_sdk.ApiClient().configuration.api_key['api_key'] = environ["INTRINIO_API_KEY"]
    security_api = intrinio_sdk.SecurityApi()
    identifiers = ['AAPL', 'MSFT', 'GS', 'NKE']
    price_list = list()
    try:
        for identifier in identifiers:
            api_response = security_api.get_security_realtime_price(identifier)
            price_list.append((identifier + " " + str(api_response.ask_price)))
    except ApiException as e:
        print("Exception when calling SecurityApi->get_security_realtime_price: %s\r\n" % e)
    finally:
        return price_list

def getQuote():
    try:
        r = requests.get('https://programming-quotes-api.herokuapp.com/quotes')
        a = json.loads(r.text)
        for i in range(10):
            i = random.randint(0, 250)
            quote = a[i]['en']
            author = a[i]['author']
            if len(quote) < 110:
                return quote, author

    except (Warning, Exception) as e:
        print(e)
        quote = "whomst'd've'ly'yaint'nt'ed'ies's'y'es"
        author = "Team 1"
        return quote, author

#############################################
class Stonks(Frame):
    def __init__(self, master):
        Frame.__init__(self, master, background="BLACK")

        self.stonks = ""
        self.label_stonks = Label(self, font="Times 15", bg="BLACK", fg="WHITE")
        self.label_stonks.pack(side=BOTTOM, anchor="n")

        self.stonksIconLbl = Label(self, font="Times 15", bg="BLACK", fg="WHITE")
        self.stonksIconLbl.pack(side=BOTTOM, anchor="n")
        self.stonks_icon_location = './icons/Stocks.png'

        self.update_stonks()

    def update_stonks(self):
        try:
            x = get_stonks()
            for i in range(len(x)):
                temp = x[i]
                temp1 = '* ' + temp
                x[i] = temp1
            string = '\n'.join(x)
            img = Image.open(self.stonks_icon_location)
            img = img.resize((45, 45), Image.ANTIALIAS)
            img = img.convert('RGB')
            pic = ImageTk.PhotoImage(img)
            self.stonksIconLbl.config(image=pic, bg="black")
            self.stonksIconLbl.image = pic
            self.label_stonks.config(text=string)

        except (Warning, Exception) as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(e, exc_type, fname, exc_tb.tb_lineno)

        finally:
            self.after(60000, self.update_stonks)

class Mail(Frame):
    def __init__(self, master):
        Frame.__init__(self, master, background="BLACK")

        self.mail = ""
        self.label_mail = Label(self, font="Times 15", bg="BLACK", fg="WHITE")
        self.label_mail.pack(side=BOTTOM, anchor="n")

        self.mailIconLbl = Label(self, font="Times 15", bg="BLACK", fg="WHITE")
        self.mailIconLbl.pack(side=BOTTOM, anchor="n")
        self.mail_icon_location = './icons/email.png'

        self.update_mail()

    def update_mail(self):
        try:
            x = get_mails()
            for i in range(len(x)):
                temp = x[i]
                temp1 = '* ' + temp
                x[i] = temp1
            string = '\n'.join(x)
            img = Image.open(self.mail_icon_location)
            img = img.resize((45, 45), Image.ANTIALIAS)
            img = img.convert('RGB')
            pic = ImageTk.PhotoImage(img)
            self.mailIconLbl.config(image=pic, bg="black")
            self.mailIconLbl.image = pic
            self.label_mail.config(text=string)

        except (Warning, Exception) as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(e, exc_type, fname, exc_tb.tb_lineno)

        finally:
            self.after(600000, self.update_mail)

class News(Frame):
    def __init__(self, master):
        Frame.__init__(self, master, background="BLACK")

        self.news = ""
        self.label_news = Label(self, font="Times 15", bg="BLACK", fg="WHITE")
        self.label_news.pack(side=BOTTOM, anchor="n")

        self.newsIconLbl = Label(self, font="Times 15", bg="BLACK", fg="WHITE")
        self.newsIconLbl.pack(side=BOTTOM, anchor="n")
        self.news_icon_location = './icons/news.png'

        self.update_news()

    def update_news(self):
        try:
            x = NewsFromBBC()
            for i in range(len(x)):
                temp = x[i]
                temp1 = '* ' + temp
                x[i] = temp1
            string = '\n'.join(x)
            img = Image.open(self.news_icon_location)
            img = img.resize((45, 45), Image.ANTIALIAS)
            img = img.convert('RGB')
            pic = ImageTk.PhotoImage(img)
            self.newsIconLbl.config(image=pic, bg="black")
            self.newsIconLbl.image = pic
            self.label_news.config(text=string)

        except (Warning, Exception) as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(e, exc_type, fname, exc_tb.tb_lineno)

        finally:
            self.after(600000, self.update_news)

class Time_and_Day(Frame):
    def __init__(self, master):
        Frame.__init__(self, master, background="BLACK")
        self.time1 = ""
        self.label_time = Label(self, font="Times 18", bg="BLACK", fg="WHITE")
        self.label_time.pack(side=TOP, anchor="e")

        self.day1 = ""
        self.label_day = Label(self, font="Times 18", bg="BLACK", fg="WHITE")
        self.label_day.pack(side=TOP, anchor="e")

        self.day_of_the_week1 = ""
        self.label_day_of_the_week = Label(self, font="Times 18", bg="BLACK", fg="WHITE")
        self.label_day_of_the_week.pack(side=TOP, anchor="e")

        self.update_time()

    def update_time(self):
        try:
            time2 = strftime("%I:%M:%S %p")
            day2 =  strftime("%B %d, %Y")
            day_of_the_week2 = strftime("%A")
            if self.time1 != time2:
                self.time1 = time2
                self.label_time.config(text=time2)
            if self.day1 != day2:
                self.day1 = day2
                self.label_day.config(text=day2)
            if self.day_of_the_week1 != day_of_the_week2:
                self.day_of_the_week1 = day_of_the_week2
                self.label_day_of_the_week.config(text=day_of_the_week2)

        except (Warning, Exception) as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(e, exc_type, fname, exc_tb.tb_lineno)

        finally:
            self.after(200, self.update_time)

class WeatherLocation(Frame):
    def __init__(self, master):
        Frame.__init__(self, master, background="BLACK")

        # self.weatherIconLbl = Label(self, font="Times 18", bg="BLACK", fg="WHITE")
        # self.weatherIconLbl.pack(side=TOP, anchor="w")
        # self.icon_location = './icons/weatherIcon.png'

        self.temperature = ""
        self.label_temperature = Label(self, font="Times 18", bg="BLACK", fg="WHITE")
        self.label_temperature.pack(side=TOP, anchor="w")

        self.roomtemp = ""
        self.label_roomtemp = Label(self, font="Times 18", bg="BLACK", fg="WHITE")
        self.label_roomtemp.pack(side=TOP, anchor="w")

        self.humidity= ""
        self.label_humidity = Label(self, font = "Times 18", bg="BLACK", fg="WHITE")
        self.label_humidity.pack(side=TOP, anchor="w")

        self.location = ""
        self.label_location = Label(self, font="Times 18", bg="BLACK", fg="WHITE")
        self.label_location.pack(side=TOP, anchor="w")

        self.update_weatherloc()

    def update_weatherloc(self):
        latitude, longitude, address = get_location()
        self.humidity, self.temperature = get_weather(latitude, longitude)
        self.roomtemp = serial_temp_reader()
        # img = Image.open(self.icon_location)
        # img = img.resize((45, 45), Image.ANTIALIAS)
        # img = img.convert('RGB')
        # pic = ImageTk.PhotoImage(img)
        # self.weatherIconLbl.config(image=pic, bg="black")
        # self.weatherIconLbl.image = pic
        self.label_temperature.config(text="Exterior: " + str(self.temperature) + ' ' + degree_sign + 'C')
        self.label_roomtemp.config(text="Room: " + str(self.roomtemp) + ' ' + degree_sign + 'C')
        self.label_humidity.config(text='Humidity: ' + str(self.humidity) + '%')
        self.label_location.config(text=address)
        self.after(60000, self.update_weatherloc)

class Greeting(Frame):
    def __init__(self, master):
        Frame.__init__(self, master, background="BLACK")
        self.user = ""
        self.greeting_label = Label(self, text=(2 * "\n" + "Log in to continue"), font="Times 43", bg="BLACK", fg="WHITE")
        self.greeting_label.pack()

        self.quote_label =  Label(self, text=(35 * "\n"), font="Times 18", bg="BLACK", fg="WHITE")
        self.quote_label.pack()

        self.author_label = Label(self, text=(5 * "\n"), font="Times 15", bg="BLACK", fg="WHITE")
        self.author_label.pack()

        self.update_user()
        self.update_quote_author()

    def update_user(self):
        try:
            filePath = "/home/team1/Py-UI/user"
            if not path.isfile(filePath):
                self.user = ""
                self.greeting_label.config(text=2 * "\n" + "Log in to continue")
                self.update_quote_author()
            else:
                with open(filePath, "r") as user_file:
                    user = user_file.read().strip()
                    if self.user is not user:
                        self.user = user
                        self.greeting_label.config(text=2 * "\n" + "Welcome, " + self.user)
        except (Warning, Exception) as e:
            print(e)
        finally:
            self.after(200, self.update_user)

    def update_quote_author(self):
        quote, author = getQuote()
        self.quote_label.config(text=35 * "\n" + quote)
        self.author_label.config(text=author + "\n\n\n\n")

class Final:
    def __init__(self, name="User"):
        self.root = Tk()
        self.root.configure(bg="BLACK")
        self.root.attributes("-fullscreen", True)
        self.root.config(cursor="none")
        self.top = Frame(self.root, bg="BLACK")
        self.top.pack(side=TOP, fill=BOTH)
        self.bottom = Frame(self.root, bg="BLACK")
        self.bottom.pack(side=BOTTOM, fill=BOTH)

        self.greeting = Greeting(self.root)

        self.time = Time_and_Day(self.top)
        self.time.pack(side=RIGHT, anchor=N)

        self.weather = WeatherLocation(self.top)
        self.weather.pack(side=LEFT)

        self.news = News(self.bottom)
        self.news.pack(side=LEFT)

        self.mail = Mail(self.bottom)
        self.mail.pack(side=RIGHT)

        self.stonks = Stonks(self.root)

        self.greeting.pack()
        self.stonks.pack()
        system("xrandr --output HDMI-0 --brightness 0.5")

if __name__ == "__main__":
    try:
        print("Running mainloop...")
        start = Final()
        start.root.mainloop()
    except (Warning, Exception ) as e:
        print(e)
    finally:
        system("xrandr --output HDMI-0 --brightness 1")
        sys.exit(1)


import tensorflow as tf

mirrored_strategy = tf.distribute.MirroredStrategy(
    cross_device_ops=tf.distribute.ReductionToOneDevice())
# model
with mirrored_strategy.scope():
    takemodel = EfficientNetB2(weights='imagenet',include_top = False, input_shape = (256, 256, 3))
    takemodel.trainable = True
    # takemodel.summary()

    layer_dict = dict([(layer.name, layer) for layer in takemodel.layers])

    x = layer_dict['top_activation'].output
    print(x)
    x = Conv2D(filters=300, kernel_size=(3, 3), activation='relu')(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    x = Flatten()(x)
    x = Dense(256, activation='relu')(x)
    x = Dropout(0.5)(x)
    x = Dense(16, activation='softmax')(x)

    model = Model(takemodel.input, x)
    model.summary()
    model.compile(optimizer = Adam(1e-4), loss = 'sparse_categorical_crossentropy', metrics = ['acc'])


'''Definition of the Propositional Logic: Formulas and Generalizations'''

import copy
import re
from pylogic import logic

class Formula():
    """Represents a propositional logic formula."""

    def __init__(self, *args):
        """ Constructor of a Formula.

        Could take several arguments, depends of the type of Formula:
            1 argument:
                atomic formula
                  (i.e. propositional letter "P", "Q", ... or costant top "T", or
                  bottom "F")
            2 arguments:
                unary operator negation "!" or "not"
                subformula
            3 arguments:
                binary symbol
                  (i.e. "&", "|", "=>", "<=", "!&", "!|", "!=>", "!<=", "=", "!="
                  or in the extended versions "and", "or", "impl", "implr",
                  "nand", "nor", "nimpl", "nimplr", "eq", "neq")
                subformula
                subformula
        """
        if len(args) == 1:
            letter = args[0]
            regex = re.compile("[A-Z]")
            if not regex.match(letter):
                raise Exception("Wrong formula: " + letter)
            connective = None
            subformula1 = letter
            subformula2 = None
        elif len(args) == 2:
            if args[0] != "not" and args[0] != logic.CONN["not"]:
                raise Exception("Wrong connective: " + args[0])
            if not isinstance(args[1], Formula):
                raise Exception("Wrong formula: " + args[1])
            connective = "not"
            subformula1 = args[1]
            subformula2 = None
        else:
            if args[0] in list(set(logic.CONN.values()) - set("!")):
                connective = [ item[0]
                               for item
                               in list(logic.CONN.items())
                               if item[1] == args[0]
                               ][0]
            elif args[0] in list(set(logic.CONN.keys()) - set("not")):
                connective = args[0]
            else:
                raise Exception("Wrong connective: " + args[0])
            if not isinstance(args[1], Formula):
                raise Exception("Wrong formula: " + args[1])
            if not isinstance(args[2], Formula):
                raise Exception("Wrong formula: " + args[2])
            subformula1 = args[1]
            subformula2 = args[2]

        self.connective = connective
        self.subformula1 = subformula1
        self.subformula2 = subformula2

    def __str__(self):
        if self.connective == None:
            return self.subformula1
        elif self.subformula2 == None:
            return "%s%s" % (logic.CONN[self.connective], str(self.subformula1))
        else:
            return "(%s %s %s)" % (str(self.subformula1), \
                                       logic.CONN[self.connective], \
                                       str(self.subformula2))

    def __eq__(self, other):
        if type(other) != Formula:
            return False
        if self.connective == None and other.connective == None:
            return self.subformula1 == other.subformula1
        else:
            return self.connective == other.connective \
                and self.subformula1 == other.subformula1 \
                and self.subformula2 == other.subformula2

    def __ne__(self, other):
        return not self.__eq__(other)

    def is_alpha(self):
        """Check if the Formula is an alpha formula.
        The notion of alpha formula is defined only for formulas in the form:
        (X o Y) and -(X o Y) where o is a primary connective"""
        if self.connective in logic.CONJ:
            return True
        elif self.connective in logic.DISJ:
            return False
        elif self.connective == "not":
            if self.subformula1.connective in logic.CONJ:
                return False
            elif self.subformula1.connective in logic.DISJ:
                return True
        return None

    def is_beta(self):
        """Check if the Formula is a beta formula.
        The notion of beta formula is defined only for formulas in the form:
        (X o Y) and -(X o Y) where o is a primary connective"""
        if self.connective in logic.DISJ:
            return True
        elif self.connective in logic.CONJ:
            return False
        elif self.connective == "not":
            if self.subformula1.connective in logic.DISJ:
                return False
            elif self.subformula1.connective in logic.CONJ:
                return True
        return None

    def is_literal(self):
        """Check if the formula is a literal,
        namely an atomic formula or the negation of an atomic formula."""
        if self.connective == None:
            return True
        elif self.connective == "not" \
                and self.subformula1.connective == None \
                and self.subformula1.subformula1 != logic.TOP \
                and self.subformula1.subformula1 != logic.BOTTOM:
            return True
        else:
            return False

    def negate(self):
        """Returns the negation of the current Formula"""
        return Formula("not", self)

    def complement(self):
        """Return the complement of the current Formula, namely the negation"""
        if self.connective == None:
            return self.negate()
        if self.connective == "not":
            return self.subformula1
        else:
            return self.negate()

    def components(self):
        """Return a tuple with the copy of the two components of the Formula,
        e.g. if is an alpha formula the alpha_1 and alpha_2.
        """
        if self.connective == None:
            ret = (self, None)
        if self.connective == "not":
            if self.subformula1.subformula2 == None:
                # literal
                ret = (self, None)
            else:
                (comp1, comp2) = self.subformula1.components()
                ret = (comp1.negate(), comp2.negate())
        else:
            if self.connective == "and":
                ret = (self.subformula1, self.subformula2)
            elif self.connective == "or":
                ret = (self.subformula1, self.subformula2)
            elif self.connective == "impl":
                ret = (self.subformula1.negate(), self.subformula2)
            elif self.connective == "implr":
                ret = (self.subformula1, self.subformula2.negate())
            elif self.connective == "nand":
                ret = (self.subformula1.negate(), self.subformula2.negate())
            elif self.connective == "nor":
                ret = (self.subformula1.negate(), self.subformula2.negate())
            elif self.connective == "nimpl":
                ret = (self.subformula1, self.subformula2.negate())
            elif self.connective == "nimplr":
                ret = (self.subformula1.negate(), self.subformula2)

        return copy.deepcopy(ret)

    def nnf(self):
        """Return the current Formula in Negation Normal Form."""
        if self.connective == None:
            return copy.deepcopy(self)
        if self.connective == "not":
            subformula = self.subformula1
            if subformula.connective == "not":
                # !!Z
                return copy.deepcopy(subformula.subformula1).nnf()
            elif subformula.connective == None:
                # litteral
                return copy.deepcopy(self)
            else:
                # dual
                comp1 = copy.deepcopy(subformula.subformula1).negate()
                comp2 = copy.deepcopy(subformula.subformula2).negate()
                return Formula(logic.DUAL[subformula.connective],
                               comp1,
                               comp2
                               ).nnf()
        else:
            return copy.deepcopy(Formula(self.connective, \
                                             self.subformula1.nnf(), \
                                             self.subformula2.nnf()))

    def cnf(self):
        '''Return the current Formula in Conjunctive Normal Form'''
        return Generalization("and", [Generalization("or", [self])]).cnf()

class Generalization():
    """Class that represents a generalized disjunction or conjunction."""

    def __init__(self, connective, formulas):
        """ Constructor of a Generalization.

        Take two arguments:
            connective -- determines the type of Generalization,
                          admitted values "and", "or", "&", "|"
            formulas -- list of the formulas in the Generalization
                        or a Generalization
        """
        if connective != "and"\
                and connective != "or"\
                and connective != logic.CONN["and"]\
                and connective != logic.CONN["or"]:
            raise Exception("Wrong connective: " + connective)
        if  not isinstance(formulas, list):
            raise Exception("Wrong formula")
        for item in formulas:
            if (not isinstance(item, Generalization)) \
                    and (not isinstance(item, Formula)):
                raise Exception("Wrong formula")
        if connective == logic.CONN["and"]:
            connective = "and"
        elif connective == logic.CONN["or"]:
            connective = "or"
        self.connective = connective
        self.list = formulas

    def __str__(self):
        ret = ""
        if self.connective == "and":
            ret = "< "
        elif self.connective == "or":
            ret = "[ "
        first = True
        for elem in self.list:
            if not first:
                ret += " , "
            else:
                first = False
            ret += str(elem)
        if self.connective == "and":
            ret += " >"
        elif self.connective == "or":
            ret += " ]"
        return ret

    def __eq__(self, other):
        return self.connective == other.connective and self.list == other.list

    def __ne__(self, other):
        return not self.__eq__(other)

    def has_non_literal(self):
        """Check if in the list of formulas there are non-literal formulas."""
        if len(self.list) == 0:
            #raise Exception("Empty list of formulas")
            # an empty generalization has a meaning
            # empty clause false, empty dual clause true
            return False
        for item in self.list:
            if isinstance(item, Formula):
                if not item.is_literal():
                    return True
                # else: ignore it
            elif isinstance(item, Generalization):
                if item.has_non_literal():
                    return True
        return False

    def get_non_literal(self):
        """Return a non-literal formula in the generalization.
        None if not present."""
        if len(self.list) == 0:
            return None
        for item in self.list:
            if isinstance(item, Formula):
                if not item.is_literal():
                    return item
                # else: ignore it
            elif isinstance(item, Generalization):
                non_literal = item.get_non_literal()
                if non_literal != None:
                    return non_literal
                # else: ignore it
        return None

    def get_non_literal_position(self):
        """Return the position of a non-literal formula in the generalization.
        None if not present."""
        if len(self.list) == 0:
            return None
        for item in self.list:
            if isinstance(item, Formula):
                if not item.is_literal():
                    return self.list.index(item)
                # else: ignore it
            elif isinstance(item, Generalization):
                non_literal = item.get_non_literal_position()
                if non_literal != None:
                    return non_literal
                # else: ignore it
        return None

    def get_parent_non_literal(self):
        """Find a non-literal formula in the generalization,
        and return a tuple with parent and index of such formula.
        None if not present."""
        if len(self.list) == 0:
            return None
        for item in self.list:
            if isinstance(item, Formula):
                if not item.is_literal():
                    #print "Formula", self, item
                    return (self, self.list.index(item))
                # else: ignore it
            elif isinstance(item, Generalization):
                #print "Generalization"
                non_literal = item.get_parent_non_literal()
                if non_literal != None:
                    return non_literal
                # else: ignore it
        return None

    def remove_every(self, formula):
        """Remove from the list every formula equivalent to the given."""
        self.list = [f for f in self.list
                     if isinstance(f, Generalization) or f != formula]

    def cnf_action(self):
        """Take a clause and return a list of clauses in cnf."""
        if self.connective != "or":
            raise Exception("Wrong type of generalization")

        # basis case
        if not self.has_non_literal():
            return [self]

        # recursive case
        position = self.get_non_literal_position()
        member = self.list[position]

        if member.is_beta():
            (beta1, beta2) = member.components()
            self.list.pop(position)               # remove old
            self.insert(position, [beta1, beta2]) # insert beta1 e beta2
            return self.cnf_action()
        elif member.is_alpha():
            (alpha1, alpha2) = member.components()
            self.list.pop(position)            # remove old
            clause1 = self                     # split
            clause2 = copy.deepcopy(self)      # split
            clause1.insert(position, [alpha1]) # insert alpha1
            clause2.insert(position, [alpha2]) # insert alpha2
            list1 = clause1.cnf_action()       # recursive call
            list2 = clause2.cnf_action()       # recursive call
            list1.extend(list2) # merge
            return list1
        elif member.connective == "not":
            subformula = member.subformula1
            if subformula.connective == "not":
                # !!Z
                self.list[position] = subformula.subformula1
            elif subformula.connective == None:
                if subformula.subformula1 == logic.TOP:
                    # !top
                    self.list[position] = Formula(logic.BOTTOM)
                elif subformula.subformula1 == logic.BOTTOM:
                    # !bottom
                    self.list[position] = Formula(logic.TOP)
            return self.cnf_action()

    def insert(self, index, elements):
        """ Take list of elements and inserts them at the given index."""
        i = index
        for element in elements:
            self.list.insert(i, element)
            i += 1

    def cnf(self):
        """Return the current Generalization in Conjunctive Normal Form"""

        if self.connective != "and"\
                or len(self.list) != 1\
                or self.list[0].connective != "or"\
                or len(self.list[0].list) != 1:
            raise Exception("Wrong type of generalization")

        # < [ ( X | !X ) , () ] , [ ... ] >
        #    conj       < ... >
        #    clause     [ ... ]
        #    member     ( ... )
        #    subformula X, !X

        # breadth-first
        # first beta
        # then alpha

        # deep-first
        # resolve a non literal deeply
        # take a clause with non-literal and return a list of clauses in cnf
        clause = copy.deepcopy(self.list[0])
        return Generalization("and", clause.cnf_action())


import numpy as np
def GreedySearch(SymbolSets, y_probs):
    '''
    SymbolSets: This is the list containing all the symbols i.e. vocabulary (without                   blank)
    y_probs: (# of symbols+1,Seq_length,batch_size). Note that your                batch size for part 1 would always remain 1, but if you plan to use             your implementation for part 2 you need to incorporate batch_size.

    Return the forward probability of greedy path and corresponding compressed symbol       sequence i.e. without blanks and repeated symbols.
    '''

    y_probs = np.swapaxes(y_probs,0,2) # now is (b_size, seq_length, symbols+1)
    y_probs = y_probs[0]# ow is (seq_length, symbols+1)

    seq_len, sym_num = y_probs.shape
    print("seq_len ", seq_len)
    print("sym_num ", sym_num)
    print("before add blank symbolset", SymbolSets)
    SymbolSets.insert(0,"X")

    greedy_seq_symbols = []
    alpha = 1
    for i in range(seq_len):
        greedy_seq_symbols.append("X")

    for i in range(seq_len):
        cur_max = 0
        cur_sym = "X"
        for j in range(sym_num):
            if y_probs[i][j] > cur_max:
                cur_max = y_probs[i][j]
                cur_sym = SymbolSets[j]

        greedy_seq_symbols[i] = cur_sym
        alpha = alpha * cur_max

    compressed_symbol = ""
    pre_symbol = None
    for i in range(seq_len):
        if pre_symbol != None and greedy_seq_symbols[i]==pre_symbol:
            continue

        if greedy_seq_symbols[i]== "X":
        	pre_symbol = None
        	continue

        compressed_symbol += greedy_seq_symbols[i]
        pre_symbol = greedy_seq_symbols[i]

    print("alpha:", alpha)
    print("compressed_symbol:", compressed_symbol)

    greedy_path = alpha

    return compressed_symbol, greedy_path

def BeamSearch(SymbolSets, y_probs, BeamWidth):
	'''
	SymbolSets: This is the list containing all the symbols i.e. vocabulary (without 				  blank)

	y_probs: Numpy array of (# of symbols+1,Seq_length,batch_size). Note that your 			   batch size for part 1 would always remain 1, but if you plan to use 			your implementation for part 2 you need to incorporate batch_size.

	BeamWidth: Width of the beam.

	The function should return the symbol sequence with the best path score (forward 	  probability) and a dictionary of all the final merged paths with their scores.
	'''


from api import db_helper
from dbmonitor import core

if __name__ == "__main__":
    #print(helpers.get_answer())
    entries = core.get_db_stat('C:/Program Files/Microsoft SQL Server/MSSQL12.MSSQLSERVER/MSSQL/DATA/')
    connection = db_helper.get_sqlconnection()
    db_helper.create_table(connection)
    db_helper.insert_record(connection, entries)
    db_helper.close_connection(connection)
    # print(db_helper.get_sqlconnection())
    # print("working")


#!/usr/bin/python
# -*- coding:utf-8 -*-
#author:iuyyoy
#content:Hero class

from __future__ import division, print_function, unicode_literals

#英雄类
class Hero(object):
    status = {
        'SpellDamage':0,
        'Frozen':0,
        'AttackTimes':1,
        'AttackedTimes':0,
        'AttackLevel':0,#用于标记最高被攻击的等级
        }
    def __init__(self, id, name, attack, hp, armor, effect, description, background, img):
        self.id = id
        self.name = name
        self.attack = Attack(attack, attack)
        self.hp = HealthPoint(hp, hp, hp)
        self.armor = Armor(armor, armor)
        self.effect = effect
        self.description = description
        self.background = background
        self.img = img
    ###游戏中的功能
    #收到伤害
    def beHurt(self, point=1):
        isdead = False
        point = self.armor - point
        if point > 0:
            isdead = not(self.hp - point)
        return isdead

    def checkDeath(self):
        return True if self.hp.present <= 0 else False

#生命值
class HealthPoint(object):
    def __init__(self, present, origin, limit, max=9999):
        super(HealthPoint, self).__init__()
        self.present = present
        self.origin = origin
        self.limit = limit
        self.max = max
    #生命值减少
    def __sub__(self, point):
        point = point if point > 0 else -point
        self.present -= point
        return False if self.present < 0 else True

    #生命值增加
    def __add__(self, point):
        if point > 0:
            self.present += point
            self.checkPresentLimit()
            return self.present
#护甲
class Armor(object):
    def __init__(self, present, origin, max=9999):
        super(Armor, self).__init__()
        self.present = present
        self.origin = origin
        self.max = max
    #护甲减少
    def __sub__(self, point):
        point = point if point > 0 else -point
        self.present -= point
        point = self.checkPresentMax()
        return point
    #护甲增加
    def __add__(self, point):
        if point > 0:
            self.present += point
            self.checkPresentMax()
    #检查是否符合极限值
    def checkPresentMax(self):
        point = 0
        if self.present > self.max:
            self.present = self.max
        elif self.present < 0:
            point = -self.present
            self.present = 0
        return point
#攻击
class Attack(object):
    def __init__(self, present, origin, max=9999):
        print("present" + str(present))
        super(Attack, self).__init__()
        self.present = present
        self.origin = origin
        self.max = max


"""
Tests for each of the workflow components try to avoid specific openeye functions.
"""
from typing import Dict, List

import pytest
from openff.toolkit.topology import Molecule
from openff.toolkit.utils.toolkits import OpenEyeToolkitWrapper, RDKitToolkitWrapper

from openff.qcsubmit import workflow_components
from openff.qcsubmit.datasets import ComponentResult
from openff.qcsubmit.exceptions import (
    ComponentRegisterError,
    InvalidWorkflowComponentError,
)
from openff.qcsubmit.utils import check_missing_stereo, get_data
from openff.qcsubmit.validators import check_torsion_connection
from openff.qcsubmit.workflow_components import (
    CustomWorkflowComponent,
    ToolkitValidator,
    deregister_component,
    get_component,
    list_components,
    register_component,
)

def get_container(molecules: [Molecule]) -> ComponentResult:
    """
    Make and return a new molecule container.
    """

    return ComponentResult(
        component_name="intial", component_description={"description": "initial filter"}, molecules=molecules,
        component_provenance={"test": "test component"})

def get_stereoisomers():
    """
    Get a set of molecules that all have some undefined stereochemistry.
    """
    mols = Molecule.from_file(get_data("stereoisomers.smi"), allow_undefined_stereo=True)

    return mols

def get_tautomers():
    """
    Get a set of molecules that all have tautomers
    """

    mols = Molecule.from_file(get_data("tautomers_small.smi"), allow_undefined_stereo=True)

    return mols

def test_list_components():
    """
    Make sure that all registered components are returned.
    """
    components = list_components()
    for component in components:
        assert component.component_name == component.__class__.__name__

def test_register_component_replace():
    """
    Test registering a component that is already registered with and without using replace.
    """
    # get the standard conformer generator
    gen = workflow_components.StandardConformerGenerator(max_conformers=1)

    with pytest.raises(ComponentRegisterError):
        register_component(component=gen, replace=False)

    # now register using replace with a new default
    register_component(component=gen, replace=True)

    gen2 = get_component(gen.component_name)
    assert gen2.max_conformers == gen.max_conformers

    # now return th list back to normal
    register_component(component=workflow_components.StandardConformerGenerator(), replace=True)

def test_register_component_error():
    """
    Make sure an error is raised if we try and register a component that is not a sub class of CustomWorkflowComponent.
    """
    # fake component
    charge_filter = {"component_name": "charge_filter"}

    with pytest.raises(InvalidWorkflowComponentError):
        register_component(component=charge_filter)

@pytest.mark.parametrize("component", [
    pytest.param(workflow_components.SmartsFilter(), id="Class instance"),
    pytest.param("SmartsFilter", id="Class name")
])
def test_deregister_component(component):
    """
    Make sure we can deregister components via name or class.
    """
    # deregister the component
    deregister_component(component=component)

    assert workflow_components.SmartsFilter() not in list_components()

    # now add it back
    register_component(component=workflow_components.SmartsFilter())

def test_deregister_component_error():
    """
    Make sure an error is raised when we try to remove a component that was not registered first.
    """

    with pytest.raises(ComponentRegisterError):
        deregister_component(component="ChargeFilter")

def test_get_component():
    """
    Make sure the correct component is returned when requested.
    """
    gen = get_component("standardconformergenerator")

    assert gen == workflow_components.StandardConformerGenerator()

def test_get_component_error():
    """
    Make sure an error is rasied when we try to get a component that was not registered.
    """
    with pytest.raises(ComponentRegisterError):
        get_component(component_name="ChargeFilter")

def test_custom_component():
    """
    Make sure users can not use custom components unless all method are implemented.
    """

    with pytest.raises(TypeError):
        test = CustomWorkflowComponent()

    class TestComponent(CustomWorkflowComponent):

        component_name = "Test component"
        component_description = "Test component"
        component_fail_message = "Test fail"

        def _apply(self, molecules: List[Molecule]) -> ComponentResult:
            pass

        def provenance(self) -> Dict:
            return {"test": "version1"}

        @staticmethod
        def is_available() -> bool:
            return True

    test = TestComponent()
    assert test.component_name == "Test component"
    assert test.component_description == "Test component"
    assert test.component_fail_message == "Test fail"
    assert {"test": "version1"} == test.provenance()

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_toolkit_mixin(toolkit):
    """
    Make sure the pydantic ToolkitValidator mixin is working correctly, it should provide provenance and toolkit name
    validation.
    """

    toolkit_name, toolkit_class = toolkit
    if toolkit_class.is_available():

        class TestClass(ToolkitValidator, CustomWorkflowComponent):
            """Should not need to implement the provenance."""

            component_name = "ToolkitValidator"
            component_description = "ToolkitValidator test class."
            component_fail_message = "Test fail"

            def _apply(self, molecules: List[Molecule]) -> ComponentResult:
                pass

        test = TestClass()
        with pytest.raises(ValueError):
            test.toolkit = "ambertools"

        test.toolkit = toolkit_name
        prov = test.provenance()
        assert toolkit_name in prov
        assert "openff-toolkit" in prov

    else:
        pytest.skip(f"Toolkit {toolkit_name} not avilable.")

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_standardconformer_generator_validators(toolkit):
    """
    Test the standard conformer generator which calls the OFFTK.
    """

    toolkit_name, toolkit_class = toolkit
    if toolkit_class.is_available():

        conf_gen = workflow_components.StandardConformerGenerator()

        # make sure we are casting to ints
        conf_gen.max_conformers = 1.02
        assert conf_gen.max_conformers == 1

        # test the toolkit validator
        with pytest.raises(ValueError):
            conf_gen.toolkit = "ambertools"
        conf_gen.toolkit = toolkit_name
        assert toolkit_name in conf_gen.provenance()

        conf_gen.clear_existing = "no"
        assert conf_gen.clear_existing is False

        assert "openff-toolkit" in conf_gen.provenance()

    else:
        pytest.skip(f"Toolkit {toolkit} not available.")

def test_element_filter_validators():
    """
    Make sure the element filter validators are working.
    """

    elem_filter = workflow_components.ElementFilter()

    with pytest.raises(KeyError):
        elem_filter.allowed_elements = ["carbon", "hydrogen"]

    elem_filter.allowed_elements = [1.02, 2.02, 3.03]

    assert elem_filter.allowed_elements == [1, 2, 3]

    assert "openmm_elements" in elem_filter.provenance()

def test_weight_filter_validator():
    """
    Make sure the weight filter simple validators work.
    """
    weight = workflow_components.MolecularWeightFilter()

    weight.minimum_weight = 0.0
    assert weight.minimum_weight == 0

    assert "openmm_units" in weight.provenance()
    assert "openff-toolkit" in weight.provenance()

def test_weight_filter_apply():
    """
    Make sure the weight filter returns molecules within the limits.
    """

    weight = workflow_components.MolecularWeightFilter()
    weight.minimum_weight = 0
    weight.maximum_weight = 80

    molecules = get_tautomers()

    result = weight.apply(molecules, processors=1)
    assert result.n_molecules == 14
    assert result.n_filtered == 36

@pytest.mark.parametrize(
    "data",
    [
        pytest.param((workflow_components.ElementFilter, "allowed_elements", [1, 10, 100]), id="ElementFilter"),
        pytest.param((workflow_components.MolecularWeightFilter, "minimum_weight", 1), id="WeightFilter"),
        pytest.param((workflow_components.StandardConformerGenerator, "max_conformers", 1), id="StandardConformers"),
        pytest.param((workflow_components.EnumerateTautomers, "max_tautomers", 2), id="EnumerateTautomers"),
        pytest.param((workflow_components.EnumerateStereoisomers, "undefined_only", True), id="EnumerateStereoisomers"),
        pytest.param((workflow_components.RotorFilter, "maximum_rotors", 3), id="RotorFilter"),
        pytest.param((workflow_components.SmartsFilter, "allowed_substructures", ["[C:1]-[C:2]"]), id="SmartsFilter"),
        pytest.param((workflow_components.WBOFragmenter, "threshold", 0.5), id="WBOFragmenter"),
        pytest.param((workflow_components.EnumerateProtomers, "max_states", 5), id="EnumerateProtomers"),
        pytest.param((workflow_components.RMSDCutoffConformerFilter, "cutoff", 1.2), id="RMSDCutoffConformerFilter")
    ],
)
def test_to_from_object(data):
    """
    Test changing a attribute of the class and making another class by parsing the object, this replicates building
    the workflow from file which is also tested in test_factories.py
    """

    component, attribute, value = data

    active_comp = component()
    # set the attribute
    setattr(active_comp, attribute, value)
    # make a new comp from parsing
    copy_comp = component.parse_obj(active_comp)

    assert copy_comp == active_comp

def test_rmsd_filter():
    """
    Test the RMSD conformer filter method.
    """
    import copy

    from simtk import unit

    rmsd_filter = workflow_components.RMSDCutoffConformerFilter(cutoff=1)
    mol = Molecule.from_smiles("CCCC")
    # make a lot of conformers for the molecule
    mol.generate_conformers(n_conformers=1000, rms_cutoff=0.5 * unit.angstrom, toolkit_registry=RDKitToolkitWrapper())
    ref_mol = copy.deepcopy(mol)
    result = rmsd_filter.apply([mol, ], processors=1)
    # now make sure the number of conformers is different
    assert result.molecules[0].n_conformers != ref_mol.n_conformers

def test_rmsd_filter_no_conformers():
    """
    Make sure the molecule is failed when no conformers are present.
    """
    rmsd_filter = workflow_components.RMSDCutoffConformerFilter(cutoff=1)
    mol = Molecule.from_smiles("CCCC")
    result = rmsd_filter.apply([mol, ], processors=1)
    # now make sure the number of conformers is different
    assert result.n_molecules == 0
    assert result.n_filtered == 1

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_conformer_apply(toolkit):
    """
    Test applying the standard conformer generator to a workflow.
    """

    toolkit_name, toolkit_class = toolkit
    if toolkit_class.is_available():

        conf_gen = workflow_components.StandardConformerGenerator()
        conf_gen.toolkit = toolkit_name
        conf_gen.max_conformers = 1
        conf_gen.clear_existing = True

        mols = get_stereoisomers()
        # remove duplicates from the set
        molecule_container = get_container(mols)

        result = conf_gen.apply(molecule_container.molecules, processors=1)

        assert result.component_name == conf_gen.component_name
        assert result.component_description == conf_gen.dict()
        # make sure each molecule has a conformer that passed
        for molecule in result.molecules:
            assert molecule.n_conformers == 1, print(molecule.conformers)

        for molecule in result.filtered:
            assert molecule.n_conformers == 0

    else:
        pytest.skip(f"Toolkit {toolkit_name} not available.")

def test_elementfilter_apply():
    """
    Test applying the element filter to a workflow.
    """

    elem_filter = workflow_components.ElementFilter()
    elem_filter.allowed_elements = [1, 6, 7, 8]

    mols = get_tautomers()

    result = elem_filter.apply(mols, processors=1)

    assert result.component_name == elem_filter.component_name
    assert result.component_description == elem_filter.dict()
    # make sure there are no unwanted elements in the pass set
    for molecue in result.molecules:
        for atom in molecue.atoms:
            assert atom.atomic_number in elem_filter.allowed_elements

    for molecue in result.filtered:
        elements = set([atom.atomic_number for atom in molecue.atoms])
        assert sorted(elements) != sorted(elem_filter.allowed_elements)

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_enumerating_stereoisomers_validator(toolkit):
    """
    Test the validators in enumerating stereoisomers.
    """

    toolkit_name, toolkit_class = toolkit
    if toolkit_class.is_available():

        enumerate_stereo = workflow_components.EnumerateStereoisomers()
        with pytest.raises(ValueError):
            enumerate_stereo.toolkit = "ambertools"

        enumerate_stereo.toolkit = toolkit_name
        assert toolkit_name in enumerate_stereo.provenance()

        enumerate_stereo.undefined_only = "y"
        assert enumerate_stereo.undefined_only is True

        enumerate_stereo.max_isomers = 1.1
        assert enumerate_stereo.max_isomers == 1

    else:
        pytest.skip(f"Toolkit {toolkit_name} is not available.")

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_enumerating_stereoisomers_apply(toolkit):
    """
    Test the stereoisomer enumeration.
    """

    toolkit_name, toolkit_class = toolkit
    if toolkit_class.is_available():

        enumerate_stereo = workflow_components.EnumerateStereoisomers()
        # set the options
        enumerate_stereo.toolkit = toolkit_name
        enumerate_stereo.undefined_only = True
        enumerate_stereo.rationalise = True

        mols = get_stereoisomers()

        result = enumerate_stereo.apply(mols, processors=1)
        for mol in mols:
            assert mol in result.molecules

        # make sure no molecules have undefined stereo
        for molecule in result.molecules:
            assert Molecule.from_smiles(molecule.to_smiles(), toolkit_registry=RDKitToolkitWrapper()) == molecule
            assert molecule.n_conformers >= 1

    else:
        pytest.skip(f"Toolkit {toolkit_name} is not available.")

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_enumerating_stereoisomers_poor_input(toolkit):
    """
    Test stereoisomer enumeration with an impossible stereochemistry.
    """

    toolkit_name, toolkit_class = toolkit
    if toolkit_class.is_available():
        molecule = Molecule.from_smiles("C=CCn1c([C@@H]2C[C@@H]3CC[C@@H]2O3)nnc1N1CCN(c2ccccc2)CC1")
        enumerate_stereo = workflow_components.EnumerateStereoisomers()
        # the molecule should fail conformer generation
        enumerate_stereo.toolkit = toolkit_name
        enumerate_stereo.undefined_only = True
        enumerate_stereo.rationalise = True

        result = enumerate_stereo.apply(molecules=[molecule, ], processors=1)
        assert result.n_molecules == 0
        assert result.n_filtered == 1

        # now turn of rationalise
        enumerate_stereo.rationalise = False
        result = enumerate_stereo.apply([molecule, ], processors=1)
        assert molecule in result.molecules
        assert result.n_molecules == 1

        # now enumerate all stereo and rationalise
        enumerate_stereo.rationalise = True
        enumerate_stereo.undefined_only = False
        # make sure the input is missing and new isomers are found

        result = enumerate_stereo.apply([molecule, ], processors=1)
        assert molecule not in result.molecules
        assert molecule in result.filtered

    else:
        pytest.skip(f"Toolkit {toolkit_name} is not available.")

@pytest.mark.parametrize("data", [
    pytest.param(("[H]C(=C([H])Cl)Cl", True), id="Molecule with missing stereo"),
    pytest.param(("[H]c1c(c(c(c(c1N([C@@]([H])(O[H])SC([H])([H])[C@]([H])(C(=O)N([H])C([H])([H])C(=O)O[H])N([H])C(=O)C([H])([H])C([H])([H])[C@@]([H])(C(=O)O[H])N([H])[H])O[H])[H])[H])I)[H]", False), id="Molecule with good stereo")
])
def test_check_missing_stereo(data):
    """
    Make sure that molecules with missing stereo chem are correctly identified.
    """
    smiles, result = data
    molecule = Molecule.from_smiles(smiles=smiles, allow_undefined_stereo=True)
    assert result is check_missing_stereo(molecule=molecule)

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_enumerating_tautomers_apply(toolkit):
    """
    Test enumerating tautomers and make sue the input molecule is also returned.
    """

    toolkit_name, toolkit_class = toolkit
    if toolkit_class.is_available():

        enumerate_tauts = workflow_components.EnumerateTautomers()
        enumerate_tauts.toolkit = toolkit_name
        enumerate_tauts.max_tautomers = 2

        mols = get_tautomers()

        result = enumerate_tauts.apply(mols, processors=1)

        # check the input molecule is present
        for mol in mols:
            assert mol in result.molecules

        assert result.n_molecules > len(mols)

    else:
        pytest.skip(f"Toolkit {toolkit_name} is not available.")

@pytest.mark.parametrize(
    "toolkit",
    [
        pytest.param(("openeye", OpenEyeToolkitWrapper), id="openeye"),
        pytest.param(("rdkit", RDKitToolkitWrapper), id="rdkit"),
    ],
)
def test_enumerating_tautomers_validator(toolkit):
    """
    Test the validators in enumerating tautomers.
    """

    toolkit_name, toolkit_class = toolkit

    if toolkit_class.is_available():

        enumerate_tautomers = workflow_components.EnumerateTautomers()

        with pytest.raises(ValueError):
            enumerate_tautomers.toolkit = "ambertools"

        enumerate_tautomers.toolkit = toolkit_name
        enumerate_tautomers.max_tautomers = 1.1
        assert enumerate_tautomers.max_tautomers == 1

        assert toolkit_name in enumerate_tautomers.provenance()

    else:
        pytest.skip(f"Toolkit {toolkit_name} not available.")

def test_enumerating_protomers_apply():
    """
    Test enumerating protomers which is only availabe in openeye.
    """

    enumerate_protomers = workflow_components.EnumerateProtomers(max_states=2)
    assert enumerate_protomers.is_available()

    with pytest.raises(ValueError):
        # make sure rdkit is not allowed here
        enumerate_protomers.toolkit = "rdkit"

    mol = Molecule.from_smiles('Oc2ccc(c1ccncc1)cc2')
    result = enumerate_protomers.apply([mol, ], processors=1)

    assert mol in result.molecules
    # this means that the parent molecule was included
    assert result.n_molecules == 3

def test_coverage_filter():
    """
    Make sure the coverage filter removes the correct molecules.
    """
    from openff.toolkit.typing.engines.smirnoff import ForceField

    coverage_filter = workflow_components.CoverageFilter()
    coverage_filter.allowed_ids = ["b83"]
    coverage_filter.filtered_ids = ["b87"]

    mols = get_stereoisomers()

    # we have to remove duplicated records
    # remove duplicates from the set
    molecule_container = get_container(mols)
    result = coverage_filter.apply(molecule_container.molecules, processors=1)

    forcefield = ForceField("openff_unconstrained-1.0.0.offxml")
    # now see if any molecules do not have b83
    parameters_by_id = {}
    for molecule in result.molecules:
        labels = forcefield.label_molecules(molecule.to_topology())[0]
        covered_types = set(
            [label.id for types in labels.values() for label in types.values()]
        )
        # now store the smiles under the ids
        for parameter in covered_types:
            parameters_by_id.setdefault(parameter, []).append(molecule.to_smiles())

    expected = parameters_by_id["b83"]
    for molecule in result.molecules:
        assert molecule.to_smiles() in expected
        assert "dihedrals" not in molecule.properties

    # we now need to check that the molecules passed contain only the allowed atoms
    # do this by running the component again
    result2 = coverage_filter.apply(result.molecules, processors=1)
    assert result2.n_filtered == 0
    assert result.n_molecules == result.n_molecules

def test_coverage_filter_tag_dihedrals():
    """
    Make sure the coverage filter tags dihedrals that we request.
    """

    coverage_filter = workflow_components.CoverageFilter()
    coverage_filter.allowed_ids = ["t1"]
    coverage_filter.tag_dihedrals = True

    mols = get_tautomers()

    # we have to remove duplicated records
    # remove duplicates from the set
    molecule_container = get_container(mols)

    result = coverage_filter.apply(molecule_container.molecules, processors=1)

    for molecule in result.molecules:
        assert "dihedrals" in molecule.properties
        torsion_indexer = molecule.properties["dihedrals"]
        assert torsion_indexer.n_torsions > 0, print(molecule)
        assert torsion_indexer.n_double_torsions == 0
        assert torsion_indexer.n_impropers == 0

def test_fragmentation_settings():
    """
    Make sure the settings are correctly handled.
    """

    fragmenter = workflow_components.WBOFragmenter()
    with pytest.raises(ValueError):
        fragmenter.functional_groups = get_data("functional_groups_error.yaml")

    fragmenter.functional_groups = get_data("functional_groups.yaml")

    assert fragmenter.functional_groups is not None

def test_fragmentation_apply():
    """
    Make sure that fragmentation is working.
    """
    fragmenter = workflow_components.WBOFragmenter()
    assert fragmenter.is_available()
    # check that a molecule with no rotatable bonds fails if we dont want the parent back
    benzene = Molecule.from_file(get_data("benzene.sdf"), "sdf")
    result = fragmenter.apply([benzene, ], processors=1)
    assert result.n_molecules == 0

    # now try ethanol
    ethanol = Molecule.from_file(get_data("methanol.sdf"), "sdf")
    fragmenter.include_parent = True
    result = fragmenter.apply([ethanol, ], processors=1)
    assert result.n_molecules == 1

    # now try a molecule which should give fragments
    diphenhydramine = Molecule.from_smiles("O(CCN(C)C)C(c1ccccc1)c2ccccc2")
    fragmenter.include_parent = False
    result = fragmenter.apply([diphenhydramine, ], processors=1)
    assert result.n_molecules == 4
    for molecule in result.molecules:
        assert "dihedrals" in molecule.properties

def test_rotor_filter_pass():
    """
    Make sure the rotor filter removes the correct molecules.
    """

    rotor_filter = workflow_components.RotorFilter()
    rotor_filter.maximum_rotors = 3

    mols = get_tautomers()

    # we have to remove duplicated records
    molecule_container = get_container(mols)
    result = rotor_filter.apply(molecule_container.molecules, processors=1)
    for molecule in result.molecules:
        assert len(molecule.find_rotatable_bonds()) <= rotor_filter.maximum_rotors

def test_rotor_filter_fail():
    """
    Test filtering out molecules with too many rotatable bonds.
    """

    rotor_filter = workflow_components.RotorFilter()
    rotor_filter.maximum_rotors = 1

    mols = get_tautomers()

    molecule_container = get_container(mols)
    result = rotor_filter.apply(molecule_container.molecules, processors=1)
    for molecule in result.molecules:
        assert len(molecule.find_rotatable_bonds()) <= rotor_filter.maximum_rotors
    for molecule in result.filtered:
        assert len(molecule.find_rotatable_bonds()) > rotor_filter.maximum_rotors

def test_smarts_filter_validator():
    """
    Make sure the validator is checking the allowed and filtered fields have valid smirks strings.
    """

    from openff.toolkit.typing.chemistry import SMIRKSParsingError

    filter = workflow_components.SmartsFilter()

    with pytest.raises(SMIRKSParsingError):
        filter.allowed_substructures = [1, 2, 3, 4]

    with pytest.raises(SMIRKSParsingError):
        # bad string
        filter.allowed_substructures = ["fkebfsjb"]

    with pytest.raises(SMIRKSParsingError):
        # make sure each item is checked
        filter.allowed_substructures = ["[C:1]-[C:2]", "ksbfsb"]

    with pytest.raises(SMIRKSParsingError):
        # good smarts with no tagged atoms.
        filter.allowed_substructures = ["[C]=[C]"]

    # a good search string
    filter.allowed_substructures = ["[C:1]=[C:2]"]
    assert len(filter.allowed_substructures) == 1

def test_smarts_filter_apply_parameters():
    """
    Make sure the environment filter is correctly identifying substructures.
    """

    filter = workflow_components.SmartsFilter()

    # this should only allow C, H, N, O containing molecules through similar to the element filter
    filter.allowed_substructures = ["[C:1]", "[c:1]", "[H:1]", "[O:1]", "[N:1]"]
    filter.filtered_substructures = ["[Cl:1]", "[F:1]", "[P:1]", "[Br:1]", "[S:1]", "[I:1]", "[B:1]"]
    allowed_elements = [1, 6, 7, 8]

    molecules = get_tautomers()

    result = filter.apply(molecules, processors=1)

    assert result.component_name == filter.component_name
    assert result.component_description == filter.dict()
    # make sure there are no unwanted elements in the pass set
    for molecule in result.molecules:
        for atom in molecule.atoms:
            assert atom.atomic_number in allowed_elements, print(molecule)

    for molecule in result.filtered:
        elements = set([atom.atomic_number for atom in molecule.atoms])
        assert sorted(elements) != sorted(allowed_elements)

def test_smarts_filter_apply_none():
    """
    Make sure we get the expected behaviour when we supply None as the filter list.
    """

    filter = workflow_components.SmartsFilter()

    filter.allowed_substructures = None

    molecules = get_tautomers()

    # this should allow all molecules through
    result = filter.apply(molecules=molecules, processors=1)

    assert len(result.molecules) == len(molecules)

    # now filter the molecule set again removing aromatic carbons
    filter.filtered_substructures = ["[c:1]"]

    result2 = filter.apply(molecules=result.molecules, processors=1)

    assert len(result2.molecules) != len(result.molecules)

@pytest.mark.parametrize("tag_dihedrals", [
    pytest.param(True, id="Tag dihedrals"),
    pytest.param(False, id="Do not tag Dihedrals")
])
def test_smarts_filter_apply_tag_torsions(tag_dihedrals):
    """
    Make sure that torsions in molecules are tagged if we supply a torsion smarts a pattern.
    """
    filter = workflow_components.SmartsFilter(tag_dihedrals=tag_dihedrals)

    # look for methyl torsions here
    filter.allowed_substructures = ["[*:1]-[*:2]-[#6H3:3]-[#1:4]"]

    molecules = get_tautomers()
    # this should filter and tag the dihedrals
    result = filter.apply(molecules, processors=1)
    for molecule in result.molecules:
        if tag_dihedrals:
            assert "dihedrals" in molecule.properties
            # make sure the torsion is connected
            torsions = molecule.properties["dihedrals"]
            for torsion in torsions.get_dihedrals:
                _ = check_torsion_connection(torsion=torsion.torsion1, molecule=molecule)
        else:
            assert "dihedrals" not in molecule.properties


# -*- coding:utf-8 -*-
from mako import runtime, filters, cache
UNDEFINED = runtime.UNDEFINED
STOP_RENDERING = runtime.STOP_RENDERING
__M_dict_builtin = dict
__M_locals_builtin = locals
_magic_number = 10
_modified_time = 1466476630.574
_enable_loop = True
_template_filename = u'C:/workspace/python/web.py-skeleton/skeleton/www/app/views/_base.html'
_template_uri = u'_base.html'
_source_encoding = 'utf-8'
_exports = []

def render_body(context,**pageargs):
    __M_caller = context.caller_stack._push_frame()
    try:
        __M_locals = __M_dict_builtin(pageargs=pageargs)
        self = context.get('self', UNDEFINED)
        title = context.get('title', UNDEFINED)
        __M_writer = context.writer()
        __M_writer(u'<!DOCTYPE html>\r\n\r\n\r\n  <meta charset="utf-8">\r\n  <title>')
        __M_writer(filters.decode.utf8(title))
        __M_writer(u'</title>\r\n  <link rel="stylesheet" href="/static/css/style.css" />\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
')
        __M_writer(filters.decode.utf8(self.container()))
        __M_writer(u'
\r\n\r\n\r\n\r\n\r\n')
        return ''
    finally:
        context.caller_stack._pop_frame()

"""
__M_BEGIN_METADATA
{"source_encoding": "utf-8", "line_map": {"33": 27, "16": 0, "23": 1, "24": 5, "25": 5, "26": 14, "27": 14}, "uri": "_base.html", "filename": "C:/workspace/python/web.py-skeleton/skeleton/www/app/views/_base.html"}
__M_END_METADATA
"""


'''
words
'''

# packages
from copy import deepcopy

# scripts
from mutate import MutateB
from mate import WholeMateOnly
from evaluate import StandardEvaluate
from operators import SymbRegressionNoArgs
from arguments import NoArgs
from shape import ShapeA
from genetic_definition import BlockDefinition, IndividualDefinition
from genetic_material import IndividualMaterial

block_def1 = BlockDefinition("preprocessor",
							ShapeA(),
							MutateB(),
							WholeMateOnly(),
							StandardEvaluate(),
							SymbRegressionNoArgs(),
							NoArgs())

POP_SIZE = 1
individual_def = IndividualDefinition([block_def1])
ind = IndividualMaterial(individual_def)
#mut = deepcopy(ind)
#individual_def.mutate(mut)
muts = individual_def.mutate(ind)

pop = [ind]+muts
for j, person in enumerate(muts):
	print("MUTANT %i" % j)
	for i, (onode, mnode) in enumerate(zip(ind[0].genome,person[0].genome)):
		if onode != mnode:
			if i in ind[0].active_nodes:
				print(i, "active node")
			else:
				print(i, "node")
			print(onode)
			print(mnode)

	for i, (onode, mnode) in enumerate(zip(ind[0].args,person[0].args)):
		if onode != mnode:
			if i in ind[0].active_args:
				print(i, "active arg")
			else:
				print(i, "arg")
			print(onode)
			print(mnode)

	print("")

print("try mating")
offspring = individual_def.mate(muts[0],muts[1])

offspring[1][0].genome = muts[0][0].genome


import boto3
import json
import os
import time
import sys

import logging
import zipfile
try:
    import zlib
    compression = zipfile.ZIP_DEFLATED
except:
    compression = zipfile.ZIP_STORED

from io import BytesIO

from eval_kit.extract_frames import extract_frames

# EVALUATION SYSTEM SETTINGS
# DON'T CHANGE ANY CODE HERE, OR YOU MAY ENCOUNTER SOME UNEXPECTED PROBLEMS!

WORKSPACE_BUCKET = 'deeperforensics-eval-workspace'
VIDEO_LIST_PATH = 'test-data/deeperforensicis_runtime_eval_video_list.txt'
VIDEO_PREFIX = 'test-data/'
UPLOAD_PREFIX = 'test-output/'
TMP_PATH = '/tmp'

def _get_s3_video_list(s3_bucket, s3_path):
    s3_client = boto3.client('s3', region_name='us-west-2')
    f = BytesIO()
    s3_client.download_fileobj(s3_bucket, s3_path, f)
    lines = f.getvalue().decode('utf-8').split('\n')
    return [x.strip() for x in lines if x != '']

def _download_s3_video(s3_bucket, s3_path, filename):
    s3_client = boto3.client('s3', region_name='us-west-2')
    local_path = os.path.join(TMP_PATH, filename)
    s3_client.download_file(s3_bucket, s3_path, local_path)

def _upload_output_to_s3(data, filename, s3_bucket, s3_prefix):
    s3_client = boto3.client('s3', region_name='us-west-2')
    local_path = os.path.join(TMP_PATH, filename)
    s3_path = os.path.join(s3_prefix, filename)

    # Put data into binary file
    data_str = json.dumps(data)
    encode_data = data_str.encode()
    with open(local_path, 'wb') as f:
        f.write(encode_data)
    s3_client.upload_file(local_path, s3_bucket, s3_path)

def get_job_name():
    return os.environ['DEEPERFORENSICS_EVAL_JOB_NAME']

def upload_eval_output(output_probs, output_times, num_frames, job_name, total_time):
    """
    This function uploads the testing output to S3 to trigger evaluation.

    params:
    - output_probs (dict): dict of probability of every video
    - output_times (dict): dict of processing time of every video
    - num_frames (dict): dict of number of frames extracting from every video
    - job_name (str)

    """
    upload_data = {
        i: {
            "prob": output_probs[i],
            "runtime": output_times[i],
            "num_frames": num_frames[i]
        } for i in output_probs
    }

    upload_data["total_time"] = total_time

    filename = '{}.bin'.format(job_name)

    _upload_output_to_s3(upload_data, filename, WORKSPACE_BUCKET, UPLOAD_PREFIX)

    logging.info("output uploaded to {}{}".format(UPLOAD_PREFIX, filename))

def get_frames_iter():
    """
    This function returns a iterator of frames of test videos.
    Each iteration provides a tuple of (video_id, frames), each frame will be in RGB color format with array shape of (height, width, 3).

    return: tuple(video_id: str, frames: list)
    """
    video_list = _get_s3_video_list(WORKSPACE_BUCKET, VIDEO_LIST_PATH)
    logging.info("got video list, {} videos".format(len(video_list)))

    for video_id in video_list:
        # get video from s3
        st = time.time()
        try:
            _download_s3_video(WORKSPACE_BUCKET, os.path.join(VIDEO_PREFIX, video_id), video_id)
        except:
            logging.info("Failed to download video: {}".format(os.path.join(VIDEO_PREFIX, video_id)))
            raise
        video_local_path = os.path.join(TMP_PATH, video_id) # local path of the video named video_id
        frames = extract_frames(video_local_path)
        elapsed = time.time() - st
        logging.info("video downloading & frames extracting time: {}".format(elapsed))
        yield video_id, frames
        try:
            os.remove(video_local_path) # remove the video named video_id
        except:
            logging.info("Failed to delete this video, error: {}".format(sys.exc_info()[0]))

def get_local_frames_iter(max_number=None):
    """
    This function returns a iterator of frames of test videos.
    It is used for local test of participating algorithms.
    Each iteration provides a tuple of (video_id, frames), each frame will be in RGB color format with array shape of (height, width, 3)

    return: tuple(video_id: str, frames: list)
    """
    video_list = [x.strip() for x in open(VIDEO_LIST_PATH)]
    logging.info("got local video list, {} videos".format(len(video_list)))

    for video_id in video_list:
        # get video from local file
        try:
            frames = extract_frames(os.path.join(VIDEO_PREFIX, video_id))
        except:
            logging.info("Failed to read image: {}".format(os.path.join(VIDEO_PREFIX, video_id)))
            raise
        yield video_id, frames

def verify_local_output(output_probs, output_times, num_frames):
    """
    This function prints the ground truth and prediction for the participant to verify, calculates average FPS.

    params:
    - output_probs (dict): dict of probability of every video
    - output_times (dict): dict of processing time of every video
    - num_frames (dict): dict of number of frames extracting from every video
    """
    # gts = json.load(open('test-data/local_test_groundtruth.json'), parse_int=float)
    gts = json.load(open('test-data/local_test_groundtruth.json'))

    all_time = 0
    all_num_frames = 0
    for k in gts:

        assert k in output_probs and k in output_times, ValueError("The detector doesn't work on video {}".format(k))

        all_time += output_times[k]
        all_num_frames += num_frames[k]

        logging.info("Video ID: {}, Runtime: {}".format(k, output_times[k]))
        logging.info("\tgt: {}".format(gts[k]))
        logging.info("\toutput probability: {:.4f}".format(output_probs[k]))
        logging.info("\tnumber of frame: {}".format(num_frames[k]))
        logging.info("\toutput time: {}".format(output_times[k]))

        logging.info(" ")

    average_fps = all_num_frames / all_time
    logging.info("Done. Average FPS: {:.03f}".format(average_fps))


import sys
from PyQt5 import QtCore, QtGui, uic
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QMessageBox
from PyQt5.QtWidgets import QFileDialog, QAction, qApp, QTreeWidgetItem, QDialog
from PyQt5.QtGui import QIcon
from ui import ui_window
from ui import add
# import pygame
import Wave_play
import time
from test import Test
import threading

class MainWindow(ui_window.Ui_MainWindow, QMainWindow):
    def __init__(self, port):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        self.pop = PopWindow()

        self.play = False
        self.music = 0
        self.song = 0
        self.progerss = 0
        self.songs = []

        self.duration = 0
        self.t = TimeControl(self.duration, self.updateProgressBar)
        self.musicSlider.setMinimum(0)
        self.musicSlider.setMaximum(1000)

        self.initButton()
        # self.list_view.hide()

        self.data = Test(port)

        self.view_controller = [self.album_view, self.list_view, self.fav_view, self.song_view]
        self.tab_controller = [self.btnMusic, self.btnFavorite]
        self.btnAlbum.hide()

        self.tab_highlight_style = "QPushButton {font: Bold 15pt \"Arial\";color: rgb(250, 220, 62);text-decoration: underline;background-color: rgba(255, 255, 255, 0);}"
        self.tab_default_style = "QPushButton {font: Bold 15pt \"Arial\";color: rgb(255, 255, 255);background-color: rgba(255, 255, 255, 0);}"

        self.showView(self.list_view)
        self.highlightTab(self.btnMusic)
        self.initWindow()

    def initButton(self):
        self.btnSearch.clicked.connect(self.searchButton_callback)

        # self.btnAlbum.clicked.connect(self.albumButton_callback)
        self.btnMusic.clicked.connect(self.musicButton_callback)
        self.btnFavorite.clicked.connect(self.favoriteButton_callback)
        self.btnNet.clicked.connect(self.netButton_callback)

        self.btnLast.clicked.connect(self.lastButton_callback)
        self.btnPlay.clicked.connect(self.playButton_callback)
        self.btnNext.clicked.connect(self.nextButton_callback)
        # self.btnVol.clicked.connect(self.volButton_callback)

        self.addFav.clicked.connect(self.addFavButton_callback)
        self.treeWidget.itemDoubleClicked['QTreeWidgetItem*','int'].connect(self.tree1_callback)
        self.fav_treeWidget.itemDoubleClicked['QTreeWidgetItem*','int'].connect(self.tree1_callback)

    def initWindow(self):
        self.showView(self.list_view)
        self.highlightTab(self.btnMusic)
        songs = self.data.displaySong()
        self.songs = songs
        self.treeWidget.clear()
        for song in songs:
            # print(song)
            item = QTreeWidgetItem(self.treeWidget)
            for i in range(4):
                item.setText(i, str(song[i]))

    def searchButton_callback(self):
        string = self.lineEdit.text()
        songs = self.data.selectSong(string)
        self.treeWidget.clear()
        item = QTreeWidgetItem(self.treeWidget)
        for song in songs:
            for i in range(4):
                item.setText(i, song[i])

    def addFavButton_callback(self):
        if not self.song == 0:
            # print(self.data.getFav(self.song))
            if self.data.getFav(self.song) == 0:
                self.data.setFav(self.song ,1)
                self.addFav.setStyleSheet("border-image: url(D:/Y3CUHK/T2/CSCI3280/Project/pyqt/finally/ui/images/xin.png)")
            else:
                # print("13"
                self.data.setFav(self.song, 0)
                self.addFav.setStyleSheet("border-image: url(D:/Y3CUHK/T2/CSCI3280/Project/pyqt/finally/ui/images/kongxin.png)")

    def musicButton_callback(self):
        self.showView(self.list_view)
        self.highlightTab(self.btnMusic)
        songs = self.data.displaySong()
        self.songs = songs
        self.treeWidget.clear()
        for song in songs:
            # print(song)
            item = QTreeWidgetItem(self.treeWidget)
            for i in range(4):
                item.setText(i, str(song[i]))

    def favoriteButton_callback(self):
        self.showView(self.fav_view)
        self.highlightTab(self.btnFavorite)
        favoriteSongs = self.data.getFavSongs()
        self.songs = favoriteSongs
        self.fav_treeWidget.clear()
        for song in favoriteSongs:
            item = QTreeWidgetItem(self.fav_treeWidget)
            for i in range(4):
                item.setText(i, str(song[i]))

    def netButton_callback(self):
        # self.pop.show()
        self.pop.exec()
        if self.pop.tab == 1:
            ip_addr = self.pop.ip_addr
            port = self.pop.port
            if not ip_addr == '' and not port == '':
                self.data.setClient(ip_addr, int(port))
                # self.data.clientStart()
                print("Connected to " + ip_addr + ' ! ' + port)
                songs = self.data.displaySong()
                self.songs = songs
                self.treeWidget.clear()
                for song in songs:
                    # print(song)
                    item = QTreeWidgetItem(self.treeWidget)
                    for i in range(4):
                        item.setText(i, str(song[i]))

        elif self.pop.tab == 2:
            filename = self.pop.filename
            song_name = self.pop.song.text()
            album_name = self.pop.album.text()
            singer_name = self.pop.singer.text()
            # print("albumfile:"+)
            albumfile =  self.pop.input_artwork.text()
            lrcfile = self.pop.input_lyrics.text()
            self.data.addSong(song_name, album_name, singer_name, 0, filename, lrcfile, albumfile)
            songs = self.data.displaySong()
            self.songs = songs
            self.treeWidget.clear()
            for song in songs:
                # print(song)
                item = QTreeWidgetItem(self.treeWidget)
                for i in range(4):
                    item.setText(i, str(song[i]))

    def lastButton_callback(self):
        numOfSongs = len(self.songs)

        for i in range(numOfSongs):

            if self.songs[i][0] == self.song:

                self.music.stop()
                self.showView(self.song_view)
                self.highlightTab(None)

                self.playMusic(self.songs[(i-1)%numOfSongs][0])

                break

    def playButton_callback(self):
        if not self.play:
            if self.music != 0:
                self.t.play()
                self.play = True
                self.music.resume()
                self.btnPlay.setStyleSheet(
                    "QPushButton {border-image: url(D:/Y3CUHK/T2/CSCI3280/Project/pyqt/finally/ui/images/pause.png);}")
        else:
            self.t.pause()
            self.play = False
            self.btnPlay.setStyleSheet(
                "QPushButton {border-image: url(D:/Y3CUHK/T2/CSCI3280/Project/pyqt/finally/ui/images/bofang.png);}")
            self.music.pause()

    def nextButton_callback(self):
        numOfSongs = len(self.songs)

        for i in range(numOfSongs):

            if self.songs[i][0] == self.song:

                self.music.stop()
                self.showView(self.song_view)
                self.highlightTab(None)

                self.playMusic(self.songs[(i+1)%numOfSongs][0])

                break

    def tree1_callback(self, item, column_no):
        self.showView(self.song_view)
        self.highlightTab(None)

        song = item.text(0)
        if self.song != song and self.music != 0:
            self.music.stop()
            self.music = 0

        if self.music == 0:
            # ip_addr = '0'
            ip_addr = self.data.getIpAddress(song)
            print(song, ip_addr)
            if ip_addr == 0:
                print(song)
                minute, second = item.text(3).split(':')
                self.duration = int(minute)*60 + int(second)
                self.t = TimeControl(self.duration, self.updateProgressBar)
                self.t.setDuration(self.duration)
                self.t.play()

                self.playMusic(song)
            else:

                self.data.getSong(song)
                time.sleep(1)
                self.playMusic(song)
                fileName = self.data.getFilename(song)
                lrcName = self.data.getLRCFilename(song)

    def playMusic(self, song):
        if self.data.getFav(song) == 0:
            self.addFav.setStyleSheet("border-image: url(D:/Y3CUHK/T2/CSCI3280/Project/pyqt/finally/ui/images/kongxin.png)")
        else:
            self.addFav.setStyleSheet("border-image: url(D:/Y3CUHK/T2/CSCI3280/Project/pyqt/finally/ui/images/xin.png)")

        self.song = song
        self.play = True
        fileName = self.data.getFilename(song)
        lrcName = self.data.getLRCFilename(song)
        imagePath = self.data.getAlbumFilename(song)
        singer = self.data.getSinger(song)
        # lrcName = ''
        self.musicSlider.setValue(0)
        self.music = Wave_play.Wave_Player(fileName, lrcName)

        self.alubum_artwork.setStyleSheet("border-image: url(./data/" + imagePath + ");")
        self.label_2.setText(song+"\n"+singer)
        self.btnPlay.setStyleSheet("border-image: url(D:/Y3CUHK/T2/CSCI3280/Project/pyqt/finally/ui/images/pause.png);")

        thread = threading.Thread(target = self.displayLrc)
        thread.start()

    def displayLrc(self):
        last = ""
        self.label.setWordWrap(True)
        while 1:
            with open('temp.txt','r') as f:

                line = f.readline()

                # print(line)
                if last != line:
                    self.label.setText(line)

                last = line

    def showView(self, view):
        for x in self.view_controller:
            x.hide()
        view.show()

    def highlightTab(self, tab):
        for x in self.tab_controller:
            x.setStyleSheet(self.tab_default_style)
        if tab != None:
            tab.setStyleSheet(self.tab_highlight_style)
            self.addFav.hide()
        else:
            self.addFav.show()

    def closeEvent(self, event):
        if (self.music != 0):
            self.music.pause()
            self.t.pause()
        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            if (self.music != 0):
                self.music.stop()
            event.accept()
        else:
            if (self.music != 0):
                self.music.resume()
            event.ignore()

    def updateProgressBar(self, value):
        value = round(round(time.time() * 1) - value)
        # print(value, end=' ')
        value = int(value * 1000 // self.duration)
        # print(value)
        self.musicSlider.setValue(value)

class PopWindow(add.Ui_Dialog, QDialog):
    # def __init__(self, port):
    def __init__(self):
        super(PopWindow, self).__init__()
        self.setupUi(self)
        self.connect_btnbox.accepted.connect(self.connect_acc)
        self.connect_btnbox.rejected.connect(self.rej)
        self.add_file_btnbox.accepted.connect(self.add_file_acc)
        self.add_file_btnbox.rejected.connect(self.rej)

        self.select_file_btn.clicked.connect(self.select_file)
        self.select_artwork_btn.clicked.connect(self.select_artwork)
        self.select_lyrics_btn.clicked.connect(self.select_lyrics)

        self.ip_addr = ""
        self.port = ""
        self.tab = 0

        self.filename = ""
        self.artwork_filename = ""
        self.lyrics_filename = ""

    def connect_acc(self):
        self.ip_addr = self.lineEdit.text()
        self.port = self.lineEdit_2.text()
        self.tab = 1
        self.close()

    def add_file_acc(self):
        self.tab = 2
        self.close()

    def select_file(self):
        self.filename, _ = QFileDialog.getOpenFileName(None, 'Open File', "","Wav files (*.wav)", options=QFileDialog.DontUseNativeDialog)
        # print(self.filename)
        self.input_file.setText(self.filename)

    def select_artwork(self):
        self.artwork_filename, _ = QFileDialog.getOpenFileName(None, 'Open File', "","Image Files (*.png *.jpg *.bmp)", options=QFileDialog.DontUseNativeDialog)
        self.input_artwork.setText(self.artwork_filename)
        # print("artword filename:" + self.artwork_filename)

    def select_lyrics(self):
        self.lyrics_filename, _ = QFileDialog.getOpenFileName(None, 'Open File', "","Lyrics Files (*.lrc)", options=QFileDialog.DontUseNativeDialog)
        self.input_lyrics.setText(self.lyrics_filename)
        # print("lrc filename:"+self.lyrics_filename)

    def rej(self):
        self.close()

class TimeControl:

    def __init__(self, duration, fn):
        self.startTime = 0
        self.duration = duration
        self.pauseTime = 0
        self.fn = fn
        self.timer = []

    def setDuration(self, duration):
        self.duration = duration

    def play(self):
        self.startTime = round(time.time() * 1)
        self.timer = [threading.Timer((i+1)/1, self.fn, [self.startTime - self.pauseTime]) for i in range(self.duration - self.pauseTime)]
        for i in range(self.duration - self.pauseTime):
            self.timer[i].start()

    def pause(self):
        for i in range(self.duration - self.pauseTime):
            self.timer[i].cancel()
        self.pauseTime = round(round(time.time() * 1) - self.startTime + self.pauseTime)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    port = sys.argv[1]
    window = MainWindow(int(port))
    window.show()
    app.exec_()
    sys.exit(window.t.pause())