import json
import matplotlib.pyplot as plt # type: ignore
from simplega import gaconfig
from simplega import boothengine

# plots the fitness over all generations using matplotlib.
def fitness_plot_stats(avg_fitness_plot, best_fitness_plot, title):
        if len(avg_fitness_plot) > 0 :
            plt.plot(avg_fitness_plot, label="avg")
        if len(best_fitness_plot) > 0 :
            plt.plot(best_fitness_plot, label="best")
        plt.title(title)
        plt.ylabel('Fitness')
        plt.xlabel('Generations')
        if gaConfig.plot_type == "avg":
            plt.legend(['Average Fitness'], loc='lower right')
        elif gaConfig.plot_type == "best":
            plt.legend(['Best Fitness'], loc='lower right')
        else:
            plt.legend(['Average Fitness', 'Best Fitness'], loc='lower right')
        plt.show()

def selct_config(option):
    root_dir = gaconfig.get_simplega()
    file_name = root_dir + "/configs/config_bts_bit_flip.json"
    selected_option = "Binary Tournament Selection with Bit Flip Mutation"
    if option == "1":
        file_name = root_dir + "/configs/config_bts_bit_flip.json"
        selected_option = "Binary Tournament Selection with Bit Flip Mutation"
    elif option == "2":
        file_name = root_dir + "/configs/config_bts_bit_swap.json"
        selected_option = "Binary Tournament Selection with Bit Swap Mutation"
    elif option == "3":
        file_name = root_dir +  "/configs/config_roulette_bit_flip.json"
        selected_option = "Roulette-Wheel Selection with Bit Flip Mutation"
    elif option == "4":
        file_name = root_dir +  "/configs/config_roulette_bit_swap.json"
        selected_option = "Roulette-Wheel Selection with Bit Swap Mutation"
    else:
        file_name = root_dir +  "/configs/config_bts_bit_flip.json"
        selected_option = "Binary Tournament Selection with Bit Flip Mutation"
    return file_name, selected_option

if __name__ == '__main__':
    print("Simple Gentic Algorithm Config Selction:")
    print("1. Binary Tournament Selection with Bit Flip Mutation")
    print("2. Binary Tournament Selection with Bit Swap Mutation")
    print("3. Roulette-Wheel Selection with Bit Flip Mutation")
    print("4. Roulette-Wheel Selection with Bit Swap Mutation")
    option = input("Enter your choice: ")
    config_file_name, selected_option = selct_config(option)
    with open(config_file_name,'r') as file:
        configString = file.read()
    configJSON = json.loads(configString)
    gaConfig = gaconfig.GAConfig.from_dict(configJSON)
    # print(gaConfig)
    if gaConfig.selection.type == "tournament":
        if gaConfig.selection.size >= gaConfig.n_populations:
            print("tournament selction size should be less than population size")
            exit()
    # gaEngine = sphereengine.SphereGAEngine(gaConfig, n_gene=gaConfig.n_gene)
    gaEngine = boothengine.BoothGAEngine(gaConfig, n_gene=gaConfig.n_gene)
    gaEngine.make_initial_population()

    avg_fitness_plot: list = []
    best_fitness_plot: list = []

    if gaConfig.plot_type == "avg":
        avg_fitness_plot.append(gaEngine.average_fitness())
    elif gaConfig.plot_type == "best":
        best_fitness_plot.append(gaEngine.best_finess())
    else:
        avg_fitness_plot.append(gaEngine.average_fitness())
        best_fitness_plot.append(gaEngine.best_finess())

    while  gaEngine.generations < gaConfig.n_generation:
        mating_pool = gaEngine.do_selection()
        next_gen = gaEngine.do_crossover(mating_pool)
        gaEngine.next_generation(next_gen)
        gaEngine.do_mutation()
        gaEngine.change_genration()
        no_of_crossover = int(gaConfig.n_populations * gaConfig.crossover_chances)
        gaEngine.totalPopulation += no_of_crossover

        if gaConfig.plot_type == "avg":
            avg_fitness_plot.append(gaEngine.average_fitness())
        elif gaConfig.plot_type == "best":
            best_fitness_plot.append(gaEngine.best_finess())
        else:
            avg_fitness_plot.append(gaEngine.average_fitness())
            best_fitness_plot.append(gaEngine.best_finess())

    print(gaEngine)
    title = "Fitness for "
    if gaConfig.plot_type == "avg":
        title = "Average Fitness for "
    if gaConfig.plot_type == "best":
        title = "Best Fitness for "

    plot_title = title + selected_option
    fitness_plot_stats(avg_fitness_plot=avg_fitness_plot,
                       best_fitness_plot=best_fitness_plot
                       ,title=plot_title)


from pyspark import SparkContext,RDD
from pyspark.sql import SparkSession

if __name__ =="__main__":

        spark =  SparkSession \
            .builder \
            .appName("Creating RDD") \
            .master("local[*]") \
            .getOrCreate()

        #only display error messages to console
        spark.sparkContext.setLogLevel("ERROR")

        #input file path
        #"D:\\spark\\Pyspark-Projects\\Intro\\PySpark-Fundamentals\\filter_program.txt"
        filePath = u"D:\\spark\\Pyspark-Projects\\Intro\\PySpark-Fundamentals\\filter_program.txt"

        #reading file using spark
        fileInput = spark.sparkContext.textFile(filePath)
        print((fileInput).collect())

        filteredRDD = fileInput.filter(lambda x : 'Py' in x)
        print(type(filteredRDD))

        print("Stopping spark session")
        spark.stop()


# coding: UTF-8
import glob
import os

import cv2
import numpy as np

from skimage.feature import hog

from .classifier import get_color_hist_features

def draw_boxes(img, bbox_list):
    img_drawn = np.copy(img)
    for bbox in bbox_list:
        cv2.rectangle(img_drawn, bbox[0], bbox[1], (0, 0, 255), 6)

    return img_drawn

def add_heat(heatmap, bbox_list):
    for bbox in bbox_list:
        heatmap[bbox[0][1]:bbox[1][1], bbox[0][0]:bbox[1][0]] += 1

    return heatmap

def apply_threshold(heatmap, threshold):
    heatmap[heatmap <= threshold] = 0

    return heatmap

def draw_labeled_bboxes(img, labels):
    img_drawn = np.copy(img)

    for car_number in range(1, labels[1] + 1):
        nonzero = (labels[0] == car_number).nonzero()
        nonzeroy = np.array(nonzero[0])
        nonzerox = np.array(nonzero[1])
        bbox = ((np.min(nonzerox), np.min(nonzeroy)), (np.max(nonzerox), np.max(nonzeroy)))
        cv2.rectangle(img_drawn, bbox[0], bbox[1], (0, 0, 255), 6)

    return img_drawn

def find_cars(
    img, y_start, y_stop, classifier, X_scaler,
    orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2)):

    bbox_list = []
    resize_to = (64, 64)

    assert pixels_per_cell[0] == pixels_per_cell[1]
    pix_per_cell = pixels_per_cell[0]

    img_to_search = img[y_start:y_stop, :, :]
    img_to_search_ycrcb = cv2.cvtColor(img_to_search, cv2.COLOR_RGB2YCR_CB)
    subimg = cv2.cvtColor(img_to_search, cv2.COLOR_RGB2HSV)

    channel_list = []
    for i in [0, 1, 2]:
        channel_list.append(img_to_search_ycrcb[:, :, i])
    # Compute individual channel HOG features
    hog_ch_list = []
    for channel in channel_list:
        hog_ch = hog(
            channel, orientations, pixels_per_cell, cells_per_block,
            transform_sqrt=True, visualise=False, feature_vector=False)
        hog_ch_list.append(hog_ch)

    # Define blocks and steps as above
    n_x_blocks = (img_to_search.shape[1] // pix_per_cell) - 1
    n_y_blocks = (img_to_search.shape[0] // pix_per_cell) - 1

    window = pixels_per_cell[0] * pixels_per_cell[1]
    n_blocks_per_window = (window // pix_per_cell) - 1
    cells_per_step = 2
    n_x_steps = (n_x_blocks - n_blocks_per_window) // cells_per_step
    n_y_steps = (n_y_blocks - n_blocks_per_window) // cells_per_step

    # Window search
    for xb in range(n_x_steps):
        for yb in range(n_y_steps):
            y_pos = yb * cells_per_step
            x_pos = xb * cells_per_step
            x_left = x_pos * pix_per_cell
            y_top = y_pos * pix_per_cell

            # Extract HOG
            hog_features_list = []
            for hog_ch in hog_ch_list:
                hog_features_list.append(hog_ch[y_pos:y_pos + n_blocks_per_window, x_pos:x_pos + n_blocks_per_window].ravel())
            hog_features = np.hstack(hog_features_list).reshape(1, -1)

            patch = subimg[y_top:y_top + window, x_left:x_left + window]
            patch_resized = cv2.resize(patch, resize_to)
            # Extract image features
            # img_features = patch_resized.ravel().reshape(1, -1)
            # Extract color hist features
            color_hist_features = get_color_hist_features(patch_resized, channels=[0, 1, 2]).reshape(1, -1)
            # Scale features
            # test_features = np.array(hog_features)
            test_features = np.hstack((hog_features, color_hist_features)).reshape(1, -1)
            X_test = X_scaler.transform(test_features)
            # Predict
            y_pred_test = classifier.predict(X_test)

            if y_pred_test == 1:
                x_box_left = np.int(x_left)
                y_top_draw = np.int(y_top)
                win_draw = np.int(window)
                bbox_list.append(
                    ((x_box_left, y_top_draw + y_start),
                     (x_box_left + win_draw, y_top_draw + win_draw + y_start))
                     )

    return bbox_list


from datetime import datetime

import pytest
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
import factories
from pytest_factoryboy import register

USER_MODEL = get_user_model()
register(factories.GoalFactory)
register(factories.BoardFactory)
register(factories.UserFactory)
register(factories.CategoryFactory)
register(factories.BoardParticipantFactory)
register(factories.GoalCommentFactory)
register(factories.TuserFactory)

@pytest.fixture
def auth_client(db, user):
    client = APIClient()
    client.force_authenticate(user)
    return client

@pytest.fixture()
def boards():
    return factories.BoardFactory.create_batch(5)

@pytest.fixture()
def board():
    return factories.BoardFactory.create()

@pytest.fixture()
def boards_with_participants(user, boards):
    for item in boards:
        factories.BoardParticipantFactory.create(
            board=item,
            user=user,
        )
    return boards

@pytest.fixture()
def board_with_participant(user, board):
    factories.BoardParticipantFactory.create(
        board=board,
        user=user,
    )
    return board

@pytest.fixture()
def category(board_with_participant, user):
    return factories.CategoryFactory.create(
        board=board_with_participant,
        user=user
    )

@pytest.fixture
def goal(category, user):
    test_date = datetime.now().date()
    return factories.GoalFactory.create(
        title='New Goal',
        category=category,
        description='Description of New Goal',
        due_date=test_date,
        user=user,
    )

@pytest.fixture
def goal_comment(goal, user):
    return factories.GoalCommentFactory.create(
        text='test_comment',
        goal=goal,
        user=user,
    )


import logging
import sys
import textwrap

from revefi_dbt_client.parser import parse_args_legacy, parse_args_v2
from revefi_dbt_client.upload import upload

LOG = logging.getLogger(__name__)

def main(legacy_parser=False):
    argv = sys.argv[1:]

    if legacy_parser:
        LOG.warning(textwrap.dedent("""
                                       Using legacy parser,
                                       please update how CLI is invoked as per the documentation: https://github.com/revefi/dbt_python_client"""))
        args = parse_args_legacy(argv)
    else:
        args = parse_args_v2(argv)

    try:
        upload(args.token, args.project_folder, args.target_folder, args.logs_folder)
    except:
        if args.ignore_errors:
            LOG.exception("Error occurred, but --ignore-error is supplied, exiting with exitCode 0")
            sys.exit(0)
        else:
            raise

if __name__ == "__main__":
    main()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import os
sys.path.append('/app')
import re
import logging
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from tornado import template

from settings import unittest as settings

def email(address):
    if re.match(r'^[\w]+@[\w\.]+$', address):
        return address
    else:
        raise ValueError('%s isn\'t an email' % address)

def send_email(src, dst, subject, text=None, html=None):
    server = smtplib.SMTP(
        host=settings['smtp']['host'],
        port=settings['smtp']['port'],
    )

    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = src
    msg['To'] = ', '.join(dst)
    if text:
        msg.attach(MIMEText(text, 'text'))
    if html:
        msg.attach(MIMEText(html, 'html'))

    server.send_message(msg)
    server.quit()

    return True

if __name__ == '__main__':
    text = 'look at HTML'
    tmpl = template.Template(
        'Hello from html template

lala'
    )
    html = tmpl.generate().decode()
    send_email(
        'src@mail.ru',
        ['dst@mail.ru', 'dst2@mail.ru'],
        'Test',
        'look at html',
        html,
    )


#!/Users/marinig/opt/anaconda3/lib/python3.7
# Filename: tinderApp.py

import sys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *

import qdarkstyle
import argparse
import oyaml as yaml
import csv
import json
import GUI.loginWindow as lw
import GUI.mainWindow as mw
from API.tinder_api_extended import TinderApi
from GUI.log import log
import traceback
from Threading.data_reloader import APIBackgroundWorker
from GUI.customwaitingwidget import QtCustomWaitingSpinner
import faulthandler
import time
import os
import re

class TinderApp(QApplication):
    def __init__(self, parsed_args, *args, **kwargs):
        super(TinderApp, self).__init__(*args, **kwargs)

        log.create_log_widget()
        self.data_folder = "./Data/"
        self.recommendations_folder = self.data_folder + "recommendations/"
        self.recommendations_file = self.data_folder + "recommendations.json"
        self.matches_folder = self.data_folder + "matches/"
        self.matches_file = self.data_folder + "matches.json"
        self.profile_folder = self.data_folder + "profile/"
        self.profile_file = self.data_folder + "profile.json"
        self.tinder_api = TinderApi(self.data_folder)
        self.logged_in = False

        # self.thread = QThread()  # 1a - create Worker and Thread inside the Form. No parent!
        # self.obj = worker.Worker()  # no parent!
        self.thread_pool = QThreadPool()   # 1b - create a ThreadPool and then create the Workers when you need!
        self.thread_pool.setMaxThreadCount(4)

        self.background_tasks_list = []
        self.background_info = QLabel("No background stuff!")
        self.background_count_label = QLabel("")
        self.background_completed = 0
        self.background_count_total = 0
        self.spinner = QtCustomWaitingSpinner(self, centerOnParent=False)
        self.spinner.hideSpinner()
        self.spinner.updateSize(QSize(30,30))

        """
        I wanted to make this config an object. I tried by calling yaml_load and getting
        the dictionary from a pure yaml file (without !!python/object:__main__.ConfigSingleton on top)
        Then I tried to pass the dictionary to an object like Struct(**dict) and
        class Struct:
            def __init__(self, **entries):
                self.__dict__.update(entries)

        But it did not work
        """
        self.configSingleton = ConfigSingleton()  # Transform the dict to attributes of the class ConfigSingleton
        self.config = self.configSingleton.yaml_config  # Transform the dict to attributes of the class ConfigSingleton
        self.config_file = self.configSingleton.yaml_config_file

        self.recommendations = None
        self.matches = None
        self.new_recommendations = None
        self.new_matches = None
        self.profile_info = None

        self.window = ""
        # set app icon
        self.setWindowIcon(QIcon("GUI/icons/tinder.png"))
        if parsed_args.css:
            self.updateStyle()
        else:
            if sys.platform!='darwin':
                self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())

        # self.startMainWindow(True)
        self.startLoginWindow()

    def export_people_data_csv(self, csv_filename, people_data, keys_to_export):
        with open(csv_filename, mode='r') as csv_file:
            csv_writer = csv.writer(csv_file, delimiter=',', quotechar='"',
                                    quoting=csv.QUOTE_MINIMAL)
            for person in people_data:
                for key in person.keys():
                    to_write = []
                    if key in keys_to_export:
                        to_write = to_write + person[key]
                if len(to_write) > 0:
                    csv_writer.writerow(to_write)

    def updateData(self, list_to_fill, downloaded_data, file_path):
        if list_to_fill is not None and isinstance(list_to_fill, list):
            list_to_fill.append(downloaded_data)
            data_to_dump = list_to_fill
        else:
            data_to_dump = downloaded_data
        try:
            with open(file_path, 'w') as fp:
                json.dump(data_to_dump, fp)
            log.i("API", "Data written to: " + file_path)
        except Exception as e:
            log.e("API", "Exception saving " + file_path + " json: " + str(e))

    def get_api_data(self, doAsync=False, api_fun=None, args=[], kwargs={},
                     finished_callback=None, callback_args=None, callback_kwargs=None,
                     update_callback=None, info=None, tag=None):
        if not doAsync:
            kwargs["log_to_widget"] = False
            kwargs["thread_update_signal"] = None
            result = api_fun(*args, **kwargs)
            self.new_data_callback(result, finished_callback)
        else:
            obj = APIBackgroundWorker(api_fun, args, kwargs, callback=finished_callback, callback_args=callback_args, callback_kwargs=callback_kwargs)
            if tag is not None:
                obj.tag = tag
            obj.signals.dataReceived.connect(self.new_data_callback)  # 2 - Connect Worker`s Signals to Form method slots to post data.
            if update_callback is None:
                update_callback = self.updateBackgroundTaskInfo
            obj.signals.dataUpdate.connect(update_callback)  # 2 - Connect Worker`s Signals to Form method slots to post data.
            if info is None:
                self.addBackgroundTask(obj, "Getting Data from API: " +str(info))
            else:
                self.addBackgroundTask(obj, info)

    def get_profile(self, doAsync=True, force_update=False):
        try:
            with open(self.profile_file, "r") as pf:
                data= json.load(pf)
            log.d("APP", "Profile file read: " +str(data))
            self.setProfileData(data, download_data=False)
        except Exception as e:
            log.e("APP", "No profile found")

        if self.profile_info is None or force_update:
            self.get_api_data(doAsync, self.tinder_api.get_self,
                              [], {},
                              finished_callback=self.setProfileData,
                              callback_kwargs={'download_data':True},
                              update_callback=self.updateBackgroundTaskInfo,
                              info="Getting profile data",
                              tag="ProfileGetter")
    def setProfileData(self, new_data, download_data=False):
        log.d("APP", "New profile info, download: " +str(download_data))
        if new_data is not None:
            self.profile_info = new_data
        if self.profile_info is None:
            return
        if self.window is not None and self.window.chat_widget is not None:
            self.window.chat_widget.setLeftId(self.profile_info["_id"])

        if download_data:
            self.get_api_data(True, self.tinder_api.download_person_data,
                                    [self.profile_info, self.profile_folder, True, True, False, True],
                                    {"force_overwrite": True},
                                    finished_callback=self.updateProfileData,
                                    update_callback=self.updateBackgroundTaskInfo,
                                    info="Downloading Profile data to: " + str(self.profile_folder),
                                    tag="ProfileDownloader")
    def updateProfileData(self, downloaded_data):
        try:
            with open(self.profile_file, 'w') as fp:
                json.dump(downloaded_data, fp)
            log.i("API", "Profile data written to: " + self.profile_file)
        except Exception as e:
            log.e("API", "Exception saving " + self.profile_file + " json: " + str(e))
        pass

    def get_matches(self, doAsync=True):
        self.get_api_data(doAsync, self.tinder_api.all_matches,
                          finished_callback=self.setNewMatches,
                          info="Getting new Matches")
    def setNewMatches(self, data):
        if 'data' in data:
            self.new_matches = data['data']['matches']
            self.updateMatchesWidgets(False, True)
    def read_matches(self, doAsync=False):
        self.get_api_data(doAsync, self.tinder_api.read_data, [self.matches_file],
                          info="Reading data from: " + str(self.matches_file),
                          finished_callback=self.setMatches,
                          tag="MatchesDownloader")
    def reload_matches(self, doAsync=False, photos=True, insta=True, messages=True, force_overwrite=False):
        self.get_api_data(doAsync, self.tinder_api.reload_data_from_disk,
                          [self.matches_folder, self.matches_file, photos, insta, messages],
                          {"force_overwrite": force_overwrite},
                          finished_callback=self.setMatches,
                          update_callback=self.updateBackgroundTaskInfo,
                          info="Reloading Matches",
                          tag="MatchesReloader")
    def download_new_matches(self, photos=True, insta=True, messages=True,  rename_images=False, amount=0, force_overwrite=False):
        self.get_api_data(True, self.tinder_api.download_people_data_api,
                          [self.new_matches, self.matches_folder, photos, insta, messages, rename_images, amount],
                          {"force_overwrite": force_overwrite},
                          finished_callback=self.updateMatches,
                          update_callback=self.updateBackgroundTaskInfo,
                          info="Downloading Matches data to: " + str(self.matches_folder),
                          tag="MatchesDownloader")
    def setMatches(self, data):
        log.d("APP", "updateMatches called")
        self.new_matches = None
        self.matches = data
        self.updateMatchesWidgets()
    def updateMatches(self, downloaded_data):
        self.updateData(self.matches, downloaded_data, self.matches_file)
        self.updateMatchesWidgets()
    def updateMatchesWidgets(self, updateList=True, updateWidgets=True):
        if self.window is not None:
            if updateList:
                self.window.matches_list.update_list(self.matches)
            if updateWidgets:
                self.window.features_panel.update_matches_widgets()

    def get_recommendations(self, doAsync=True):
        self.get_api_data(doAsync, self.tinder_api.get_recs_v2,
                              finished_callback=self.setNewRecommendations,
                              info="Getting new Recommendations")
    def setNewRecommendations(self, data):
        if 'data' in data:
            self.new_recommendations = data['data']['results']
            self.updateRecommendationsWidgets(False, True)
    # Read recommendations.json file containing all recommendations
    def read_recommendations(self, doAsync=False):
        self.get_api_data(doAsync, self.tinder_api.read_data, [self.recommendations_file],
                          info="Reading data from: " + str(self.recommendations_file),
                          finished_callback=self.setRecommendations,
                          tag="RecomendationsDownloader")
    # Redownload recommendations and writes the output to file file containing all recommendations
    def reload_recommendations(self, doAsync=False,photos=True, insta=True, force_overwrite=False):
        self.get_api_data(doAsync, self.tinder_api.reload_data_from_disk,
                          [self.recommendations_folder, self.recommendations_file, photos, insta, False],
                          {"force_overwrite": force_overwrite},
                          finished_callback=self.setRecommendations,
                          update_callback=self.updateBackgroundTaskInfo,
                          info="Reloading Recommendations",
                          tag="RecommendationsReloader")
    def download_new_recommendations(self, photos=True, insta=True, rename_images=False, amount=0, force_overwrite=False):
        self.get_api_data(True, self.tinder_api.download_people_data_api,
                          [self.new_recommendations, self.recommendations_folder, photos, insta, False, rename_images, amount],
                          {"force_overwrite": force_overwrite},
                          finished_callback=self.updateRecommendations,
                          update_callback=self.updateBackgroundTaskInfo,
                          info="Downloading Recommendations data to: " + str(self.matches_folder),
                          tag="RecommendationsDownloader")
    def setRecommendations(self, data):
        log.d("APP", "setRecommendations called")
        self.new_recommendations = None
        self.recommendations = data
        self.updateRecommendationsWidgets()
    def updateRecommendations(self, downloaded_data):
        self.updateData(self.recommendations, downloaded_data, self.recommendations_file)
        self.updateRecommendationsWidgets()
    def updateRecommendationsWidgets(self, updateList=True, updateWidgets=True):
        if self.window is not None:
            if updateList:
                self.window.recommendations_list.update_list(self.recommendations)
            if updateWidgets:
                self.window.features_panel.update_recommendations_widgets()

    def get_messages(self, match_data, finished_callback=None, person_name=""):
        self.app.get_api_data(True, self.app.tinder_api.get_messages,
                              [], {'match_data': match_data, 'count': 100, 'page_token': None},
                              finished_callback=finished_callback,
                              info="Getting messages " + person_name,
                              tag="MessagesDownloader")
    def get_match_info(self, id, name):
        self.get_api_data(True, self.tinder_api.get_person, [id], finished_callback=self.person_data_received,
                          info="Getting data of " +str(name + "_"+ str(id)))

    def person_data_received(self, data):
        self.window.json_view.load_data(data["data"])
        log.d("PERSON_DATA", +str(data))

    def new_data_callback(self, data, callback, callback_args, callback_kwargs, async_data=None, time_started=None, tag=None):
        if async_data is not None:
            self.completeBackgroundTask(async_data + ": completed! ", tag=tag)
        if time_started is not None:
            print(async_data + " execution time: " + str(time.time() - time_started) + "s")
        if callback is not None:
            print("Callback, args: " +str(callback_args) + ". kwwargs: " +str(callback_kwargs))
            if callback_args is not None and callback_kwargs is not None:
                callback(data, callback_args, callback_kwargs)
            elif callback_args is not None:
                callback(data, callback_args)
            elif callback_kwargs is not None:
                callback(data, callback_kwargs)
            else:
                callback(data)

    def updateStyle(self):
        log.i("APP", "Update style!")
        try:
            with open('./style.css', 'r') as cssfile:
                self.setStyleSheet(cssfile.read())
        except Exception as e:
            log.e("APP", "Update style Exception")

    def startLoginWindow(self):
        self.window = lw.LoginWindow(self, self.background_info, self.background_count_label, self.spinner, parsed_args)
        self.window.show()
        if self.config:
            self.window.form_widget.verify_login(True)

    def verify_login(self, doAsync, callback):
        log.i("APP", "Config File: " + str(os.path.abspath(self.config_file)))
        log.i("APP", "Verify login: " + str(self.config))
        self.get_api_data(doAsync, self.tinder_api.authverif,
                          [self.config['facebook']['auth_token'], self.config['facebook']['user_id']],
                          finished_callback=callback, info="Verifying login",
                          tag="LoginVerifier")

    def login_verified(self, isVerified, openMainWindow=False):
        self.logged_in = isVerified
        QApplication.processEvents()
        if openMainWindow:
            with open(self.config_file, 'w') as fy:
                yaml.dump(self.config, fy)
            self.startMainWindow(True)
        self.update_status_bar()

    def update_status_bar(self):
        if self.logged_in:
            log.i("APP", "Login verified!")
            self.window.statusBar.showMessage("Login verified!")
            self.window.setWindowTitle("TinderAI (Online)")
        else:
            log.i("APP", "Login FAILED!")
            self.window.statusBar.showMessage("Login FAILED!")
            self.window.setWindowTitle("TinderAI (OFFLINE)")

    def startMainWindow(self, doAsync=False):
        if self.window is not None:
            self.window.close()
        if self.config:
            self.window = mw.MainWindow(self, self.background_info, self.background_count_label, self.spinner, parsed_args)
            self.window.show()
            self.update_status_bar()
            self.read_recommendations(doAsync)
            self.read_matches(doAsync)
            self.get_profile(doAsync, force_update=False) #it should be None at the beginning, triggering the get_self_data
        else:
            self.window = lw.LoginWindow(self, parsed_args)
            self.window.show()
            self.window.form_widget.statusBar.showMessage("No config file found, login again")

    def addBackgroundTask(self, task, info=""):
        if task.tag is not None:
            while task.tag in self.background_tasks_list:
                string_matches = re.match(r"(.*)([0-9]+)", task.tag)
                if string_matches is not None:
                    # print("string_matches: " +str(string_matches.groups()))
                    task.tag = string_matches.group(1)+str(int(string_matches.group(2))+1)
                else:
                    task.tag += "_1"
            self.background_tasks_list.append(task.tag)
        self.updateBackgroundTaskInfo(info)
        self.background_count_total += 1
        if self.background_count_total <= 1:
            self.spinner.showSpinner()
            self.background_count_label.setVisible(True)
        self.updateBackgroundTaskCount()
        log.d("THREADS", "Added new background task " +str(info) +" " +str(self.background_completed) + "/" + str(self.background_count_total) +" Tasks: " +str(self.background_tasks_list), False)
        self.thread_pool.start(task)

    def completeBackgroundTask(self, info="", tag=None):
        self.updateBackgroundTaskInfo(info)
        if tag is not None and tag in self.background_tasks_list:
            self.background_tasks_list.remove(tag)
        self.background_completed += 1
        if self.background_completed >= self.background_count_total:
            self.background_count_total = 0
            self.background_completed = 0
            self.spinner.hideSpinner()
            self.updateBackgroundTaskInfo("All tasks completed!")
            self.background_count_label.setVisible(False)
        self.updateBackgroundTaskCount()
        log.d("THREADS", "Completed background task " +str(info) +" " +str(self.background_completed) + "/" + str(self.background_count_total) +" Tasks: " +str(self.background_tasks_list), False)

    def updateBackgroundTaskCount(self):
        self.background_count_label.setText(str(self.background_completed) +"/"+str(self.background_count_total))

    def updateBackgroundTaskInfo(self, text=""):
        self.background_info.setText(str(text))

class ConfigSingleton:
    __instance__ = None
    yaml_config_file = "./settings.yaml"
    try:
        yaml_config = yaml.safe_load(open(yaml_config_file))
    except Exception:
        yaml_config = None

    def __init__(self):
        """ Constructor. """
        if ConfigSingleton.__instance__ is None:
            ConfigSingleton.__instance__ = self
        else:
            raise Exception("You cannot create another SingletonGovt class")

    def get_instance():
        """ Static method to fetch the current instance. """
        if not ConfigSingleton.__instance__:
            ConfigSingleton()
        return ConfigSingleton.__instance__

def process_cl_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--css',  action='store_true', help='Reloads the CSS at each event, used for styling purposes')  # optional flag
    parsed_args, unparsed_args = parser.parse_known_args()
    return parsed_args, unparsed_args

"""
THIS IS SUPER IMPORTANT IN PYQT5 APPS
Without this, python won't print any unhandled exception since they happen within the app.exec_()
"""
def trap_exc_during_debug(*args):
    exc_type, exc_value, exc_traceback = sys.exc_info()
    log.e("MAIN", "General Exception: " +str(args))
    traceback.print_tb(exc_traceback, limit=None, file=sys.stdout)

if __name__ == '__main__':
    # install exception hook: without this, uncaught exception would cause application to exit
    sys.excepthook = trap_exc_during_debug
    parsed_args, unparsed_args = process_cl_args()
    # QApplication expects the first argument to be the program name.
    qt_args = sys.argv[:1] + unparsed_args

    with open("./fault_handler.log", "w") as fobj:
        faulthandler.enable(fobj)
        app = TinderApp(parsed_args, qt_args)
        app.exec_()


from lib.ApiLib import *
from Position import *
import time
from loguru import logger
from OrderInfo import *
from TelegramBot import *

WAIT_SECONDS_FOR_BUY = 30

isBuckbotSuspend = False

class CatchBot:
    def __init__(self, symbol, option):
        self.symbol = symbol
        self.option = option

    def stop(self):
        pass

    def start(self):
        logger.info("{:10} | Start CatchBot", self.symbol)

        while True:
            try:
                order = self.waitForCatch() # 타겟 이격도 이상 급락하면 매수해서 리턴된다.
                TelegramBot.sendMsg("{:10} | 캐치 매수 체결됨: {:10.5f}".format(self.symbol, order['price']))

                position = Position(order, self.option)

                pnl = position.waitForPositionClosed()  # 포지션이 종료되면 리턴된다. (익절이든 본절/손절이든)
                logger.info("{:10} | 캐치 포지션 종료. PNL: {:10.5f}%", self.symbol, pnl)
                TelegramBot.sendMsg("{:10} | 캐치 포지션 종료. PNL: {:10.5f}%".format(self.symbol, pnl))

            except Exception as ex:
                logger.error("{:10} | CatchBot 종료. Exception: {}", self.symbol, repr(ex))
                TelegramBot.sendMsg("{:10} | CatchBot 종료. Exception: {}".format(self.symbol, repr(ex)))
                break

    def waitForBuyClosed(self, order, waitSeconds):
        if Lib.hasClosed(order):
            return order

        for sec in range(waitSeconds):
            o = Lib.api.fetch_order(order['id'], self.symbol)

            if Lib.hasClosed(o):
                break

            time.sleep(1)

        return o

    def getTargetDIPrice(self, curPrice):
        ma20 = Lib.get20Ma(self.symbol, curPrice)
        targetPrice = ma20 * (1 - self.option.targetDI)
        return targetPrice

    def orderBuyLimit(self, price):
        quantity = Lib.getQuantity(price, self.option.marginRatio)
        return Lib.api.create_limit_buy_order(self.symbol, quantity, price)

    def waitForCatch(self):
        global isBuckbotSuspend

        countOfFailure = 0
        order = None
        isBuckbotSuspend = False

        while True:
            if dt.datetime.now().second != 59:
                time.sleep(0.5)
                continue

            try:
                curPrice = Lib.getCurrentPrice(self.symbol)
                targetPrice = self.getTargetDIPrice(curPrice)

                if targetPrice >= curPrice:
                    logger.debug("{:10} | 캐치 만족: {:10.5f}", self.symbol, targetPrice)
                    isBuckbotSuspend = True # 매수할 때 잔고 여유가 있어야 하므로 bucketBot 대기 매수를 전부 취소하고 스레드를 일시 중지한다.
                    time.sleep(1)

                    order = self.orderBuyLimit(targetPrice)     # 1분봉 종료 시 이격도를 만족하면 지정가 매수한다.
                    logger.info("{:10} | 캐치 매수 주문: {:10.5f}", self.symbol, targetPrice)
                    order = self.waitForBuyClosed(order, WAIT_SECONDS_FOR_BUY)

                    if Lib.hasClosed(order):
                        logger.info("{:10} | 캐치 매수 체결됨: {:10.5f}", self.symbol, order['price'])
                        break   # 매수 체결되었으므로 캐치 종료
                    else:
                        logger.info("{:10} | {}초 동안 미체결되어 매수 취소함", self.symbol, WAIT_SECONDS_FOR_BUY)
                        Lib.api.cancel_order(order['id'], self.symbol)  # 30초 동안 체결되지 않으면 주문 취소한다.
                        isBuckbotSuspend = False

                if countOfFailure > 0:
                    logger.info("{:10} | 에러 복구 됨", self.symbol)
                    countOfFailure = 0

            except Exception as ex:
                countOfFailure += 1
                logger.warning("{:10} | {} Raised an exception. {}", self.symbol, countOfFailure, repr(ex))
                if countOfFailure >= TRY_COUNT:
                    raise ex  # 1초 뒤에 다시 시도해 보고 연속 5번 exception 나면 매매를 종료한다.

            time.sleep(1) # 1초에 두 번 취소->주문 되는걸 방지하기 위해 1초를 쉰다.

        return order


import itertools
import json
import operator
import typing

import models

def fetch_geo_data(text: typing.List[str]) -> typing.List[models.GeoMessage]:
    messages: typing.List[models.GeoMessage] = []
    for row in text:
        data = json.loads(row)
        if 'geo' in row:
            messages.append(models.GeoMessage(data))

    return sorted(messages, key=operator.attrgetter('utc_dttm'))

def fetch_control_data(
        text: typing.List[str],
) -> typing.List[models.ControlMessage]:
    messages: typing.List[models.ControlMessage] = []
    for row in text:
        data = json.loads(row)
        if 'control_switch_on' in row:
            messages.append(models.ControlMessage(data))

    return sorted(messages, key=operator.attrgetter('utc_dttm'))

def find_selfdrived_time(
        messages: typing.List[models.ControlMessage],
) -> typing.List[models.SelfdrivedInterval]:
    intervals: typing.List[models.SelfdrivedInterval] = []
    periods = itertools.groupby(messages,
                                operator.attrgetter('control_switch_on'))
    for is_selfdrived, timeseries in periods:
        if is_selfdrived:
            intervals.append(models.SelfdrivedInterval(list(timeseries)))
    return intervals

def filter_stops(
        messages: typing.List[models.GeoMessage],
) -> typing.List[models.GeoMessage]:
    groups = itertools.groupby(messages, key=operator.attrgetter('geo'))
    return [min(group[1], key=operator.attrgetter('utc_dttm'))
            for group in groups]

def split_by_seconds(
        messages: typing.List[models.GeoMessage],
) -> typing.List[models.GeoMessage]:
    groups = itertools.groupby(messages, key=operator.attrgetter('utc_dttm'))
    return [max(group[1], key=operator.attrgetter('geo'))
            for group in groups]

def compare_coordinates(
        messages: typing.List[models.GeoMessage],
) -> typing.List[models.Segment]:
    segments: typing.List[models.Segment] = []
    messages.sort(key=operator.attrgetter('utc_dttm'))
    for i, msg in enumerate(messages):
        if i+1 != len(messages):
            segments.append(models.Segment((messages[i], messages[i+1])))
    return segments

def check_time(
        interval: models.SelfdrivedInterval,
        segment: models.Segment,
) -> bool:
    if interval.begin_time <= segment.arrival_time <= interval.end_time:
        return True
    return False

def who_was_drive(
        intervals: typing.List[models.SelfdrivedInterval],
        segments: typing.List[models.Segment],
):
    for seg in segments:
        checks: typing.List[bool] = []
        for i in intervals:
            checks.append(check_time(i, seg))
        seg.is_selfdrived = any(checks)
    return segments

def get_routes_info(segments: typing.List[models.Segment]):
    results: typing.List[models.RouteInfo] = []
    groups = itertools.groupby(segments,
                               key=operator.attrgetter('is_selfdrived'))

    for is_selfdrived, group in groups:
        route_segments = tuple(group)
        distance_list = map(operator.attrgetter('distance'), route_segments)
        first_segment = min(route_segments,
                            key=operator.attrgetter('arrival_time'))
        last_segment = max(route_segments,
                           key=operator.attrgetter('destination_time'))
        arrival_point = str(first_segment.arrival_point)
        arrival_time = first_segment.arrival_time.isoformat()
        destination_point = str(last_segment.destination_point)
        destination_time = last_segment.destination_time.isoformat()

        results.append(models.RouteInfo(is_selfdrived=is_selfdrived,
                                        distance=sum(list(distance_list)),
                                        units='Meters',
                                        trip_time=len(route_segments),
                                        segments=route_segments,
                                        arrival_point=arrival_point,
                                        arrival_time=arrival_time,
                                        destination_time=destination_time,
                                        destination_point=destination_point,
                                        ))
    return results

def route_calculator(data: typing.Any) -> typing.List[models.RouteInfo]:
    geo_messages = fetch_geo_data(data)
    control_messages = fetch_control_data(data)
    uniq_geo = filter_stops(geo_messages)
    splited_geo = split_by_seconds(uniq_geo)
    selfdrived_intervals = find_selfdrived_time(control_messages)
    all_segments = compare_coordinates(splited_geo)
    all_segments = who_was_drive(selfdrived_intervals, all_segments)
    routes = get_routes_info(all_segments)
    return routes

def do_stuff():
    with open('data', 'r') as file_obj:
        raw_data = file_obj.readlines()

        for r in route_calculator(raw_data):
            print(r.serialize())

if __name__ == '__main__':
    do_stuff()


from deeplake.constants import MB, PARTIAL_NUM_SAMPLES
from deeplake.core.chunk.sample_compressed_chunk import SampleCompressedChunk
import numpy as np
import pytest

import deeplake
from deeplake.core.meta.tensor_meta import TensorMeta
from deeplake.core.sample import Sample  # type: ignore
from deeplake.core.tiling.deserialize import np_list_to_sample
from deeplake.core.tiling.sample_tiles import SampleTiles

compressions_paremetrized = pytest.mark.parametrize("compression", ["lz4"])

common_args = {
    "min_chunk_size": 1 * MB,
    "max_chunk_size": 2 * MB,
    "tiling_threshold": 1 * MB,
}

def create_tensor_meta():
    tensor_meta = TensorMeta()
    tensor_meta.dtype = "float32"
    tensor_meta.max_shape = None
    tensor_meta.min_shape = None
    tensor_meta.htype = None
    tensor_meta.length = 0
    return tensor_meta

@compressions_paremetrized
def test_read_write_sequence(compression):
    tensor_meta = create_tensor_meta()
    common_args["tensor_meta"] = tensor_meta
    common_args["compression"] = compression
    dtype = tensor_meta.dtype
    data_in = [np.random.rand(250, 125, 3).astype(dtype) for _ in range(10)]
    data_in2 = data_in.copy()
    while data_in:
        chunk = SampleCompressedChunk(**common_args)
        num_samples = int(chunk.extend_if_has_space(data_in))
        data_out = [chunk.read_sample(i) for i in range(num_samples)]
        np.testing.assert_array_equal(data_out, data_in2[:num_samples])
        data_in = data_in[num_samples:]
        data_in2 = data_in2[num_samples:]

@pytest.mark.slow
@compressions_paremetrized
def test_read_write_sequence_big(cat_path, compression):
    tensor_meta = create_tensor_meta()
    common_args = {
        "min_chunk_size": 16 * MB,
        "max_chunk_size": 32 * MB,
        "tiling_threshold": 16 * MB,
        "tensor_meta": tensor_meta,
        "compression": compression,
    }

    dtype = tensor_meta.dtype
    data_in = []
    for i in range(50):
        if i % 10 == 0:
            data_in.append(np.random.rand(6001, 3000, 3).astype(dtype))
        elif i % 3 == 0:
            data_in.append(deeplake.read(cat_path))
        else:
            data_in.append(np.random.rand(1000, 500, 3).astype(dtype))
    data_in2 = data_in.copy()
    tiles = []
    original_length = len(data_in)

    while data_in:
        chunk = SampleCompressedChunk(**common_args)
        num_samples = chunk.extend_if_has_space(data_in)
        if num_samples == PARTIAL_NUM_SAMPLES:
            tiles.append(chunk.read_sample(0, is_tile=True))
            sample = data_in[0]
            assert isinstance(sample, SampleTiles)
            if sample.is_last_write:
                current_length = len(data_in)
                index = original_length - current_length
                full_data_out = np_list_to_sample(
                    tiles,
                    sample.sample_shape,
                    sample.tile_shape,
                    sample.layout_shape,
                    dtype,
                )
                np.testing.assert_array_equal(full_data_out, data_in2[index])
                data_in = data_in[1:]
                tiles = []

        elif num_samples > 0:
            data_out = [chunk.read_sample(i) for i in range(num_samples)]
            for i, item in enumerate(data_out):
                if isinstance(item, Sample):
                    item = item.array
                np.testing.assert_array_equal(item, data_in[i])
            data_in = data_in[num_samples:]

# @compressions_paremetrized
# def test_update(compression):
#     tensor_meta = create_tensor_meta()
#     common_args["tensor_meta"] = tensor_meta
#     common_args["compression"] = compression
#     dtype = tensor_meta.dtype
#     arr = np.random.rand(7, 25, 125, 3).astype(dtype)
#     data_in = list(arr)
#     chunk = SampleCompressedChunk(**common_args)
#     chunk.extend_if_has_space(data_in)
#     data_out = np.array([chunk.read_sample(i) for i in range(7)])
#     np.testing.assert_array_equal(data_out, data_in)

#     data_3 = np.random.rand(175, 350, 3).astype(dtype)
#     data_5 = np.random.rand(1500, 750, 3).astype(dtype)

#     chunk.update_sample(3, data_3)
#     chunk.update_sample(5, data_5)
#     for i in range(7):
#         if i == 3:
#             np.testing.assert_array_equal(chunk.read_sample(i), data_3)
#         elif i == 5:
#             np.testing.assert_array_equal(chunk.read_sample(i), data_5)
#         else:
#             np.testing.assert_array_equal(chunk.read_sample(i), arr[i])


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import errno
import socket
import sys
import time
import traceback

from . import handleParameter
from . import handleData
from . import handleCmd
from . import result
from . import showHelp
from . import autoComplete

try:
    reload(sys)  # Python 2.7
    sys.setdefaultencoding('utf8')
except NameError:
    try:
        from importlib import reload  # Python 3.4+
        reload(sys)
    except ImportError:
        from imp import reload  # Python 3.0 - 3.3
        reload(sys)

def main():
    handle = QcloudCLI()
    handle.main()

class QcloudCLI:
    def __init__(self):
        self.user_input = sys.argv[1:]
        self.handleParameter = handleParameter.handleParameter()
        self.handleCmd = handleCmd.handleCmd()
        self.handleData = handleData.handleData()
        self.showHelp = showHelp.showHelp()
        self.completer = autoComplete.Completer()

    def main(self):
        module = ''
        #get module such as cvm cdb..maybe extra cmd such as help,version
        if self.user_input.__len__() > 0:
            module = self.user_input[0].lower()

        #show qcloudcli help
        help_cmd = ['help','-h','--help']
        if not module or module.lower() in help_cmd:
            self.handleCmd.showQcloudCliHelp()
            return

        #show version
        version_cmd = ['version','--version']
        if module.lower() in version_cmd:
            self.handleCmd.showVersion()
            return

        #configure qcloudcli
        configure_cmd = ['configure']
        if module.lower() in configure_cmd:
            self.handleCmd.configureQcloudcli()
            return

        #showconfigure qcloudcli
        showconfigure_cmd = ['showconfigure']
        if module.lower() in showconfigure_cmd:
            self.handleCmd.showconfigure()
            return

        #addprofile qcloudcli
        addprofile_cmd = ['addprofile']
        if module.lower() in addprofile_cmd:
            self.handleCmd.addprofile()
            return

        # useprofile qcloudcli
        useprofile_cmd = ['useprofile']
        if module.lower() in useprofile_cmd:
            self.handleCmd.useprofile()
            return

        # useprofile qcloudcli
        useprofile_cmd = ['delprofile']
        if module.lower() in useprofile_cmd:
            self.handleCmd.delprofile()
            return

        # get action,such as DescribeInterfaces
        action = self.handleParameter.getAction()

        # get paramlist
        keyValues = self.handleParameter._getKeyValues()
        outPutFormat = self.handleParameter.getUserDefinedOutPutFormat(keyValues)
        if outPutFormat is not None and len(outPutFormat) != 0:
            outPutFormat = outPutFormat[0]
        else:
            outPutFormat = self.handleCmd.getUserFormat()
            if outPutFormat is None or outPutFormat == "":
                outPutFormat = 'json'

        if module in self.handleData.getAllModules():
            moduleAllActions = self.handleData.getModuleActions(module)
            if action in moduleAllActions:
                instance = self.handleData.makeInstance(module, action)
                instance_version = self.handleData.makeInstance(module, action)
                in_class = self.handleData.makeClass(module, action)
                in_class_version = self.handleData.makeClass(module, action)
                is_version = 0
                if module == 'cvm' and action+'V3' in moduleAllActions:
                    is_version = 1
                    in_class_version = self.handleData.makeClass(module, action+'V3')
                    instance_version = self.handleData.makeInstance(module, action+'V3')
                if (instance is not None or instance_version is not None) and (in_class is not None or in_class_version is not None):
                    helpcmds = ['-h', '--help', 'help']
                    cmdlen = self.user_input.__len__()
                    if cmdlen >= 3:
                        for i in range(2, cmdlen):
                            if self.user_input[i] in helpcmds:
                                self.showHelp.showParameterError(module, action, is_version, self.completer._help_to_show_instance_attribute(in_class, in_class_version)[0],self.completer._help_to_show_instance_attribute(in_class, in_class_version)[1],self.completer._help_to_show_instance_attribute(in_class, in_class_version)[2], self.completer._help_to_show_instance_attribute(in_class, in_class_version)[3])
                                return
                    if keyValues.get("RegionId") is None and keyValues.get("regionId") is None and keyValues.get("Regionid")is None and keyValues.get("regionid") is None:
                        keyValues["RegionId"] = [self.handleCmd.getUserRegion()]
                    if not self.handleData.checkInputIsEmpty(keyValues):
                        print('Your [SecretId] or [SecretKey] or [RegionId] is absence!')
                        return
                    try:
                        if not keyValues.get("Version") is None and self.is_valid_date(keyValues.get("Version")[0]) and is_version == 1:
                            outcome = self.handleData.getResponse(module, action, keyValues, instance_version, in_class_version)
                        else:
                            outcome = self.handleData.getResponse(module, action, keyValues, instance, in_class)
                        if outcome is None:
                            return
                        result.display_result(action, outcome, outPutFormat, keyValues)
                    except socket.error as e:
                        print(e)
                        if e.errno == errno.ETIMEDOUT:
                            print('Connection aborted due to timeout exception.')
                            print('Please check your network connection, firewall and router settings.')
                            print('If you are behind a proxy, you need to set the https_proxy environment variable.')
                        else:
                            print(traceback.format_exc())
                    except Exception as e:
                        print(e)
                        print(traceback.format_exc())
                else:
                    print('qcloudcli internal error, please try again.')
            else:
                self.showHelp.showActionError(module)
        else:
            self.showHelp.showModuleError()

    def is_valid_date(self, str):
        try:
            time.strptime(str, "%Y-%m-%d")
            return True
        except:
            return False

if __name__ == '__main__':
    main()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jan 11 17:02:41 2018

@author: ad247405
"""

import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import nibabel as nib
import pandas as pd
import nibabel as nib
import json
from nilearn import plotting
from nilearn import image
from scipy.stats.stats import pearsonr
import shutil
import scipy.stats
import matplotlib.pyplot as plt
import seaborn as sns
import parsimony.utils.check_arrays as check_arrays
from sklearn import preprocessing
import statsmodels.api as sm
from statsmodels.formula.api import ols
import seaborn as sns

#https://central.xnat.org/REST/projects/NUDataSharing
INPUT_CLINIC_FILENAME = "/neurospin/abide/schizConnect/data/december_2017_clinical_score/schizconnect_NUSDAST_assessmentData_4495.csv"

y_all = np.load("/neurospin/brainomics/2016_schizConnect/2018_analysis_2ndpart_clinic/results/clustering_ROIs/data/y.npy")
site = np.load("/neurospin/brainomics/2016_schizConnect/2018_analysis_2ndpart_clinic/results/clustering_ROIs/data/site.npy")
y_nudast = y_all[site==3]

pop= pd.read_csv("/neurospin/brainomics/2016_schizConnect/2018_analysis_2ndpart_clinic/results/clustering_ROIs/data/population.csv")

site = np.load("/neurospin/brainomics/2016_schizConnect/2018_analysis_2ndpart_clinic/results/clustering_ROIs/data/site.npy")
clinic = pd.read_csv(INPUT_CLINIC_FILENAME)

pop= pop[pop["site_num"]==3]
age = pop["age"].values
sex = pop["sex_num"].values

labels_cluster = np.load("/neurospin/brainomics/2016_schizConnect/2018_analysis_2ndpart_clinic/results/clustering_ROIs/results/thick+vol/3_clusters/labels_cluster.npy")
labels_cluster = labels_cluster[site==3]

df_scores = pd.DataFrame()
df_scores["subjectid"] = pop.subjectid
for score in clinic.question_id.unique():
    df_scores[score] = np.nan

for s in pop.subjectid:
    curr = clinic[clinic.subjectid ==s]
    for key in clinic.question_id.unique():
        if curr[curr.question_id == key].empty == False:
            df_scores.loc[df_scores["subjectid"]== s,key] = curr[curr.question_id == key].question_value.values[0]

df_scores["totalSANS"] = 0
for i in (1,2,3,4,5,6,7,9,10,11,12,14,15,16,18,19,20,21,23,24):
   df_scores["totalSANS"] = df_scores["totalSANS"]  + df_scores["sans%s"%i].astype(np.float).values

df_scores["totalSAPS"] = 0
for i in (1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,26,27,28,29,30,31,32,33):
   df_scores["totalSAPS"] = df_scores["totalSAPS"]  + df_scores["saps%s"%i].astype(np.float).values

df_scores["sansSUbtot"] = df_scores["sans8"].astype(np.float).values+df_scores["sans13"].astype(np.float).values+\
df_scores["sans17"].astype(np.float).values+df_scores["sans22"].astype(np.float).values+\
df_scores["sans25"].astype(np.float).values

df_scores["sapsSUbtot"] = df_scores["saps7"].astype(np.float).values+df_scores["saps20"].astype(np.float).values+\
df_scores["saps25"].astype(np.float).values+df_scores["saps34"].astype(np.float).values

################################################################################
output = "/neurospin/brainomics/2016_schizConnect/2018_analysis_2ndpart_clinic/\
results/clustering_ROIs/results/thick+vol/3_clusters/nudast/"
key_of_interest= list()

df_stats = pd.DataFrame(columns=["T","p","mean Cluster 1","mean Cluster 2","mean Cluster 3"])
df_stats.insert(0,"clinical_scores",df_scores.keys())
for key in df_scores.keys():
    try:
        neurospycho = df_scores[key].astype(np.float).values
        df = pd.DataFrame()
        df[key] = neurospycho[np.array(np.isnan(neurospycho)==False)]
        df["age"] = age[np.array(np.isnan(neurospycho)==False)]
        df["sex"] = sex[np.array(np.isnan(neurospycho)==False)]
        df["labels"]=labels_cluster[np.array(np.isnan(neurospycho)==False)]
        T,p = scipy.stats.f_oneway(df[df["labels"]=='SCZ Cluster 1'][key],\
                 df[df["labels"]=='SCZ Cluster 2'][key],\
                    df[df["labels"]=='SCZ Cluster 3'][key])
        if p<0.05:
            print(key)
            print(p)
            key_of_interest.append(key)
        df_stats.loc[df_stats.clinical_scores==key,"T"] = round(T,3)
        df_stats.loc[df_stats.clinical_scores==key,"p"] = round(p,4)
        df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 1"] = round(df[df["labels"]=='SCZ Cluster 1'][key].mean(),3)
        df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 2"] = round(df[df["labels"]=='SCZ Cluster 2'][key].mean(),3)
        df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 3"] = round(df[df["labels"]=='SCZ Cluster 3'][key].mean(),3)

    except:
        print("issue")
        df_stats.loc[df_stats.clinical_scores==key,"T"] = np.nan
        df_stats.loc[df_stats.clinical_scores==key,"p"] = np.nan
df_stats.to_csv(os.path.join(output,"clusters_clinics_p_values.csv"))

################################################################################
key = "totalSAPS"
key = "totalSANS"
key = "sansSUbtot"
key = "sapsSUbtot"
df_scores["panss_diff"] = df_scores["sansSUbtot"].astype(np.float).values-df_scores["sapsSUbtot"].astype(np.float).values
NP_scores = ["vocabsca",'dstscalc',"sstscalc","lnsscalc","d4prime","lmiscalc","fpiscalc",'matrxsca',"trailb","wcstpsve"]

for key in key_of_interest:
    plt.figure()
    df = pd.DataFrame()
    score = df_scores[key].astype(np.float).values
    df["labels"]=labels_cluster[np.array(np.isnan(score)==False)]
    df[key] =  score[np.array(np.isnan(score)==False)]
    T,p = scipy.stats.f_oneway(df[df["labels"]=='Subcortical'][key],
                         df[df["labels"]=='Cortical'][key],\
                        df[df["labels"]=='Preserved'][key])
    ax = sns.violinplot(x="labels", y=key, data=df,order=["Controls","Subcortical","Cortical","Preserved"])
    plt.title("ANOVA patients diff: t = %s, and  p= %s"%(T,p))
    plt.savefig(os.path.join(output,"plots","%s.png"%key))

df[df["labels"]=='SCZ Cluster 1'][key].mean()
df[df["labels"]=='SCZ Cluster 1'][key].std()
df[df["labels"]=='SCZ Cluster 2'][key].mean()
df[df["labels"]=='SCZ Cluster 2'][key].std()
df[df["labels"]=='SCZ Cluster 3'][key].mean()
df[df["labels"]=='SCZ Cluster 3'][key].std()

###############################################################################
###############################################################################
#Save table with scores
import six

df = df_stats[df_stats["T"].isnull()==False]
render_mpl_table(df, header_columns=0, col_width=2.0,output=os.path.join(output,"all_anova_nudast_results.png"))

df = df_stats[df_stats["T"].isnull()==False]
df = df_stats[df_stats["p"]<0.05]
render_mpl_table(df, header_columns=0, col_width=2.0,output=os.path.join(output,"significant_anova_nudast_results.png"))

def render_mpl_table(data,output, col_width=30.0, row_height=0.325, font_size=12,
                     header_color='#40466e', row_colors=['#f1f1f2', 'w'], edge_color='w',
                     bbox=[0, 0, 1, 1], header_columns=0,
                     ax=None, **kwargs):
    if ax is None:
        size = (np.array(data.shape[::-1]) + np.array([0, 1])) * np.array([col_width, row_height])
        fig, ax = plt.subplots(figsize=size)
        ax.axis('off')

    mpl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=data.columns, cellLoc='center',loc='upper left')

    mpl_table.auto_set_font_size(False)
    mpl_table.set_fontsize(font_size)

    for k, cell in  six.iteritems(mpl_table._cells):
        cell.set_edgecolor(edge_color)
        if k[0] == 0 or k[1] < header_columns:
            cell.set_text_props(weight='bold', color='w')
            cell.set_facecolor(header_color)
        else:
            cell.set_facecolor(row_colors[k[0]%len(row_colors) ])
    plt.tight_layout()
    plt.savefig(output)
    return ax

###############################################################################
###############################################################################
#code to plot NP meand variables

NP_scores = ["vocabsca",'dstscalc',"sstscalc","lnsscalc","d4prime","lmiscalc","fpiscalc",'matrxsca',"trailb","wcstpsve"]

#NP_scores = ["vocabsca",'dstscalc',"sstscalc","lnsscalc","d4prime","lmiscalc","fpiscalc",'matrxsca']

df_stats = pd.DataFrame(columns=["mean Controls","std Controls","mean Cluster 1","mean Cluster 2","mean Cluster 3",\
                                 "std Cluster 1","std Cluster 2","std Cluster 3"])
df_stats.insert(0,"clinical_scores",NP_scores)
for key in NP_scores:
    neurospycho = df_scores[key].astype(np.float).values
    df = pd.DataFrame()
    y = y_nudast[np.array(np.isnan(neurospycho)==False)]
    score = neurospycho[np.array(np.isnan(neurospycho)==False)]
    score = ((score - score[y==0].mean(axis=0))/score[y==0].std(axis=0))
    df[key] = score
    df["labels"]=labels_cluster[np.array(np.isnan(neurospycho)==False)]
    df_stats.loc[df_stats.clinical_scores==key,"mean Controls"] = round(df[df["labels"]=='Controls'][key].mean(),3)

    df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 1"] = round(df[df["labels"]=='Subcortical'][key].mean(),3)
    df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 2"] = round(df[df["labels"]=='Cortical'][key].mean(),3)
    df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 3"] = round(df[df["labels"]=='Preserved'][key].mean(),3)

    df_stats.loc[df_stats.clinical_scores==key,"std Cluster 1"] = round(df[df["labels"]=='Subcortical'][key].std(),3)
    df_stats.loc[df_stats.clinical_scores==key,"std Cluster 2"] = round(df[df["labels"]=='Cortical'][key].std(),3)
    df_stats.loc[df_stats.clinical_scores==key,"std Cluster 3"] = round(df[df["labels"]=='Preserved'][key].std(),3)

#plt.errorbar(x,y=df_stats["mean Controls"],yerr=df_stats["std Controls"],label = "Controls",marker='o',ls='--')
#plt.errorbar(x,y=df_stats["mean Cluster 1"],yerr=df_stats["std Cluster 1"],label = "SCZ Cluster 1",marker='v',ls='--')
#plt.errorbar(x,y=df_stats["mean Cluster 2"],yerr=df_stats["std Cluster 2"],label = "SCZ Cluster 2",marker='p',ls='--')
#plt.errorbar(x,y=df_stats["mean Cluster 3"],yerr=df_stats["std Cluster 3"],label = "SCZ Cluster 3",marker='d',ls='--')
#plt.legend()
#plt.ylabel("Z-score")

plt.plot(df_stats["mean Controls"],'o',label = 'Controls', marker='o',markersize=10,ls='--',color= "darkgreen")
plt.plot(df_stats["mean Cluster 1"],'o',label = 'Subcortical', marker='v',markersize=10,ls='--',color= "darkblue")
plt.plot(df_stats["mean Cluster 2"],'o',label = 'Cortical', marker='s',markersize=10,ls='--',color= "firebrick")
plt.plot(df_stats["mean Cluster 3"],'o',label = 'Preserved', marker='d',markersize=10,ls='--',color= "goldenrod")
plt.annotate('', xy=(0.67, -0.37), xycoords='axes fraction', xytext=(1, -0.37),
            arrowprops=dict(arrowstyle="<->", color='black',lw= 3))
plt.annotate('', xy=(0.47, -0.37), xycoords='axes fraction', xytext=(0.67, -0.37),
            arrowprops=dict(arrowstyle="<->", color='black',lw= 3))
plt.annotate('', xy=(0.12, -0.37), xycoords='axes fraction', xytext=(0.47, -0.37),
            arrowprops=dict(arrowstyle="<->", color='black',lw= 3))
plt.annotate('', xy=(0, -0.37), xycoords='axes fraction', xytext=(0.12, -0.37),
            arrowprops=dict(arrowstyle="<->", color='black',lw= 3))
plt.text(7, -4.2, "Executive Functions")
plt.text(4.2, -4.2, "Episodic Memory")
plt.text(1.1, -4.2, "Working Memory")
plt.text(-0.9, -4.2, "Intelligence")

plt.legend(loc = 'upper center',ncol = 4)
plt.ylabel("Z-score")
x = np.arange(10)
plt.axis([-1,10, -2,3])
NP_scores_legend = ["WAIS vocabulary",'WMS Digit Span',"WMS Spatial Span",\
"WMS Letter Number\n Sequencing","CPT dprime", "WMS Logical Memory",\
"WMS Family Picture",'WAIS Matrix\n Reasoning',"Trails B time",'WCST perseverative\n errors']
#NP_scores_legend = ["WAIS vocab",'WMS Digit Span',"WMS Spatial Span","WMS LN","CPT dprime", "WMS LM","WMS FP",'WAIS matrix']
plt.xticks(x,NP_scores_legend,rotation=60, fontsize=10)
plt.tight_layout()
plt.savefig(os.path.join(output,"neuropsy_per_clusters"), bbox_inches="tight")
###############################################################################
NP_scores = ["cvl15tsc","cvlsdcrs",\
"cvlldcrs","cvllsls","cvlrccs"]

df_stats = pd.DataFrame(columns=["mean Controls","std Controls","mean Cluster 1","mean Cluster 2","mean Cluster 3",\
                                 "std Cluster 1","std Cluster 2","std Cluster 3"])
df_stats.insert(0,"clinical_scores",NP_scores)
for key in NP_scores:
    neurospycho = df_scores[key].astype(np.float).values
    df = pd.DataFrame()
    y = y_nudast[np.array(np.isnan(neurospycho)==False)]
    score = neurospycho[np.array(np.isnan(neurospycho)==False)]
    score = ((score - score[y==0].mean(axis=0))/score[y==0].std(axis=0))
    df[key] = score
    df["labels"]=labels_cluster[np.array(np.isnan(neurospycho)==False)]
    df_stats.loc[df_stats.clinical_scores==key,"mean Controls"] = round(df[df["labels"]=='Controls'][key].mean(),3)

    df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 1"] = round(df[df["labels"]=='Subcortical'][key].mean(),3)
    df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 2"] = round(df[df["labels"]=='Cortical'][key].mean(),3)
    df_stats.loc[df_stats.clinical_scores==key,"mean Cluster 3"] = round(df[df["labels"]=='Preserved'][key].mean(),3)

    df_stats.loc[df_stats.clinical_scores==key,"std Cluster 1"] = round(df[df["labels"]=='Subcortical'][key].std(),3)
    df_stats.loc[df_stats.clinical_scores==key,"std Cluster 2"] = round(df[df["labels"]=='Cortical'][key].std(),3)
    df_stats.loc[df_stats.clinical_scores==key,"std Cluster 3"] = round(df[df["labels"]=='Preserved'][key].std(),3)

plt.plot(df_stats["mean Controls"],'o',label = 'Controls', marker='o',markersize=10,ls='--',color= "darkgreen")
plt.plot(df_stats["mean Cluster 1"],'o',label = 'Subcortical', marker='v',markersize=10,ls='--',color= "darkblue")
plt.plot(df_stats["mean Cluster 2"],'o',label = 'Cortical', marker='s',markersize=10,ls='--',color= "firebrick")
plt.plot(df_stats["mean Cluster 3"],'o',label = 'Preserved', marker='d',markersize=10,ls='--',color= "goldenrod")
plt.legend(loc = 'upper center',ncol =4)
plt.ylabel("Z-score")
x = np.arange(5)
NP_scores_legend = ["Sum of Trials 1-5","Short Delay Cued Recall",\
"Long Delay Cued Recall","Learning Slope","Discriminability"]
plt.xticks(x,NP_scores_legend,rotation=60, fontsize=12)
plt.tight_layout()
plt.title("California Verbal Learning Task")

###############################################################################
## Libraries
#import matplotlib.pyplot as plt
#import pandas as pd
#from math import pi
#NP_scores = ["vocabsca",'dstscalc',"sstscalc","lnsscalc","d4prime","lmiscalc",\
#"fpiscalc",'matrxsca',"trailb","wcstpsve"]
#
## Set data
#df = pd.DataFrame({
#'group': ['Cluster 1','Cluster 2','Cluster 3'],
#'WAIS vocab': [df_stats[df_stats["clinical_scores"]=="vocabsca"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="vocabsca"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="vocabsca"]["mean Cluster 3"].values],\
#
#'WMS Digit Span':  [df_stats[df_stats["clinical_scores"]=="dstscalc"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="dstscalc"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="dstscalc"]["mean Cluster 3"].values],\
#
#'WMS Spatial Span': [df_stats[df_stats["clinical_scores"]=="sstscalc"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="sstscalc"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="sstscalc"]["mean Cluster 3"].values],
#
#'WMS LN': [df_stats[df_stats["clinical_scores"]=="lnsscalc"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="lnsscalc"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="lnsscalc"]["mean Cluster 3"].values],\
#
#'CPT dprime': [df_stats[df_stats["clinical_scores"]=="d4prime"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="d4prime"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="d4prime"]["mean Cluster 3"].values],\
#
#'WMS LM':  [df_stats[df_stats["clinical_scores"]=="lmiscalc"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="lmiscalc"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="lmiscalc"]["mean Cluster 3"].values],\
#
#'WMS FP': [df_stats[df_stats["clinical_scores"]=="fpiscalc"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="fpiscalc"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="fpiscalc"]["mean Cluster 3"].values],
#
#'WAIS matrix': [df_stats[df_stats["clinical_scores"]=="matrxsca"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="matrxsca"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="matrxsca"]["mean Cluster 3"].values],\
#
#'Trails B': [df_stats[df_stats["clinical_scores"]=="trailb"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="trailb"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="trailb"]["mean Cluster 3"].values],\
#
#'WCST errors':  [df_stats[df_stats["clinical_scores"]=="wcstpsve"]["mean Cluster 1"].values,\
#               df_stats[df_stats["clinical_scores"]=="wcstpsve"]["mean Cluster 2"].values,\
#                df_stats[df_stats["clinical_scores"]=="wcstpsve"]["mean Cluster 3"].values]
#
#})
#NP_scores_legend = ["WAIS vocab",'WMS Digit Span',"WMS Spatial Span","WMS LN",\
#"CPT dprime", "WMS LM","WMS FP",'WAIS matrix','Trails B','WCST errors',"group"]
##NP_scores_legend = ["WAIS vocab",'WMS Digit Span',"WMS Spatial Span","WMS LN",\
##"CPT dprime", "WMS LM","WMS FP",'WAIS matrix',"group"]
#
#df = df[NP_scores_legend]
#
## number of variable
#categories=list(df)[:-1]
#N = len(categories)
#
## We are going to plot the first line of the data frame.
## But we need to repeat the first value to close the circular graph:
#values0=df.loc[0].drop('group').values.flatten().tolist()
#values0 += values0[:1]
#values0
#values1=df.loc[1].drop('group').values.flatten().tolist()
#values1 += values1[:1]
#values1
#
#values2=df.loc[2].drop('group').values.flatten().tolist()
#values2 += values2[:1]
#values2
#
#
## What will be the angle of each axis in the plot? (we divide the plot / number of variable)
#angles = [n / float(N) * 2 * pi for n in range(N)]
#angles += angles[:1]
#
## Initialise the spider plot
#ax = plt.subplot(111, polar=True)
#
## Draw one axe per variable + add labels labels yet
#plt.xticks(angles[:-1], categories, color='black', size=12)
#
## Draw ylabels
#ax.set_rlabel_position(0)
#plt.yticks([0], ["controls"], color="grey", size=7)
#plt.ylim(-2,3)
#
## Plot data
#ax.plot(angles, values0, linewidth=3, linestyle='solid',label= "Cluster 1")
#ax.plot(angles, values1, linewidth=3, linestyle='solid',label="Cluster 2")
#ax.plot(angles, values2, linewidth=3, linestyle='solid',label="Cluster 3")
#ax.legend(loc=7)
## Fill area


from collections import defaultdict, Counter

from pylicenses.providers.condachannel import CondaChannelProvider
from pylicenses.providers.condalocal import CondaProvider
from pylicenses.providers.piplocal import PipProvider
from pylicenses.providers.pypi import PyPiProvider
from pylicenses.providers.static import StaticProvider

version = '0.1'

class PyLicenses(object):
    """
    Extensible dependencies license finder
    """
    PROVIDERS = {
        'primary': [PipProvider, CondaProvider],
        'fallback': [StaticProvider,
                     CondaChannelProvider,
                     PyPiProvider,
        ]
    }

    def __init__(self, github_auth=None):
        """

        :param github_auth: the tuple (user,password), defaults to None
        """
        # a pipeline of providers
        # TODO unify all providers into one pipeline and use an n-pass strategy to execute
        #      until no progress is made (progress = reduce #missing packages)
        self.github_auth = tuple(github_auth) if github_auth else None
        self._packages = defaultdict(dict)
        self.providers = defaultdict(list)
        # initialize providers, passing information
        for kind, provs in PyLicenses.PROVIDERS.items():
            for provCls in provs:
                kwargs = {
                    kwarg: getattr(self, kwarg) for kwarg in provCls.init_kwargs
                }
                self.providers[kind].append(provCls(**kwargs))

    @property
    def packages(self):
        return self._packages

    def discover(self, subset=None):
        """
        return dict of all packages including license files
        """
        # get packages and licenses dicts from primary providers
        packages = self._packages
        for prov in self.providers['primary']:
            prov.get_packages_info(packages, subset=subset)
        # find those with missing license files
        for prov in self.providers['fallback']:
            missing = self.missing_licenses(subset=subset)
            infos = prov.get_packages_info(missing)
            for pkg, missing_data in infos.items():
                if subset and not pkg in subset:
                    continue
                data = packages.get(pkg)
                data.update(missing_data) if infos else None
        return self

    def missing_licenses(self, subset=None):
        return {pkg: data for pkg, data in self.packages.items()
                if (subset is None or pkg in subset)
                and not any(data.get(k) for k in ('license_text', 'license_source'))
                }

    def resolved_licenses(self, subset=None):
        return {pkg: data for pkg, data in self.packages.items()
                if (subset is None or pkg in subset)
                and any(data.get(k) for k in ('license_source', 'license_text'))
                }

    def get_license_stats(self):
        c = Counter()
        by_license = defaultdict(set)
        for pkg, data in self.resolved_licenses().items():
            name = data['name']
            license = data.get('license_family') or data.get('license', 'unknown')
            c[license] += 1
            by_license[license].add(name)
        return c, by_license

    def get_package_dependencies(self, pkg):
        data = self.packages[pkg]
        depends = set()
        if 'requires_dist' in data:
            reqs = data['requires_dist']
            for dist in reqs.split(';'):
                dep_name = dist.split(' ')[0]
                depends.add(dep_name) if dep_name else None
        if 'depends' in data:
            for dist in data['depends']:
                dep_name = dist.split(' ')[0]
                depends.add(dep_name) if dep_name else None
        return depends

    def discover_package_dependencies(self):
        """
        for each package determine what required it, from package dependencies

        Note:
            The dependencies are derived from package meta data only. Any pip or
            conda requirements.txt is not taken into account. The dependencies
            are reported independent of versions and no correctness is done
            (i.e. no verification whether dependencies are satisfied)

        :return: .packages is updated to contain the required_by key for each
           package. If required_by is an empty set the package was not required
           by any (known) package.
        """
        packages = self.packages
        requireds = defaultdict(set)
        for pkg, data in packages.items():
            requireds[pkg]  # ensure we have an empty set for every pkg
            if pkg != data['name']:
                # only use basic package names, not versioned
                continue
            for dep in self.get_package_dependencies(pkg):
                requireds[dep].add(pkg)
        for pkg, required_by in requireds.items():
            if pkg in packages:
                # only add to known packages
                packages[pkg]['required_by'] = required_by
                packages[pkg]['is_primary'] = not required_by
        return self


from datetime import datetime
from urllib.error import HTTPError

from kivy.clock import Clock
from kivymd.uix.selectioncontrol import MDCheckbox
from kivymd.uix.snackbar import Snackbar
from kivymd.utils import asynckivy
from plyer import filechooser, camera

from Model.Database import Contest, LiveContest, Rider
import View.AdminScreen.ControlScreen.control_screen
import importlib

from View.AdminScreen.ControlScreen.components.common.content.rider_content import RiderContent

importlib.reload(View.AdminScreen.ControlScreen.control_screen)

class ControlScreenController:
    """
    The `ControlScreenController` class represents a controller implementation.
    Coordinates work of the view with the model.
    The controller implements the strategy pattern. The controller connects to
    the view to control its actions.
    """

    def __init__(self, model):
        self.model = model  # Model.control_screen.ControlScreenModel
        self.model.controller = self
        self.view = View.AdminScreen.ControlScreen.control_screen.ControlScreenView(controller=self, model=self.model)
        self.current_tab = 'Contests'

    def get_view(self) -> View.AdminScreen.ControlScreen.control_screen:
        return self.view

    def go_to_main(self):
        self.view.manager_screens.go_to('main screen')

    def check_data(self, dt):
        '''Asynchronously creates and adds chips to the container.'''

        async def check_data():
            await asynckivy.sleep(0)
            self.model.check_data()

        asynckivy.start(check_data())

    def adjust_theme(self):
        self.view.theme_cls.theme_style = "Dark" if self.view.theme_cls.theme_style == "Light" else "Light"

    def register_rider(self, rider, contest, *args):
        contest.register(rider)
        rider.register_to_contest(contest)

        self.set_participant_list(contest)

    def set_participant_list(self, contest):
        participants = []
        for rider in self.model.riders:
            registered = False
            if rider in contest.registered_riders:
                registered = True
            item = {
                'controller': self,
                'registered': registered,
                'rider': rider,
                'contest': contest,
                'name': str(rider.full_name),
            }
            participants.append(item)

        self.model.participant_list = participants
        return participants

    def unregister_rider(self, rider, contest, *args):
        if rider in contest.registered_riders:
            contest.update(pull__registered_riders=rider)
            rider.update(pull__registered_contest=contest.id)
            # Save the changes to the contest object here
            contest.save()
            rider.save()

        updated_contest = Contest.objects(id=str(contest.id)).first()
        self.set_participant_list(updated_contest)

    def open_participant_list(self, contest):
        self.set_participant_list(contest)
        self.view.mobile_view.ids.bottom_sheet.open()
        self.view.tablet_view.ids.bottom_sheet.open()

    def go_live(self, contest):
        contest.go_live()
        contest.save()
        self.start_live_contest(contest)

    def end_live(self, contest):
        contest.live = False
        contest.save()

    def start_live_contest(self, contest):
        live_contest = LiveContest.objects(contest=contest).first()
        if not live_contest:
            live_contest = LiveContest(contest=contest)

        if not live_contest.start_time:
            live_contest.start_time = datetime.now()

        live_contest.save()
        self.model.live_contest = live_contest
        self.view.manager_screens.get_screen('judges screen').model.live_contest = live_contest
        self.view.manager_screens.get_screen('dockhand screen').model.live_contest = live_contest

    def complete_contest(self, contest):
        contest.completed = True
        contest.save()
        Clock.schedule_once(self.model.check_data, 0)

    def cancel_dialog(self):
        self.model.new_contest = None
        self.model.new_rider = None

    def create_contest(self):
        self.model.new_contest = Contest()

    def set_event_type(self, type):
        if not self.model.new_contest:
            return
        self.model.new_contest.event_type = type

    def set_event_date(self, date):
        if not self.model.new_contest:
            return
        self.model.new_contest.date = date

    def set_name(self, value):
        if not self.model.new_contest:
            return
        self.model.new_contest.event_name = value

    def set_location(self, value):
        if not self.model.new_contest:
            return
        self.model.new_contest.park = value

    def set_description(self, value):
        if not self.model.new_contest:
            return
        self.model.new_contest.description = value

    def save_contest_image(self, path):
        if path:
            image_path = path[0] if isinstance(path, list) else path
            self.model.image_path = image_path

    def set_contest_date(self, date):
        if not self.model.new_contest:
            return
        self.model.new_contest.date = datetime.strptime(date, '%m/%d/%Y')

    def save_contest(self):
        if self.model.new_contest:
            if self.model.image_path:
                self.model.new_contest.set_image(self.model.image_path)
            self.model.new_contest.save()
            self.model.new_contest = None
            Clock.schedule_once(self.check_data,0)

    def delete_contest(self, contest):
        contest.delete()
        self.model.check_data()

    def update_contest(self, contest_content, *args):
        contest = contest_content.contest
        # Update the contest object's attributes with values from ContestContent

        # Convert the date string back into a datetime object
        if contest_content.date != 'None':
            date_format = "%m/%d/%Y"
            contest.date = datetime.strptime(contest_content.date, date_format)

        try:
            if contest_content.image_path_changed:
                status, image_url = contest.set_image(contest_content.image_path)
                if status == "rate_limit_exceeded":
                    # Show a notification to the user
                    self.show_notification("Too many requests. Image update skipped.")
        except Exception as e:
            print(f"Error: {e}")

        # Save the contest object
        contest.save()
        self.model.check_data()

    def show_notification(self, message):
        # Assuming you're using KivyMD's Snackbar for notifications
        print(message)

    def create_rider(self):
        if self.model.new_rider:
            self.model.new_rider = None
        self.model.new_rider = Rider()

    def set_first_name(self, value):
        if not self.model.new_rider:
            return
        self.model.new_rider.first_name = value.capitalize()

    def set_last_name(self, value):
        if not self.model.new_rider:
            return
        self.model.new_rider.last_name = value.capitalize()

    def set_gender(self, value):
        if not self.model.new_rider:
            return
        self.model.new_rider.gender = value.capitalize()

    def set_stance(self, value):
        if not self.model.new_rider:
            return
        self.model.new_rider.stance = value.capitalize()

    def set_home_park(self, value):
        if not self.model.new_rider:
            return
        self.model.new_rider.home_park = value

    def set_rider_dob(self, dob):
        if not self.model.new_rider:
            return
        self.model.new_rider.date_of_birth = datetime.strptime(dob, '%m/%d/%Y')

    def save_rider(self):
        if not self.model.new_rider:
            return
        if self.model.image_path:
            self.model.new_rider.set_image(self.model.image_path)
            self.model.image_path = None

        self.model.new_rider.save()

        self.model.new_rider = None
        self.model.check_data()

    def update_rider(self, rider_content, *args):
        rider = rider_content.rider

        try:
            if rider_content.image_path_changed:
                rider.set_image(rider_content.image_path)
        except HTTPError as e:
            if e.code == 429:
                print("Too many requests when trying to set the image. Skipping image update.")
            else:
                # Handle other HTTP errors if necessary
                print(f"HTTP Error {e.code}: {e.reason}")
        except Exception as e:
            # Handle other exceptions if necessary
            print(f"Error: {e}")

        rider.save()
        self.model.check_data()
        return

    def delete_rider(self, rider):
        rider.delete()
        self.model.check_data()

    def store_image(self, path):
        if path:
            image_path = path[0] if isinstance(path, list) else path
            self.model.image_path = image_path


# Create your views here.

import models
import forms
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.core.exceptions import ObjectDoesNotExist

def poll(r):
    return render_to_response('poll.html',{'poll':forms.Poll()})

def poll_handler(r):

    f = forms.Poll(r.POST)
    if f.is_valid():
        urlid = models.Poll.make_urlid()
        p=models.Poll(
            description = f.cleaned_data['description'],
            question    = f.cleaned_data['question'],
            choices     = f.cleaned_data['choices'],
            urlid       = urlid)
        p.save()
        return HttpResponseRedirect('/vote/'+urlid)
    else:
        return HttpResponseRedirect('/',)

def vote(r):

    # either the voter has just casted his ballot, in which case, the
    # post handler has appended a ?voter='name' and the models.Voter
    # should be passed to the template to present smart initials

    # or the voter has not just voted, she is unidentified, the
    # initial value for the form are the default values

    urlid = r.path.split('/')[-1]
    poll = models.Poll.objects.get(urlid=urlid)

    if r.GET and r.GET.get('name'):
        name = r.GET.get('name')
        try:
            v = poll.voter_set.get(name=name)
        except ObjectDoesNotExist:
            v = models.Voter(name=name)

        voter = forms.Voter({
                'name':v.name,
                'prefs':v.prefs,
                'comment':v.comment})
    else:
        voter = forms.Voter()

    return render_to_response('vote.html',{
            'question':poll.question,
            'description':poll.description,
            'choices':poll.choice_list(),
            'voters':[(v.name,v.pref_list(),v.comment) for v in poll.voter_set.all()],
            'results':poll.results(),
            'form':voter,
            'urlid':urlid})

def vote_handler(r):

    # either the voter has already voted and his name is among the
    # voters of the poll, no new voter must be created, only his
    # choices must be updated

    # or the voter has never voted with this name and she must be created

    urlid = r.path.split('/')[-1]
    poll = models.Poll.objects.get(urlid=urlid)

    f = forms.Voter(r.POST)
    if f.is_valid():
        name = f.cleaned_data['name']
        if name in [ v.name for v in poll.voter_set.all()]:
            v = poll.voter_set.get(name=name)
        else:
            v = models.Voter(name=name)
            v.poll = poll

        v.prefs = f.cleaned_data['prefs']
        v.comment = f.cleaned_data['comment']
        v.save()

        return HttpResponseRedirect('/vote/'+urlid+'?name='+name)


from flask import Flask, request, render_template
from flask_cors import CORS
import requests
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import openai
from dotenv import load_dotenv
import os
import random

app = Flask(__name__)
load_dotenv()

CORS(app)

openai.api_key = os.environ.get('OPENAI_KEY')
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=os.environ.get('SPOTIFY_CLIENT_ID'),
                                               client_secret=os.environ.get('SPOTIFY_CLIENT_SECRET'),
                                               redirect_uri="http://localhost:8888/callback",
                                               scope="user-top-read playlist-modify-public"))

""" interpret with openai

    Parameters:
        - prompt - the mood/vibe the user inputted
    Returns:
        - a string
"""

def gpt3_interpret(prompt):
    # Define the prompt and the OpenAI API parameters
    model = "text-davinci-003"
    # model = "text-curie-001"
    temperature = .7
    max_tokens = 250
    prompt = f"What are some words that describe the the mood: {prompt}\n"

    # Call the OpenAI API to generate text based on the prompt
    response = openai.Completion.create(
        engine=model,
        prompt=prompt,
        temperature=temperature,
        max_tokens=max_tokens
    )

    # Return the string
    return str(response.choices[0].text)

""" get tracks with openai

    Parameters:
        - prompt - the words to descirbe a users mood,
        use gpt3_interpret() first
    Returns
        - a string
"""

def gpt3_tracks(prompt, genre):
    # Define the prompt and the OpenAI API parameters
    model = "text-davinci-003"
    # model = "text-curie-001"
    temperature = .4
    max_tokens = 500
    frequency_penalty = 0.69
    presence_penalty = 0.56
    prompt = f"Can you give me a mix of 10 {genre} tracks that fit the following mood: {prompt}\n"

    # Call the OpenAI API to generate text based on the prompt
    response = openai.Completion.create(
        engine=model,
        prompt=prompt,
        temperature=temperature,
        max_tokens=max_tokens,
        frequency_penalty=frequency_penalty,
        presence_penalty=presence_penalty
    )

    # Return the string
    return str(response.choices[0].text)

""" get mood emoji with openai

    Parameters:
        - prompt - the mood/vibe the user inputted
    Returns:
        - a string with 1-3 emojis
"""

def gpt3_emoji(prompt):
    # Define the prompt and the OpenAI API parameters
    model = "text-davinci-003"
    # model = "text-curie-001"
    temperature = .7
    max_tokens = 256
    frequency_penalty = 0
    presence_penalty = 0
    prompt = f"What are 1 to 3 emojis that describes the the mood: {prompt}\n"

    # Call the OpenAI API to generate text based on the prompt
    response = openai.Completion.create(
        engine=model,
        prompt=prompt,
        temperature=temperature,
        max_tokens=max_tokens,
        frequency_penalty=frequency_penalty,
        presence_penalty=presence_penalty
    )

    # Return the string
    return str(response.choices[0].text)

""" get a response to the phrase

    Parameters:
        - prompt - the mood/vibe the user inputted
    Returns:
        - a string
"""

def gpt3_phrase(prompt):
    # Define the prompt and the OpenAI API parameters
    model = "text-davinci-003"
    # model = "text-curie-001"
    temperature = .7
    max_tokens = 256
    frequency_penalty = 0
    presence_penalty = 0
    prompt = f"What is a funny edgy positive thing I can tell my friend if they said: {prompt}\n"

    # Call the OpenAI API to generate text based on the prompt
    response = openai.Completion.create(
        engine=model,
        prompt=prompt,
        temperature=temperature,
        max_tokens=max_tokens,
        frequency_penalty=frequency_penalty,
        presence_penalty=presence_penalty
    )

    # Return the string
    return str(response.choices[0].text)

def spotify_search_songs(track_list):
    """
    use spotify to search for tracks and return a list of them. Returns a list of song URLs

    Parameters:
        - song_list - a string of songs
    """
    to_strip = "0123456789. "
    tracks_url = []
    track_list_split = track_list.split('\n')

    for track in track_list_split:
        track = track.lstrip(to_strip)
        track = track.strip("\"“”")
        track = track.replace('"', '')
        track = track.replace('”', '')

        if not track:
            continue
        print(f"Searching for {track}")
        try:
            results = sp.search(q=str(track), type='track')
        except requests.exceptions.RequestException as e:
            print(str(e))
            continue

        # Check if any results were found
        if len(results['tracks']['items']) > 0:
            # Get the URI of the first search result
            tracks_url.append(results['tracks']['items']
                              [0]['external_urls']['spotify'])

    return tracks_url

""" use to get html embed code for a list of songs

    Parameters:
        - tracks_uri - a list of track uri's
    Returns:
        - a string HTML
"""

def spotify_get_embed(tracks_uri):
    embed_list = []
    for url in tracks_uri:
        oembed_url = f'https://open.spotify.com/oembed?url={url}'
        response = requests.get(oembed_url)
        embed_list.append(response.json()['html'])

    return embed_list

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/search')
def search():
    # Input mood
    # input = "roadtrip"
    genre = request.args.get('genres')
    input = request.args.get('q')

    print(input)
    print(genre)

    # Call functions
    interpretation = gpt3_interpret(input)
    print(interpretation)
    reponse_phrase = gpt3_phrase(input)
    print(reponse_phrase)
    emojis = gpt3_emoji(input)
    print(emojis)
    tracks_string = gpt3_tracks(interpretation, genre)
    # tracks_string = gpt3_tracks("", genre)
    # print(tracks_string)
    tracks_url = spotify_search_songs(tracks_string)
    embed_list = spotify_get_embed(tracks_url)

    # Define the HTML content as a string format
    html = ""
    for embed in embed_list:
        html += embed

    # Return JSON response
    response = {
        "html": html,
        "URLS": tracks_url,
        "emojis": emojis,
        "interpretation": interpretation,
        "phrase": reponse_phrase,
    }

    return html

@app.route('/expsearch')
def expsearch():
    # Input mood
    # input = "roadtrip"
    genre = request.args.get('genres')
    input = request.args.get('q')

    print(input)
    print(genre)

    # Call functions
    reponse_phrase = gpt3_phrase(input)
    print(reponse_phrase)
    emojis = gpt3_emoji(input)
    print(emojis)
    tracks_string = gpt3_tracks(input, genre)
    # tracks_string = gpt3_tracks("", genre)
    # print(tracks_string)
    tracks_url = spotify_search_songs(tracks_string)
    embed_list = spotify_get_embed(tracks_url)

    # Define the HTML content as a string format
    html = ""
    for embed in embed_list:
        html += embed

    # Return JSON response
    response = {
        "html": html,
        "URLS": tracks_url,
        "emojis": emojis,
        "interpretation": input,
        "phrase": reponse_phrase,
    }

    return html

app.run(host="0.0.0.0", port=5000)


import json

# Convert to class, init with User as input

def open_name_database(database):
    ''' opens the database of aliased names'''
    with open(database, 'r') as f:
        return json.load(f)

def save_names_database(name_dict, database):
    ''' saves the database of aliased names'''
    with open(database, 'w') as f:
        json.dump(name_dict, f, indent=4)

def check_alias(name, database):
    ''' checks if an alias exists, else passes input instead '''
    try:
        names = open_name_database(database)
    except IOError:
        return name
    for key in names:
        if name.lower() in names[key]:
            return key
    return name

def remove_entry(name, database):
    try:
        names = open_name_database(database)
    except IOError:
        return name
    if name in names:
        names.pop(name)
        save_names_database(names, database)
        return "{} was removed from the database!".format(name)

def register_name_(source_, name, database):
    ''' registers aliases a name to something, i.e an IRC username/anime name '''
    source = source_
    database = database

    try:
        names = open_name_database(database)
    except IOError:
        names = {}
    try:
        name_list = names[name]
        if source.lower() in name_list:
            return '{0} is already aliased to {1}.'.format(name, source)
        else:
            names[name].append(source.lower())
            save_names_database(names, database)
            return 'Successfully aliased {0} to {1}.'.format(name, source)
    except KeyError:
        names[name] = [source.lower()]
        if names != None:
            save_names_database(names, database)
            return 'Added {0} with alias {1}.'.format(name, source)