import json
import struct
import tensorflow as tf
import cv2
import numpy as np
import os

imageSize = 337
width = imageSize
height = imageSize

mobileNetArchitectures = [
    ['conv2d', 2],
    ['separableConv', 1],
    ['separableConv', 2],
    ['separableConv', 1],
    ['separableConv', 2],
    ['separableConv', 1],
    ['separableConv', 2],
    ['separableConv', 1],
    ['separableConv', 1],
    ['separableConv', 1],
    ['separableConv', 1],
    ['separableConv', 1],
    ['separableConv', 1],
    ['separableConv', 1]
]

f = open("manifest.json")
variables = json.load(f)
f.close()

# with tf.variable_scope(None, 'MobilenetV1'):
for x in variables:
    filename = variables[x]["filename"]
    byte = open('./waits/'+filename,'rb').read()
    fmt = str (int (len(byte) / struct.calcsize('f'))) + 'f'
    d = struct.unpack(fmt, byte)
    # d = np.array(d,dtype=np.float32)
    d = tf.cast(d, tf.float32)
    d = tf.reshape(d,variables[x]["shape"])
    variables[x]["x"] = tf.Variable(d,name=x)

def read_imgfile(path, width, height):
    img = cv2.imread(path)
    img = cv2.resize(img, (width,height))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img = img.astype(float)
    img = img * (2.0 / 255.0) - 1.0
    return img

def convToOutput(mobileNetOutput, outputLayerName):
    w = tf.nn.conv2d(mobileNetOutput,weights(outputLayerName),[1,1,1,1],padding='SAME')
    w = tf.nn.bias_add(w,biases(outputLayerName), name=outputLayerName)
    return w

def conv(inputs, stride, blockId):
    # w = tf.nn.conv2d(inputs,weights("Conv2d_" + str(blockId)), stride, padding='SAME')
    # w = tf.nn.bias_add(w,biases("Conv2d_" + str(blockId)))
    # w = tf.nn.relu6(w)
    # return w
    return tf.nn.relu6(
        tf.nn.conv2d(inputs,weights("Conv2d_" + str(blockId)), stride, padding='SAME')
        + biases("Conv2d_" + str(blockId)))

def weights(layerName):
    return variables["MobilenetV1/" + layerName + "/weights"]['x']

def biases(layerName):
    return variables["MobilenetV1/" + layerName + "/biases"]['x']

def depthwiseWeights(layerName):
    return variables["MobilenetV1/" + layerName + "/depthwise_weights"]['x']

def separableConv(inputs, stride, blockID, dilations):
    if (dilations == None):
        dilations = [1,1]

    dwLayer = "Conv2d_" + str(blockID) + "_depthwise"
    pwLayer = "Conv2d_" + str(blockID) + "_pointwise"

    w = tf.nn.depthwise_conv2d(inputs,depthwiseWeights(dwLayer),stride, 'SAME',rate=dilations, data_format='NHWC')
    w = tf.nn.bias_add(w,biases(dwLayer))
    w = tf.nn.relu6(w)

    w = tf.nn.conv2d(w,weights(pwLayer), [1,1,1,1], padding='SAME')
    w = tf.nn.bias_add(w,biases(pwLayer))
    w = tf.nn.relu6(w)

    return w

image = tf.placeholder(tf.float32, shape=[1, imageSize, imageSize, 3],name='image')

count = 0
x = image
rate = [1,1]
buff = []
# conv_res = {}
with tf.variable_scope(None, 'MobilenetV1'):

    for m in mobileNetArchitectures:
        strinde = [1,m[1],m[1],1]
        if (m[0] == "conv2d"):
            x = conv(x,strinde,count)
            buff.append(x)
        elif (m[0] == "separableConv"):
            if count == 13:
                rate = [2,2]
            x = separableConv(x,strinde,count,rate)
            buff.append(x)
        count += 1

# x = tf.identity(x, name="output")

heatmaps = convToOutput(x, 'heatmap_2')
offsets = convToOutput(x, 'offset_2')
displacementFwd = convToOutput(x, 'displacement_fwd_2')
displacementBwd = convToOutput(x, 'displacement_bwd_2')
heatmaps = tf.sigmoid(heatmaps,'heatmap')

init = tf.global_variables_initializer()
saver = tf.train.Saver()

with tf.Session() as sess:
    sess.run(init)
    saver = tf.train.Saver()

    ans = sess.run([heatmaps,offsets,displacementFwd,displacementBwd], feed_dict={
            image: [np.ndarray(shape=(width, height, 3),dtype=np.float32)]
        }
    )

    save_dir = './checkpoints'
    save_path = os.path.join(save_dir, 'model.ckpt')
    # if not os.path.exists(save_dir):
        # os.mkdir(save_dir)
    save_path = saver.save(sess, save_path)

    tf.train.write_graph(sess.graph,"./models/","model.pbtxt")

    # Result
    input_image = read_imgfile("./images/tennis_in_crowd.jpg",width,height)
    input_image = np.array(input_image,dtype=np.float32)
    input_image = input_image.reshape(1,width,height,3)
    mobileNetOutput = sess.run(x, feed_dict={ image: input_image } )

    heatmaps_result,offsets_result,displacementFwd_result,displacementBwd_result = sess.run(
        [heatmaps,offsets,displacementFwd,displacementBwd], feed_dict={ image: input_image } )

    print(input_image)
    print(input_image.shape)
    print(np.mean(input_image))

    count = 0
    for b in buff:
        conv_result = sess.run(b, feed_dict={ image: input_image } )
        print("========")
        print(count)
        print(conv_result[0:1, 0:1, :])
        print(conv_result.shape)
        print(np.mean(conv_result))
        count += 1

    print("========")
    print("mobileNetOutput")
    print(mobileNetOutput[0:1, 0:1, :])
    print(mobileNetOutput.shape)
    print(np.mean(mobileNetOutput))

    heatmaps_result = heatmaps_result[0]

    print("========")
    print("heatmaps")
    print(heatmaps_result[0:1, 0:1, :])
    print(heatmaps_result.shape)
    print(np.mean(heatmaps_result))


import django
from django.conf import settings
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls')),
]

# Images & debug configuration
if settings.DEBUG:
    import debug_toolbar

    urlpatterns = (
            [
                path(
                    "media/<path:path>/",
                    django.views.static.serve,
                    {"document_root": settings.MEDIA_ROOT, "show_indexes": True},
                ),
                path("__debug__/", include(debug_toolbar.urls)),
            ]
            + staticfiles_urlpatterns()
            + urlpatterns
    )


from flask import Blueprint, render_template, abort
from sqlalchemy import func, distinct

from skylines.database import db
from skylines.lib.dbutil import get_requested_record
from skylines.model import User, Club, Flight, Airport

statistics_blueprint = Blueprint('statistics', 'skylines')

@statistics_blueprint.route('/')
@statistics_blueprint.route('/<page>/<id>')
def index(page=None, id=None):
    club = None
    pilot = None
    airport = None

    query = db.session.query(Flight.year.label('year'),
                             func.count('*').label('flights'),
                             func.count(distinct(Flight.pilot_id)).label('pilots'),
                             func.sum(Flight.olc_classic_distance).label('distance'),
                             func.sum(Flight.duration).label('duration'))

    pilots_query = db.session.query(func.count(distinct(Flight.pilot_id)))

    if page == 'pilot':
        pilot = get_requested_record(User, id)
        query = query.filter(Flight.pilot_id == pilot.id)

    elif page == 'club':
        club = get_requested_record(Club, id)
        query = query.filter(Flight.club_id == club.id)
        pilots_query = pilots_query.filter(Flight.club_id == club.id)

    elif page == 'airport':
        airport = get_requested_record(Airport, id)
        query = query.filter(Flight.takeoff_airport_id == airport.id)
        pilots_query = pilots_query.filter(Flight.takeoff_airport_id == airport.id)

    elif page is not None:
        abort(404)

    query = query.filter(Flight.is_rankable())

    query = query.group_by(Flight.year).order_by(Flight.year.desc())

    max_flights = 1
    max_pilots = 1
    max_distance = 1
    max_duration = 1

    sum_flights = 0
    sum_distance = 0
    sum_duration = 0

    if page == 'pilot':
        sum_pilots = 0
    else:
        sum_pilots = pilots_query.scalar()

    list = []
    for row in query:
        row.average_distance = row.distance / row.flights
        row.average_duration = row.duration / row.flights

        list.append(row)

        max_flights = max(max_flights, row.flights)
        max_pilots = max(max_pilots, row.pilots)
        max_distance = max(max_distance, row.distance)
        max_duration = max(max_duration, row.duration.total_seconds())

        sum_flights = sum_flights + row.flights
        sum_distance = sum_distance + row.distance
        sum_duration = sum_duration + row.duration.total_seconds()

    return render_template('statistics/years.jinja',
                           years=list,
                           max_flights=max_flights,
                           max_pilots=max_pilots,
                           max_distance=max_distance,
                           max_duration=max_duration,
                           sum_flights=sum_flights,
                           sum_distance=sum_distance,
                           sum_duration=sum_duration,
                           sum_pilots=sum_pilots,
                           airport=airport,
                           pilot=pilot,
                           club=club)


from typing import Any, Tuple, List
import sys
matx = sys.modules['matx']
from .. import ASYNC, PadWithBorderOp
from ._base import BaseInterfaceClass, BatchBaseClass
from ._common import _torch_padding_mode, _assert

class Pad(BaseInterfaceClass):
    def __init__(self,
                 padding: List[int],
                 fill: List[int] = [0],
                 padding_mode: str = "constant",
                 device_id: int = -2,
                 sync: int = ASYNC) -> None:
        super().__init__(device_id=device_id, sync=sync)
        self._padding: List[int] = padding
        self._fill: List[int] = fill
        self._padding_mode: str = padding_mode

    def __call__(self, device: Any, device_str: str, sync: int) -> Any:
        return PadImpl(device, device_str, self._padding, self._fill, self._padding_mode, sync)

class PadImpl(BatchBaseClass):
    def __init__(self,
                 device: Any,
                 device_str: str,
                 padding: List[int],
                 fill: List[int] = [0],
                 padding_mode: str = "constant",
                 sync: int = ASYNC) -> None:
        super().__init__()
        self.device_str: str = device_str

        if len(padding) == 1:
            self.padding: List[int] = [padding[0]] * 4
        elif len(padding) == 2:
            self.padding: List[int] = [padding[0], padding[1], padding[0], padding[1]]
        elif len(padding) == 4:  # left, top, right, bottom
            self.padding: List[int] = [padding[0], padding[1], padding[2], padding[3]]
        else:
            _assert(
                False,
                "Padding must be an int or a 1, 2, or 4 element tuple, not a {} element tuple".format(
                    len(padding)))

        if len(fill) == 1:
            self.fill: Tuple[int, int, int] = (fill[0], fill[0], fill[0])
        else:
            self.fill: Tuple[int, int, int] = (fill[0], fill[1], fill[2])

        #_assert(padding_mode in _torch_padding_mode_list, "padding_mode not found")

        self.padding_mode: str = _torch_padding_mode(padding_mode)
        self.sync: int = sync
        self.op: PadWithBorderOp = PadWithBorderOp(device, self.fill, self.padding_mode)
        self.name: str = "Pad"

    def _process(self, imgs: List[matx.NDArray]) -> List[matx.NDArray]:
        return self.op(
            imgs, [
                self.padding[1]], [
                self.padding[3]], [
                self.padding[0]], [
                    self.padding[2]], sync=self.sync)

    def __repr__(self) -> str:
        return self.name + '(padding={0}, fill={1}, padding_mode={2}, device={3}, sync={4})'.\
            format(self.padding, self.fill, self.padding_mode, self.device_str, self.sync)


# -*- coding: utf-8 -*-
import json

from flask import url_for
import pytest

from project.models import Translation
import base
LENGTH_ERROR = base.length_error(2, 100)

@pytest.mark.usefixtures('client_class')
class TestTranslations:
    def jwt_header(self, username='test'):
        jwt = base.valid_jwt_token(client=self.client, username=username)
        return jwt

    def test_get_translations(self):
        res = self.client.get(
                url_for('main_api.translations'),
                headers={'Authorization': self.jwt_header()},
                )
        assert res.status_code == 200
        assert b'translation' in res.data
        assert b'date_created' in res.data

    def test_failed_add_translation(self):
        test_data = json.dumps(dict(translation='testing term translation',
                                    term_id=1))
        res = self.client.post(url_for('main_api.translations'),
                               data=test_data,
                               content_type='application/json')
        assert res.status_code == 401

    def test_add_translation(self):
        res = self.client.get(
                              url_for('main_api.term', term='term'),
                              headers={'Authorization': self.jwt_header()},
                              )

        assert b'testing term translation' not in res.data
        test_data = json.dumps(dict(translation='testing term translation',
                                    term_id=1))
        res = self.client.post(url_for('main_api.translations'),
                               data=test_data,
                               headers={'Authorization': self.jwt_header()},
                               content_type='application/json')

        assert b'testing term translation' in res.data.lower()

        assert res.status_code == 201  # Added
        res = self.client.get(url_for('main_api.term',
                              term='term'))
        assert b'testing term translation' in res.data.lower()

    def test_translation_exists(self):
        self.test_add_translation()
        # Add the translation again
        test_data = json.dumps(dict(translation='testing term translation',
                               term_id=1))
        res = self.client.post(url_for('main_api.translations'),
                               data=test_data,
                               headers={'Authorization': self.jwt_header()},
                               content_type='application/json')
        assert res.status_code == 400
        assert b'Translation already exists' in res.data

    # Add translation using parametrization
    @pytest.mark.parametrize('translation,\
            term_id,\
            tags,\
            status_code,\
            message', [
                ('t', 1, None, 400, LENGTH_ERROR),
                ('t'*101, 1, None, 400, LENGTH_ERROR),
                ('testing translation', 3, None, 400, 'Term does not exist'),
                ('testing translation', 1, [], 201, 'testing translation'),
                ('translation1', 1, ['test_tag'], 201, 'translation1'),
                ('testing translation',
                 1, ['testing_tag'], 201,
                 '"tags": [\n                1\n            ]'),
                ('testing translation',
                 1, ['testing_tag', 'tag2'], 201,
                 '[\n                1,\n                2\n            ]'),
        ])
    def test_parametrized_add_translation(self,
                                          translation,
                                          term_id,
                                          tags,
                                          status_code,
                                          message):
        """Test adding a new translation"""
        translation_data = json.dumps(dict(
                                      translation=translation,
                                      term_id=term_id,
                                      tags=tags,
                                      date_created='2018-01-11T15:43:00',
                                      modified_date='2018-01-11T15:43:00'
                                      ))

        res = self.client.post(url_for('main_api.translations'),
                               data=translation_data,
                               headers={'Authorization': self.jwt_header()},
                               content_type='application/json')

        assert res.status_code == status_code
        assert message.encode(encoding='UTF-8') in res.data
        if res.status_code == 201:
            # Test creation and modification dates are read-only
            date_created = res.json['translations'][1]['date_created']
            modified_date = res.json['translations'][1]['modified_date']
            assert date_created != '2018-01-11T15:43:00+00:00'
            assert modified_date != '2018-01-11T15:43:00+00:00'
            # Test translation author
            assert res.json['translations'][1]['author'] == 1

    def test_upvote_translation(self):
        translation = Translation.query.get(1)
        assert translation.score == 1

        res = self.client.get(
                url_for('main_api.upvote_translation', translation_id=1),
                headers={'Authorization': self.jwt_header()},
                content_type='application/json')
        assert res.status_code == 200
        assert res.json['message'] == ('The translation was'
                                       ' successfully upvoted.')

        assert translation.score == 2

        # Unupvote
        res = self.client.get(
                url_for('main_api.upvote_translation', translation_id=1),
                headers={'Authorization': self.jwt_header()},
                content_type='application/json')
        assert res.status_code == 200
        assert res.json['message'] == ('The translation was'
                                       ' successfully unupvoted.')
        assert translation.score == 1

    def test_downvote_translation(self):
        translation = Translation.query.get(1)
        assert translation.score == 1

        res = self.client.get(
                url_for('main_api.downvote_translation', translation_id=1),
                headers={'Authorization': self.jwt_header()},
                content_type='application/json')
        assert res.status_code == 200
        assert res.json['message'] == ('The translation was'
                                       ' successfully downvoted.')

        assert translation.score == 0

        # Undownvote
        res = self.client.get(
                url_for('main_api.downvote_translation', translation_id=1),
                headers={'Authorization': self.jwt_header()},
                content_type='application/json')
        assert res.status_code == 200
        assert res.json['message'] == ('The translation was'
                                       ' successfully undownvoted.')
        assert translation.score == 1

    @pytest.mark.parametrize('translation_id, user, status_code, message', [

        # The user "test" is not an author nor an admin
        # 1 == "translation"
        (1,
         'test',
         401,
         'Deleting requires to be the author or an admin'
         ),

        # "author_translation"
        (2,
         'test',
         401,
         'Deleting requires to be the author or an admin'
         ),

        # "translation" has no author
        (1,
         'author',
         401,
         'Deleting requires to be the author or an admin'
         ),

        # "author_translation" blongs to the user "author"
        (2,
         'author',
         200,
         'The translation was successfully deleted.'
         ),

        # The admin user "admin" doesn't care who added the translation
        (1,
         'admin',
         200,
         'The translation was successfully deleted.'
         ),

        (2,
         'admin',
         200,
         'The translation was successfully deleted.'
         ),
    ])
    def test_delete_translation(self,
                                translation_id,
                                user,
                                status_code,
                                message):
        res = self.client.delete(
                url_for('main_api.delete_translation',
                        translation_id=translation_id),
                headers={'Authorization': self.jwt_header(user)},
                )
        assert res.status_code == status_code
        assert res.json['message'] == message


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Oct  3 09:32:22 2021

@author: phoudayer
"""

import types
import pandas as pd
import numpy  as np
import matplotlib.pyplot as plt
import scipy.stats as st
from scipy.optimize import minimize, curve_fit
from scipy.linalg import block_diag

#============================================================================#
#                                   USETEX                                   #
#============================================================================#
from matplotlib import rc
rc('text', usetex=True)
rc('xtick', labelsize=15)
rc('ytick', labelsize=15)
#============================================================================#

#============================================================================#
#                             DIAGNOSTIC DEFINITION                          #
#============================================================================#
def read_freq(fname, l_max, n_min, n_max):
    '''Return the frequencies contained in fname with
    l <= l_max, n_min <= n <= n_max'''
    return pd.read_csv(
        fname, index_col=0, usecols=range(l_max+2), na_values=-99.9999
    ).loc[n_min:n_max]

def read_freq_cov(fname, l_max, n_min, n_max):
    '''Return the covariance matrices (1 per degree)
    contained in fname with l <= l_max, n_min <= n <= n_max'''
    return np.array([
        np.diag(
            pd.read_csv(
                    fname, index_col=0, usecols=[0,4+l], na_values=-9.9999
                ).loc[n_min:n_max].values.reshape((n_max-n_min+1))**2
            ) for l in range(l_max+1)
        ])

def generate_freq_cov(sig, l_max, n_min, n_max):
    '''Genrerate the covariance matrices (1 per degree)
    using a single dispersion value (sig) with l <= l_max, n_min <= n <= n_max'''
    return np.array(
        [sig**2*np.eye(n_max-n_min+1) for l in range(l_max+1)]
    )

def dk(f, f_cov, k):
    '''Return the k-th differences (and the corresponding covariance matrix)
    of the frequencies f'''
    if k == 0:
        dk_f = f.copy()
        dk_f_cov = f_cov.copy()
        # for l in range(f.shape[1]):
        #     dk_f['l = {}'.format(l)] -= f['l = {}'.format(l)].index.values + l/2
        return dk_f, dk_f_cov
    if k == 1:
        a = [1,0,-1]       # Here we consider centered differences
    if k == 2:
        a = [1,-2,1]

    q = len(a)//2
    dimA = len(f)
    A = sum(
        np.diag(
            np.flip(a)[i]*np.ones(dimA-np.abs(i-q))/2**k, i-q
        ) for i in range(len(a))
    )
    dk_f     = pd.DataFrame(
        np.dot(A, f)[q:-q], index=f.index[q:-q], columns=f.columns
    )
    dk_f_cov = np.array(
        [((A @ f_cov_l) @ A.T)[q:-q,q:-q] for f_cov_l in f_cov]
    )
    return dk_f, dk_f_cov

def plot_diagnostic(f, dk_f, dk_f_cov, dk_f_mod=None, show=False):
    '''Plot the k-th differences as a function of frequency'''
    colors = ['k', 'r', 'b']
    markers = ['v', 'd', '*']
    for l_name, dk_f_cov_l, m_l, c_l in zip(f, dk_f_cov, markers, colors):
        plt.errorbar(
            f.loc[dk_f[l_name].index, l_name], dk_f[l_name],
            yerr=np.diag(dk_f_cov_l)**0.5, fmt=m_l, color=c_l,
            alpha=0.2, label=r"$\ell = "+l_name[-1]+"$"
        )
    if dk_f_mod is not None:
        resolution = len(dk_f_mod)
        all_f = np.array(f).flatten()
        ordered = np.argsort(all_f)
        f_long = np.linspace(all_f[ordered][0], all_f[ordered][-1], resolution)
        plt.plot(f_long, dk_f_mod, 'k-', alpha = 0.5, label="Model")
    plt.legend()
    if show: plt.show()
#============================================================================#

#============================================================================#
#                               FITTING FUNCTIONS                            #
#============================================================================#
def M94a(f, a, tau, phi):
    '''Expression of the frequency shift caused by the base of the convection
    zone (BCZ) in an overshoot model derived in Monteiro et al. (1994) and
    reused in Vrard et al. (2015)'''
    return (a/f) * np.cos(2*np.pi*f*tau+phi)

def M94b(f, a, tau, phi):
    '''Expression of the frequency shift caused by the base of the convection
    zone (BCZ) in a non-overshoot model derived in Monteiro et al. (1994) and
    reused in Vrard et al. (2015) and Dréau et al. (2021)'''
    return (a/f**2) * np.cos(2*np.pi*f*tau+phi)

def MT98(f, a, b, tau, phi):
    '''Expression of the frequency shift caused by the 2nd He ionisation
    derived in Monteiro & Thompson (1998) and used in Verma et al. (2014a)'''
    return a * np.sin(np.pi*f*b)**2/(np.pi*f*b) * np.cos(2*np.pi*f*tau+phi)

def HG07(f, a, b, tau, phi):
    '''Expression of the frequency shift caused by the 2nd He ionisation
    derived in Houdek & Gough (2007)
    This expression were also applied to the second differences fit in
    Verma et al. (2014a, 2019) and adapted in Farnir et al. (2019)'''
    return (a*f) * np.exp(-(b*f)**2) * np.cos(2*np.pi*f*tau+phi)

def V15(f, a, tau, phi):
    '''Expression of the frequency shift caused by the 2nd He ionisation
    used in Vrard et al. (2015)'''
    return a * np.cos(2*np.pi*f*tau+phi)

def Offset(f, a0):
    '''Just an offset to model the smooth component'''
    return a0

def Inverse_polynomial(f, a0, a1, a2, a3):
    '''Expression of the smooth component introduced in Houdek & Gough (2007)'''
    return a0 + a1*f**-1 + a2*f**-2 + a3*f**-3

def Polynomial(f, a0, a1, a2):
    '''Expression of the smooth component introduced in Verma et al. (2014)'''
    return a0 + a1*f**1 + a2*f**2

def Asymptotic(k, f, a0, a1):
    '''Expression of the smooth component derived of the asymptotic
    expansion presented in Houdek & Gough (2011).
    For each k-th differences, we kept only the most important terms.'''
    if k == 1:
        return 1 + a0*f**-2 + a1*f**-4
    if k == 2:
        return 0 + a0*f**-3 + a1*f**-5

def arg_types(func):
    'Argument types of func for prior construction'
    if func == M94a:
        return ['scale', 'depth', 'phase']
    if func == M94b:
        return ['scale', 'depth', 'phase']
    if func == MT98:
        return ['scale', 'scale', 'depth', 'phase']
    if func == HG07:
        return ['scale', 'scale', 'depth', 'phase']
    if func == V15:
        return ['scale', 'depth', 'phase']
    if func == Offset:
        return ['scale']
    if func == Inverse_polynomial:
        return ['scale', 'scale', 'scale', 'scale']
    if func == Polynomial:
        return ['scale', 'scale', 'scale']
    if (func == Asymptotic or type(func) is types.LambdaType):
        return ['scale', 'scale']
#============================================================================#

#============================================================================#
#                              POSTERIOR DEFINITION                          #
#============================================================================#
def log_prior_on_scale(par):
    '''Return Jeffrey's prior on scale'''
    return -np.log(np.abs(par))

def log_prior_on_depth(par, m, std):
    '''Return the Beta districution of mean m and standard deviation std'''
    a =     m*(m*(1-m)/std**2-1)
    b = (1-m)*(m*(1-m)/std**2-1)
    return st.beta(a, b).logpdf(par)

def log_prior_on_phase(par):
    '''Return Jeffrey's prior on phase'''
    return 0.0

def first_guess(func, fname):
    types = arg_types(func)
    x0 = []
    for kind in types:
        if kind == 'scale' :
            if 'RGB' in fname:
                x0.append(0.5)
            elif 'MS' in fname:
                x0.append(0.1)
            else :
                x0.append(0.1)
        if kind == 'depth' :
            if 'RGB' in fname:
                x0.append(0.5)
            elif 'MS' in fname:
                x0.append(0.3)
            else :
                x0.append(0.3)
        if kind == 'phase' :
            if 'RGB' in fname:
                x0.append(0.0)
            elif 'MS' in fname:
                x0.append(0.0)
            else :
                x0.append(0.0)
    return np.array(x0)

def log_prior(func, *args):
    types = arg_types(func)
    logp = []
    for kind, par in zip(types, args):
        if kind == 'scale' :
            logp.append(log_prior_on_scale(par))
        if kind == 'depth' :
            logp.append(log_prior_on_depth(par, 0.25, 0.1))
        if kind == 'phase' :
            logp.append(log_prior_on_phase(par))
    logp = np.sum(logp)
    print(logp)
    return logp

def log_likelihood(f, dk_f, dk_f_cov, func, *args):
    '''The likelihood function is calculated assuming a
    Gaussian distribution on the diagnostic dk_f with
    covariance matrix dk_f_cov'''
    logl = 0.0
    for l_name, dk_f_cov_l in zip(f, dk_f_cov):
        dk_f_mod_l = func(f.loc[dk_f[l_name].index, l_name], *args)
        logl += st.multivariate_normal(dk_f_mod_l, dk_f_cov_l).logpdf(dk_f[l_name])
    print(logl)
    print('')
    return logl

def log_posterior(f, dk_f, dk_f_cov, func, *args):
    logp = log_prior(func, *args)
    logl = log_likelihood(f, dk_f, dk_f_cov, func, *args)
    return logp + logl
#============================================================================#

#============================================================================#
#                                 MAIN SCRIPT                                #
#============================================================================#
if __name__=='__main__':
    # Name of the file containing the frequencies
    fname = 'freq1.csv'

    # Maximum degree (<4) and radial orders considered
    l_max = 2
    n_min = 10
    n_max = 40

    # We consider a particular set of radial order to avoid NaNs
    # in the specific case of frequencies extracted from data
    if fname == 'freq_KIC_6277741_RGB.csv':
        n_min = 5
        n_max = 9
    if fname == 'freq_KIC_8379927_MS.csv':
        n_min = 16
        n_max = 26

    # We read the frequencies in fname
    freq = read_freq(fname, l_max, n_min, n_max)

    # We define a covariance matrix
    if 'KIC' in fname:
        freq_cov = read_freq_cov(fname, l_max, n_min, n_max)
    else:
        # We naively asssume here that all degrees l share the same covariance matrix
        sig = 1e-3    # This means sigma(\nu)/\Delta\nu ~ 0.001 for all frequencies
        freq_cov = generate_freq_cov(sig, l_max, n_min, n_max)

    # Diagnostic considered (d^k nu = k^th differences)
    k = 2                          # Different options: 0, 1, 2
    dk_freq, dk_freq_cov = dk(freq, freq_cov, k)

    # Definition of a model
    glitch = HG07                   # Different options: M94a, M94b, MT98, HG07, V15
    smooth = Inverse_polynomial    # Different options: Offset, Polynomial, Inverse_polynomial
    # smooth = lambda f, a, b: Asymptotic(k, f, a, b)
    model  = lambda f, *params: glitch(f, *params[:glitch.__code__.co_argcount-1]) \
                              + smooth(f, *params[glitch.__code__.co_argcount-1:])

    # Merging frequencies, diagnostics and covariance matrices of all degrees
    all_freq = np.array(freq.loc[dk_freq.index]).flatten()
    all_dk_freq = np.array(dk_freq).flatten()
    all_dk_freq_cov = block_diag(*dk_freq_cov)
    ordered = np.argsort(all_freq)

    # Initial guess for our model
    x0 = np.concatenate(
        (first_guess(glitch, fname), first_guess(smooth, fname))
    )
    maxfev = int(1e5)   # This option determine the maximum number of curvefit iterations
    Two_fits = True     # This option allows a first fit to determine a first guess

    if Two_fits:
        # Fit of the smooth component alone
        p_smooth, p_smooth_cov = curve_fit(
            smooth, all_freq[ordered], all_dk_freq[ordered],
            p0=first_guess(smooth, fname), sigma=all_dk_freq_cov[ordered],
            absolute_sigma=True, maxfev=maxfev
        )
        residuals = all_dk_freq[ordered] - smooth(all_freq[ordered], *p_smooth)

        # Fit of the residuals using the glitch model
        p_glitch, p_glitch_cov = curve_fit(
            glitch, all_freq[ordered], residuals,
            p0=first_guess(glitch, fname), sigma=all_dk_freq_cov[ordered],
            absolute_sigma=True, maxfev=maxfev
        )

        # The best solution is then used as a first guess for the complete fit (smooth + glitch)
        x0 = np.concatenate((p_glitch, p_smooth))

    # Fit of the complete model
    p_mod, p_mod_cov = curve_fit(
        model, all_freq[ordered], all_dk_freq[ordered],
        p0=x0, sigma=all_dk_freq_cov[ordered],
        absolute_sigma=True, maxfev=maxfev
    )

    print('Best parameter set : ', *zip(
        np.concatenate(
            (glitch.__code__.co_varnames[1:], smooth.__code__.co_varnames[1:])
        ), np.round(p_mod, 5)
    ))
    resolution = 1000
    freq_long = np.linspace(all_freq[ordered][0], all_freq[ordered][-1], resolution)
    dk_freq_mod = model(freq_long, *p_mod)

    # Chi2 estimate
    residuals = all_dk_freq[ordered] - model(all_freq[ordered], *p_mod)
    print(
        'Chi2 = ', ((residuals.T @ np.linalg.inv(all_dk_freq_cov[ordered])) @ residuals)
        / (len(residuals)-model.__code__.co_argcount)
    )

    # Comparison of the fitted expression with the data
    plot_diagnostic(freq, dk_freq, dk_freq_cov, dk_freq_mod, show=True)

    # # Definition of a cost function
    # cost_func = lambda params: - log_prior(glitch, *params[:glitch.__code__.co_argcount-1]) \
    #                             - log_prior(smooth, *params[glitch.__code__.co_argcount-1:]) \
    #                             - log_likelihood(freq, dk_freq, dk_freq_cov, model, *params)

    # # Minimisation using a log posterior function
    # res = minimize(cost_func, x0, method='Powell', tol=1e-4, options={'maxiter': 1000, 'apdative':True})
    # print('Best parameter set : ', *zip(np.concatenate((glitch.__code__.co_varnames[1:],
    #                                                     smooth.__code__.co_varnames[1:])),
    #                                     np.round(res.x, 3)))
    # dk_freq_mod = model(freq, *res.x)
    # plot_diagnostic(freq, dk_freq, dk_freq_cov, dk_freq_mod, show=True)

#============================================================================#


from anytree import Node, RenderTree
from pickpack import pickpack

title = 'Please choose your favorite fruit: '
options = [
    { 'name': 'Apples', 'grow_on': 'trees' },
    { 'name': 'Oranges', 'grow_on': 'trees' },
    { 'name': 'Strawberries', 'grow_on': 'vines' },
    { 'name': 'Grapes', 'grow_on': 'vines' },
]

def get_description_for_display(option):
    # format the option data for display
    return Node('{0} (grow on {1})'.format(option.get('name'), option.get('grow_on')))

option, index = pickpack(options, title, indicator='=>', options_map_func=get_description_for_display)
print(option, index)


import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras import models
from tensorflow.keras import backend as K
import horovod.tensorflow.keras as hvd
#import horovod.tensorflow as hvd_tf

import numpy as np
import argparse
import math
import time

from cifar import load_cifar
import custom_callbacks

# Horovod: initialize Horovod.
hvd.init()

parser = argparse.ArgumentParser()
parser.add_argument('--epochs', type=int, default=10, help="epochs by GPU")
parser.add_argument('--batch_size', type=int, default=2048)
parser.add_argument('--learning_rate', type=float, default=0.01)

args = parser.parse_args()
batch_size = args.batch_size
epochs = args.epochs
# Horovod: modified learning rate
lr = args.learning_rate * hvd.size()

gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)
if gpus:
    tf.config.experimental.set_visible_devices(gpus[hvd.local_rank()], 'GPU')

train_ds, test_ds = load_cifar(batch_size)

model = tf.keras.applications.resnet50.ResNet50(include_top=True, weights=None,
            input_shape=(32, 32, 3), classes=10)

opt = tf.keras.optimizers.SGD(lr)
opt = hvd.DistributedOptimizer(opt)

model.compile(loss='categorical_crossentropy',
              optimizer=opt,
              experimental_run_tf_function=False,
              metrics=['accuracy'])

time_callback = custom_callbacks.TimeHistory()
avg_cb = custom_callbacks.MetricAverageCallback()

# Horovod: broadcast initial variable states from rank 0 to all other processes.
# This is necessary to ensure consistent initialization of all workers when
# training is started with random weights or restored from a checkpoint.
callbacks = [hvd.callbacks.BroadcastGlobalVariablesCallback(0),
             time_callback,
             avg_cb]

model.fit(train_ds,
          steps_per_epoch=math.ceil(50000/batch_size),
          epochs=epochs,
          verbose=0,
          callbacks=callbacks
          )

if hvd.rank() == 0:
    times = avg_cb.reduced_time
# tentative code version SA-MIRI Lab8
    print("TIME: ", times)
    print("Average time: ", sum(times)/len(times))
    print("Average time without epoch 1: ", sum(times[1:])/len(times[1:]))


"""
the key is full binary tree
it must be 2^n - 1

1 cannot (1 can)
2 cannot
4 cannot

divided into 3 parts
1 root
left 2^i - 1
right 2^j - 1

ah no..
5 can, so not 2^n - 1
2*n - 1???

"""

# Definition for a binary tree node.
from typing import List, Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
        if n%2==0:
            return None

        def build(start, end):
            if start == end:
                return TreeNode()

            res = []
            for idx in range(start+1, end, 2):
                lefts = build(start, idx-1)
                rights = build(idx+1, end)

                for left in lefts:
                    for right in rights:
                        res.append(TreeNode(0,left,right))
            return res
        return build(1,n)


# -*- coding: utf-8 -*-
"""
Created on Tue Mar 1 18:51:22 2022

@author: suraj
"""
import streamlit as st
from streamlit_cropper import st_cropper
import numpy as np
import cv2
from  PIL import Image, ImageEnhance
from urllib.request import urlopen
import os
import base64
import io
from io import BytesIO

Output_image = 500

def main():

    @st.cache
    def load_image(url):
        with urlopen(url) as response:
            image = np.asarray(bytearray(response.read()), dtype="uint8")
        image = cv2.imdecode(image, cv2.IMREAD_COLOR)
        image = image[:, :, [2, 1, 0]] # BGR -> RGB
        return image

    image = load_image('https://raw.githubusercontent.com/rafaelgrecco/Filter-Selector/master/Images/placeholder.jpg')
    image = Image.fromarray(image)
    st.title('SnapEdit')
    st.sidebar.title('Sidebar')

    menu = ['Filters','Image Corrections','Tools', 'Information']
    op = st.sidebar.selectbox('Option', menu)
    if op=='Tools':
        st.set_option('deprecation.showfileUploaderEncoding', False)

    # Upload an image and set some options for demo purposes

        img = st.file_uploader('Upload an image', type=['jpg', 'png', 'jpeg'])

        realtime_update = st.sidebar.checkbox(label="Update in Real Time", value=True)
        box_color = st.sidebar.color_picker(label="Box Color", value='#0000FF')
        aspect_choice = st.sidebar.radio(label="Aspect Ratio", options=["1:1", "16:9", "4:3", "2:3", "Free"])
        aspect_dict = {
            "1:1": (1, 1),
            "16:9": (16, 9),
            "4:3": (4, 3),
            "2:3": (2, 3),
            "Free": None
        }
        aspect_ratio = aspect_dict[aspect_choice]

        if img:
            img = Image.open(img)
            if not realtime_update:
                st.write("Double click to save crop")
        # Get a cropped image from the frontend
            cropped_img = st_cropper(img, realtime_update=realtime_update, box_color=box_color,
                                    aspect_ratio=aspect_ratio)

        # Manipulate cropped image at will
            st.write("Preview")
            _ = cropped_img.thumbnail((150,150))
            st.image(cropped_img)

    if op == 'Filters':

        img = st.file_uploader('Upload an image', type=['jpg', 'png', 'jpeg'])

        if img is not None:
            image = Image.open(img)
            st.sidebar.text('Original Image')
            st.sidebar.image(image, width=200)

        filters = st.sidebar.radio('Filters', ['Original','Grayscale', 'Sepia', 'Blur', 'Contour', 'Sketch'])

        if filters == 'Grayscale':
            img_convert = np.array(image.convert('RGB'))
            gray_image = cv2.cvtColor(img_convert, cv2.COLOR_RGB2GRAY)
            st.image(gray_image, width=Output_image)

        elif filters == 'Sepia':
            img_convert = np.array(image.convert('RGB'))
            img_convert = cv2.cvtColor(img_convert, cv2.COLOR_RGB2BGR)
            kernel = np.array([[0.272, 0.534, 0.131],
                            [0.349, 0.686, 0.168],
                            [0.393, 0.769, 0.189]])
            sepia_image = cv2.filter2D(img_convert, -1, kernel)
            st.image(sepia_image, channels='BGR', width=Output_image)

        elif filters == 'Blur':
            img_convert = np.array(image.convert('RGB'))
            slide = st.sidebar.slider('Quantidade de Blur', 3, 81, 9, step=2)
            img_convert = cv2.cvtColor(img_convert, cv2.COLOR_RGB2BGR)
            blur_image = cv2.GaussianBlur(img_convert, (slide,slide), 0, 0)
            st.image(blur_image, channels='BGR', width=Output_image)

        elif filters == 'Contour':
            img_convert = np.array(image.convert('RGB'))
            img_convert = cv2.cvtColor(img_convert, cv2.COLOR_RGB2BGR)
            blur_image = cv2.GaussianBlur(img_convert, (11,11), 0)
            canny_image = cv2.Canny(blur_image, 100, 150)
            st.image(canny_image, width=Output_image)

        elif filters == 'Sketch':
            img_convert = np.array(image.convert('RGB'))
            gray_image = cv2.cvtColor(img_convert, cv2.COLOR_RGB2GRAY)
            inv_gray = 255 - gray_image
            blur_image = cv2.GaussianBlur(inv_gray, (25,25), 0, 0)
            sketch_image = cv2.divide(gray_image, 255 - blur_image, scale=256)
            st.image(sketch_image, width=Output_image)
        else:
            st.image(image, width=Output_image)

    if op == 'Image Corrections':

        img = st.file_uploader('Upload an image', type=['jpg', 'png', 'jpeg'])

        if img is not None:
            image = Image.open(img)
            st.sidebar.text('Original Image')
            st.sidebar.image(image, width=200)

        MImage = st.sidebar.radio('Image enhancement', ['Original', 'Contrast', 'brightness', 'Sharpness'])

        if MImage == 'Contrast':
            slide = st.sidebar.slider('Contrast', 0.0, 2.0, 1.0)
            enh = ImageEnhance.Contrast(image)
            contrast_image = enh.enhance(slide)
            st.image(contrast_image, width=Output_image)

        elif MImage == 'brightness':
            slide = st.sidebar.slider('brightness', 0.0, 5.0, 1.0)
            enh = ImageEnhance.Brightness(image)
            brightness_image = enh.enhance(slide)
            st.image(brightness_image, width=Output_image)

        elif MImage == 'Sharpness':
            slide = st.sidebar.slider('Sharpness', 0.0, 2.0, 1.0)
            enh = ImageEnhance.Sharpness(image)
            sharpness_image = enh.enhance(slide)
            st.image(sharpness_image, width=Output_image)
        else:
            st.image(image, width=Output_image)

    elif op == 'Information':
        st.subheader('Project by aditya,mayur,sachin,suraj')

if __name__ == '__main__':
    main()

hide_streamlit_style = """
            <style>
            #MainMenu {visibility: hidden;}
            footer {

    visibility: hidden;

    }
footer:after {
    content:'made by acpceians';
    visibility: visible;
    display: block;
    position: relative;
    #background-color: red;
    padding: 5px;
    top: 2px;
}
            </style>
            """
st.markdown(hide_streamlit_style, unsafe_allow_html=True)


from __init__ import *

from discord.ext import commands
import discord
from numpy import nan
import datetime as dt
import plotly.graph_objects as go
import tweepy
from wol_bot_static import token, teams, ha, pred_cols, twitter_apikey, twitter_secret_apikey, \
    twitter_access_token, twitter_secret_access_token, poll_channel, help_brief, help_desc
import asyncio
from random import randrange
from SG2 import Player, Club, XI, claim, TEMP_CLUB

# token - Discord bot token
# teams - dictionary for converting team code to full team name
# ha    - dictionary for converting h to home and a to away
# pred_ - columns for prediction data

# prediction league functions
def game_result(wolves, opp):
    if(wolves > opp):
        return "wolves"
    elif(opp > wolves):
        return "opp"
    else:
        return "draw"

def make_ordinal(n):
    '''
    Convert an integer into its ordinal representation::

        make_ordinal(0)   => '0th'
        make_ordinal(3)   => '3rd'
        make_ordinal(122) => '122nd'
        make_ordinal(213) => '213th'
    '''
    n = int(n)
    suffix = ['th', 'st', 'nd', 'rd', 'th'][min(n % 10, 4)]
    if 11 <= (n % 100) <= 13:
        suffix = 'th'
    return str(n) + suffix

def refresh_scores():
    pred = pd.read_csv('data_wol/predictions.csv')
    results = pd.read_csv('data_wol/results.csv')

    #get games that need their point values to be updated
    update = pred[pred['pts'].isnull()]

    for index, row in update.iterrows():
        game = results[(results['game'] == row['game']) & (results['opp_score'].notnull())]

        #if game has been played and has a result, add the points, otherwise pass
        if game.shape[0] > 0:
            total_pts = 0
            ind = min(list(game.index))
            if (game['opp_score'][ind] == row['opp_score']):
                total_pts += 1

            if (game['wolves'][ind] == row['wolves']):
                total_pts += 1

            if (game_result(game['wolves'][ind], game['opp_score'][ind]) == game_result(row['wolves'], row['opp_score'])):
                total_pts += 2

            pred.at[index, 'pts'] = int(total_pts)

    pred.to_csv('data_wol/predictions.csv', index=False)

# poll functions
def get_poll_info(polls, code):
    return polls[polls["code"] == code.lower()]

def get_user_responses(responses, code, author):
    return responses[(responses["user"] == str(author)) & (responses["code"] == code)]

def get_poll_results(responses, polls, code):
    poll = get_poll_info(polls, code)
    poll_responses = responses[responses["code"] == code]["response"].value_counts(normalize=True)
    msg = "Results:\n**{}**\n```".format(poll["poll"].iloc[0])
    other = 0
    for i in range(len(poll_responses)):
        if i <= 4:
            msg += "{:18.15}  {:.1f}%\n".format(poll_responses.index[i], poll_responses[i] * 100)
        else:
            other += poll_responses[i]
    if other > 0:
        msg += "{:18.15}  {:.1f}%```".format("other", other * 100)
    else:
        msg += "```"
    return msg

def add_polls_row(polls, code, poll, limit):
    nr = pd.DataFrame({"code": code, "poll": poll, "vote_limit": limit, "open": 1}, index=[0])
    pd.concat([nr, polls]).reset_index(drop=True).to_csv('data_wol/polls.csv', index=False)

def add_responses_row(responses, code, response, author):
    nr = pd.DataFrame({"code": code, "response": response, "user": author}, index=[0])
    pd.concat([nr, responses]).reset_index(drop=True).to_csv("data_wol/poll_responses.csv", index=False)

def poll_code_exists(polls, code):
    return code in polls['code'].unique()

def clean_mentions_str(mention):
    return mention.replace("<", "").replace(">", "").replace("@", "").replace("!", "")

async def make_sg_table(df_table):
    df_table["ppg"] = df_table["pts"] / (df_table["w"] + df_table["l"] + df_table["d"])
    df_table["ppg"] = [round(x, 2) for x in df_table["ppg"]]
    df_table.sort_values(by=["elo", "ppg", "gd"], ascending=(False, False, False), inplace=True)
    df_table["rank"] = range(1, len(df_table) + 1)
    df_table.set_index("rank", inplace=True)
    df_table.columns = ["User", "Wins", "Losses", "Draws", "  GF  ", "  GA  ", "  GD  ", "  Pts  ", "  ELO  ", "  PPG  "]
    df_table[["Wins", "Losses", "Draws", "  GF  ", "  GA  ", "  GD  ", "  Pts  ", "  ELO  "]] = df_table[["Wins", "Losses", "Draws", "  GF  ", "  GA  ", "  GD  ", "  Pts  ", "  ELO  "]].astype(int)
    df_table["User"] = [await bot.fetch_user(int(id)) for id in df_table["User"]]
    df_table["User"] = [id.name for id in df_table["User"]]
    ax = plt.subplot(911, frame_on=False)  # no visible frame
    ax.xaxis.set_visible(False)  # hide the x axis
    ax.yaxis.set_visible(False)  # hide the y axis
    tbl = table(ax, df_table)  # where df is your data frame
    tbl.auto_set_font_size(False)
    tbl.set_fontsize(10)
    tbl.auto_set_column_width(col=list(range(df_table.shape[1])))
    plt.savefig('data_wol/sg_table.png')
    ax.clear()

def update_sg_table(df_table, user, res, gf, ga, pts, sort=False):
    # TODO: Add ELO ratings
    if user in df_table["user"].values:
        print("user found")
        row = df_table[df_table["user"] == user].iloc[0]
        row.update(pd.Series([
            row[res] + 1,
            row["gf"] + gf,
            row["ga"] + ga,
            row["pts"] + pts
        ], index=[res, "gf", "ga", "pts"]))
        df_table.loc[row.name] = row
    else:
        print("user not found")
        temp = pd.Series([len(df_table) + 1, str(user), 0, 0, 0, 0, 0, 0, 0, 1500], index=df_table.columns)
        df_table = df_table.append(temp, ignore_index=True)
        row = df_table[df_table["user"] == user].iloc[0]
        row.update(pd.Series([
            row[res] + 1,
            row["gf"] + gf,
            row["ga"] + ga,
            row["pts"] + pts
        ], index=[res, "gf", "ga", "pts"]))
        df_table.loc[row.name] = row

    if sort:
        df_table["gd"] = df_table["gf"] - df_table["ga"]
        df_table["ppg"] = df_table["pts"] / (df_table["w"] + df_table["d"] + df_table["l"])
        df_table.sort_values(by=["elo", "ppg", "gd"], ascending=False, inplace=True)
        df_table.drop("ppg", axis=1, inplace=True)
        df_table["rank"] = range(1, len(df_table) + 1)

    return df_table

def check_if_open(user1, user2):
    try:
        with open('data_wol/sg_open.json', 'r', encoding='utf-8') as f:
            comp_open = json.load(f)
        return comp_open[user1] == "open" and comp_open[user2] == "open"
    except:
        return False

def update_elo(df_table, user1, user2, result):
    if result == ("w", "l"):
        res = (1, 0)
    elif result == ("l", "w"):
        res = (0, 1)
    else:
        res = (0.5, 0.5)
    row1 = df_table[df_table["user"] == user1].iloc[0]
    row2 = df_table[df_table["user"] == user2].iloc[0]
    elo1 = int(row1["elo"])
    elo2 = int(row2["elo"])
    t1_trans = 10 ** (elo1 / 400)
    t2_trans = 10 ** (elo2 / 400)
    t1_exp = t1_trans / (t1_trans + t2_trans)
    t2_exp = t2_trans / (t1_trans + t2_trans)
    expected = (t1_exp, t2_exp)
    K = 16
    row1["elo"] = int(elo1 + K * (res[0] - expected[0]))
    row2["elo"] = int(elo2 + K * (res[1] - expected[1]))
    df_table.loc[row1.name] = row1
    df_table.loc[row2.name] = row2
    return df_table

#refresh scores on startup
refresh_scores()

intents = discord.Intents.default()
intents.members = True
bot = commands.Bot(intents=intents, command_prefix='$')

sg_table_loc = "data_wol/sg_table_bronze.csv"

@bot.event
async def on_ready():
    print('We have logged in as {0.user}'.format(bot))

@bot.command(brief=help_brief["ping"], description=help_desc["ping"])
async def ping(ctx):
    latency = bot.latency
    await ctx.send(latency)

# prediction table commands

@bot.command(brief=help_brief["score"], description=help_desc["score"])
async def score(ctx, game, score):
    results_score = pd.read_csv('data_wol/results.csv')
    pred_score = pd.read_csv('data_wol/predictions.csv')

    #get data
    author = str(ctx.message.author)
    score_parts = score.split('-') #command will have wolves score first and opp score second

    #check if game exists
    exists_v = results_score['game'].str.contains(game)
    exists = (exists_v.sum()) > 0

    if exists:
        date = results_score[results_score['game'] == game]['date']
        time = results_score[results_score['game'] == game]['time']
        fixture = dt.datetime.strptime('{} {}'.format(date[min(date.index)], time[min(time.index)]), '%m/%d/%Y %H:%M')

        #if (fixture < dt.datetime.now()):
        #    message = "It's too late to predict {} {}.".format(teams[game[0:2]], ha[game[2]])
        #else:

        nrow = [author, game, score_parts[1], score_parts[0], nan]  # data has opp first, wolves second

        #overwrite if exists
        overwrite_check = pred_score[(pred_score['user'] == author) & (pred_score['game'] == game)]
        if overwrite_check.shape[0] == 1:
            pred_score.loc[list(overwrite_check.index)[0]] = nrow
        else:
            pred_score = pred_score.append(pd.DataFrame([nrow], columns=pred_cols), ignore_index=True)

        pred_score.to_csv('data_wol/predictions.csv', index=False)
        message = "Score recorded! You predicted Wolves {}, {} {}.".format(score_parts[0], teams[game[:-1]], score_parts[1])
    else:
        nexts = results_score[results_score['wolves'].isnull()]['game']
        next = nexts[min(nexts.index)]
        message = "Please enter prediction for the next match {} {} with game code '{}'.".format(teams[next[0:2]], ha[next[2]], next)

    await ctx.send(message)

@bot.command(brief=help_brief["format"], description=help_desc["format"])
async def format(ctx):
    results_format = pd.read_csv('data_wol/results.csv')
    nexts = results_format[results_format['wolves'].isnull()]['game']
    next = nexts[min(nexts.index)]
    message = "Command should be formatted as '$score GAMECODE WOLSCORE-OPPSCORE'. Example, '$score mch 2-1' where 'mch' " \
              "translates to 'Manchester City Home'. Next match is {} {} with a game code of '{}'.\n\nScoring is as follows:"\
              "\n2 pts for the correct result\n1 pt for each correct goal total.".format(teams[next[0:2]], ha[next[2]], next)
    await ctx.message.author.send(message)

@bot.command(hidden=True)
async def short_lb(ctx):
    pred_lb = pd.read_csv('data_wol/predictions.csv')
    lb = pred_lb.groupby(['user']).sum().sort_values(by=['pts'], ascending=False).reset_index()
    top_5 = lb.nlargest(5, 'pts')
    user = lb[lb['user'] == str(ctx.author)]
    message = '```  Rank  |       User       |  Pts  \n'
    for index, row in top_5.iterrows():
        message += '{:^8}|{:^18}|{:^7}\n'.format(make_ordinal(index + 1), row['user'].split('#')[0], int(row['pts']))
    message += '...\n{:^8}|{:^18}|{:^7}```'.format(make_ordinal(list(user.index)[0] + 1), list(user['user'])[0].split('#')[0],
                                              int(list(user['pts'])[0]))
    await ctx.send(message)

@bot.command(hidden=True)
async def leaderboard(ctx):
    full_pred_lb = pd.read_csv('data_wol/predictions.csv')
    full_lb = full_pred_lb.groupby(['user']).sum().sort_values(by=['pts'], ascending=False).reset_index()
    user_list = [x.split('#')[0] for x in list(full_lb['user'])]

    files = []

    for i in range(math.ceil(len(user_list) / 20)):
        if i * 20 < len(user_list):
            temp_full_lb = full_lb[(i * 20):((i + 1) * 20)]
            temp_user_list = user_list[(i * 20):((i + 1) * 20)]
        else:
            temp_full_lb = full_lb[(i * 20):len(full_lb)]
            temp_user_list = user_list[(i * 20):len(user_list)]
        layout = go.Layout(autosize=True, margin = {'l': 0, 'r': 0, 't': 0, 'b': 0} )
        fig = go.Figure(layout=layout, data=[go.Table(columnwidth=[10, 15, 10],
                                       header=dict(values=['Rank', 'User', 'Points'], font=dict(color='black', size=12),
                                                   height=(500 / (temp_full_lb.shape[0] + 1))),
                                       cells=dict(
                                           values=[list(range((i * 20) + 1, ((i + 1) * 20) + 1)), temp_user_list, list(temp_full_lb['pts'])],
                                           font=dict(color='black', size=11), height= (500 / (temp_full_lb.shape[0] + 1))))
                              ])
        fig.update_layout(width=350, height=700) #(25 * (full_lb.shape[0] + 2))
        fig.write_image("data_wol/table{}.png".format(i))
        files.append("data_wol/table{}.png".format(i))

    await asyncio.wait([ctx.send(file=discord.File(f)) for f in files])

@bot.command(hidden=True)
async def refresh(ctx):
    refresh_scores()
    await ctx.send('Scores have been updated.')

# fa cup

@bot.command()
async def confirm_fa(ctx):
    confirms = pd.read_csv("data_wol/fa_confirmed.csv")
    if ctx.author.id in set(confirms["id"]):
        await ctx.send('You are already registered.')
    else:
        confirms = confirms.append(pd.DataFrame([[ctx.author.id, "confirmed"]], columns=["id","confirmed"]), ignore_index=True)
        confirms.to_csv("data_wol/fa_confirmed.csv", index=False)
        await ctx.send('You are confirmed for the upcoming Wolves Prediction FA Cup.')

@bot.command(hidden=True, pass_context=True)
async def nextround(ctx):
    matchups = pd.read_csv("data_wol/matchups.csv")
    comp = json.load(open('data_wol/comp.json'))
    confirms = pd.read_csv("data_wol/fa_confirmed.csv")
    confirms_list = list(set(confirms["id"]))

    if comp["tot"] == comp["done"]:
        champ = list(set(matchups[matchups["round"] == comp["done"]]["winner"]))[0]
        user = bot.get_user(int(champ))
        print("Tourney is over! Congrats {}".format(user))

    elif comp["name"] == "none":

        # start comp
        #
        # is this a general formula? no because confirms go away after qualifier

        all_mems = [member.id for member in ctx.guild.members]
        tot_mems = len(all_mems)

        comp["name"] = "facup"
        comp["tot"] = math.ceil(math.log(tot_mems,2))
        comp["quals"] = comp["tot"] - 7 if comp["tot"] > 7 else 0
        comp["done"] = 1
        comp["status"] = "open"

        rd = comp["done"]
        bye = ((2 ** (comp["tot"] - rd)) * 2) - tot_mems
        print(bye)

        while bye > 0:
            if len(confirms_list) > 0:
                conf_bye = confirms_list.pop(randrange(len(confirms_list)))
                all_mems.remove(conf_bye)
                matchups = matchups.append(pd.DataFrame([[rd, conf_bye, -1, "", "bye", conf_bye]],
                                              columns=list(matchups.columns)), ignore_index=True)
            else:
                reg_bye = all_mems.pop(randrange(len(all_mems)))
                matchups = matchups.append(pd.DataFrame([[rd, reg_bye, -1, "", "bye", reg_bye]],
                                                        columns=list(matchups.columns)), ignore_index=True)
            bye -= 1

        while len(all_mems) > 1:
            home = all_mems.pop(randrange(len(all_mems)))
            away = all_mems.pop(randrange(len(all_mems)))
            matchups = matchups.append(pd.DataFrame([[rd, home, away, "", "", ""]],
                                                    columns=list(matchups.columns)), ignore_index=True)

        if len(all_mems) > 0:
            reg_bye = all_mems.pop(randrange(len(all_mems)))
            matchups = matchups.append(pd.DataFrame([[rd, reg_bye, -1, "", "bye", reg_bye]],
                                                    columns=list(matchups.columns)), ignore_index=True)

        print(matchups[matchups["round"] == 1].shape[0])
        matchups.to_csv("data_wol/matchups.csv", index=False)
        with open('data_wol/comp.json', 'w', encoding='utf-8') as f:
            json.dump(comp, f, ensure_ascii=False, indent=4)
        #pd.DataFrame(columns=["id","confirmed"]).to_csv("data_wol/fa_confirmed.csv", index=False)

    else:
        print("match-ups for round > 1")
        matchups = pd.read_csv("data_wol/matchups.csv")
        comp = json.load(open('data_wol/comp.json'))
        qual = comp["quals"] < comp["done"]
        confirms_list = []
        if qual:
            confirms = pd.read_csv("data_wol/fa_confirmed.csv")
            confirms_list = list(set(confirms["id"]))
        winners = list(set(matchups[matchups["round"] == comp["done"]]["winner"]))
        comp["done"] += 1
        rd = comp["done"]
        bye = ((2 ** (comp["tot"] - rd)) * 2) - len(winners)

        while bye > 0:
            if len(confirms_list) > 0:
                conf_bye = confirms_list.pop(randrange(len(confirms_list)))
                winners.remove(conf_bye)
                matchups = matchups.append(pd.DataFrame([[rd, conf_bye, -1, "", "bye", conf_bye]],
                                              columns=list(matchups.columns)), ignore_index=True)
            else:
                reg_bye = winners.pop(randrange(len(winners)))
                matchups = matchups.append(pd.DataFrame([[rd, reg_bye, -1, "", "bye", reg_bye]],
                                                        columns=list(matchups.columns)), ignore_index=True)
            bye -= 1

        while len(winners) > 1:
            home = winners.pop(randrange(len(winners)))
            away = winners.pop(randrange(len(winners)))
            matchups = matchups.append(pd.DataFrame([[rd, home, away, "", "", ""]],
                                                    columns=list(matchups.columns)), ignore_index=True)

        if len(winners) > 0:
            reg_bye = winners.pop(randrange(len(winners)))
            matchups = matchups.append(pd.DataFrame([[rd, reg_bye, -1, "", "bye", reg_bye]],
                                                    columns=list(matchups.columns)), ignore_index=True)

        print(matchups[matchups["round"] == comp["done"]].shape[0])
        matchups.to_csv("data_wol/matchups.csv", index=False)
        with open('data_wol/comp.json', 'w', encoding='utf-8') as f:
            json.dump(comp, f, ensure_ascii=False, indent=4)
        #pd.DataFrame(columns=["id","confirmed"]).to_csv("data_wol/fa_confirmed.csv", index=False)

@bot.command(hidden=True, pass_context=True)
async def simulate(ctx):
    matchups = pd.read_csv("data_wol/matchups.csv")
    comp = json.load(open('data_wol/comp.json'))
    if comp["done"] == comp["quals"]:
        confirms = pd.read_csv("data_wol/fa_confirmed.csv")
        confirms_list = list(set(confirms["id"]))
    winners = []

    for index, row in matchups.iterrows():
        if row["a_pred"] == "bye":
            winners.append(row["winner"])
        elif row["winner"] > 100:
            winners.append(row["winner"])
        else:
            if randrange(2) == 0:
                #######
                ##
                ##   HOW DO I GET A USER NAME FROM THE USER ID???
                ##
                ########
                print(await bot.fetch_user(row["home"]))
                winners.append(row["home"])
            else:
                winners.append(row["away"])

    matchups["winner"] = winners
    matchups.to_csv("data_wol/matchups.csv", index=False)

# tweet commands

@bot.command(hidden=True)
async def tweet(ctx, *, tweet):
    auth = tweepy.OAuthHandler(twitter_apikey, twitter_secret_apikey)
    auth.set_access_token(twitter_access_token, twitter_secret_access_token)
    api = tweepy.API(auth)
    api.update_status(tweet)
    await ctx.send('You tried to Tweet: {}'.format(tweet))

@bot.command(brief=help_brief["tweethelp"], description=help_desc["tweethelp"])
async def tweethelp(ctx):
    await ctx.send("Jeff Shi can tweet! Any message with three ðŸ’¬ reactions will be tweeted to the Discord Twitter account "
                   "(as long as mods permit). Messages with the ðŸ”¹ reaction have been sent. Check out the server Twitter page "
                   "at https://twitter.com/WwfcDiscord")

@bot.event
async def on_reaction_add(reaction, user):
    print(reaction.message.content)
    print(reaction.emoji)
    channel_id = 346329500637855745
    #channel_id = 557526209043628032
    if reaction.message.channel.id != channel_id:
        return

    if reaction.emoji == "ðŸ’¬":
        reaction_ct = reaction.message.reactions
        tweet_go = 0
        already_tweeted = 0
        mod_denied = 0
        print(reaction_ct)
        for re in reaction_ct:
            if re.emoji == "ðŸ“µ" and re.count > 0:
                mod_denied = 1
            if re.emoji == "ðŸ”¹" and re.count > 0 and re.me:
                already_tweeted = 1
            if re.emoji == "ðŸ’¬" and re.count >= 3:
                tweet_go = 1
                print("tweet is a go")

            if already_tweeted > 0:
                print("already tweeted")
                return
            elif mod_denied > 0:
                print("the mod denied your tweet")
                return
            elif tweet_go > 0:
                auth = tweepy.OAuthHandler(twitter_apikey, twitter_secret_apikey)
                auth.set_access_token(twitter_access_token, twitter_secret_access_token)
                api = tweepy.API(auth)
                api.update_status(reaction.message.content)
                print("sent tweet")
                await reaction.message.add_reaction("ðŸ”¹")
    return
    #await reaction.message.channel.send(reaction.emoji)

## SG stuff
#with open('data_wol/comp.json', 'w', encoding='utf-8') as f:
 #   json.dump(comp, f, ensure_ascii=False, indent=4)

  #  comp = json.load(open('data_wol/comp.json'))
@bot.command()
async def sg_comp(ctx, op):
    if op.lower() in ['open', 'closed']:
        with open('data_wol/sg_open.json', 'r', encoding='utf-8') as f:
            comp_open = json.load(f)
        comp_open[str(ctx.author.id)] = op
        with open('data_wol/sg_open.json', 'w', encoding='utf-8') as f:
            json.dump(comp_open, f, ensure_ascii=False, indent=4)
        await ctx.send("<@{}> is now {} for league matches.".format(ctx.author.id, op))
    elif op.lower() == 'help':
        await ctx.send("Use this command to tell Jeff if you want your matches to count towards the official table.")
    else:
        await ctx.send("<@{}> Not valid. Please use 'open' or 'closed' to indicate whether you are open for ranked matches or not. Use 'help' for info.".format(ctx.author.id))

@bot.command()
async def sg_open(ctx):
    with open('data_wol/sg_open.json', 'r', encoding='utf-8') as f:
        comp_open = json.load(f)
    open_table = ""
    for key in comp_open.keys():
        open_table += "| {} |  {}\n".format(comp_open[key].replace("open", "  OPEN  ").upper(), await bot.fetch_user(int(key)))
    await ctx.send(open_table)

@bot.command()
async def sg_table(ctx):
    df_table = pd.read_csv(sg_table_loc, dtype={'user': 'str'})
    await make_sg_table(df_table)
    await asyncio.wait([ctx.send(file=discord.File("data_wol/sg_table.png"))])

@bot.event
async def on_message_edit(message_before, message_after):

    if len(message_after.embeds) > 0 and message_after.channel.id in [914630952414761092, 915742189424898120]:
        emb = message_after.embeds[0]

        if emb.description.split("\n")[2] == 'Status - ***Full-time***':
            score = emb.description.split("\n")[0]
            spl_score = score.split('`')
            home = spl_score[2].replace("*","").strip()
            away = spl_score[4].replace("*","").strip()
            hscore = int(spl_score[3].split("-")[0])
            ascore = int(spl_score[3].split("-")[1])

            df_table = pd.read_csv(sg_table_loc, dtype={'user': 'str'})

            hmgr = clean_mentions_str(emb.fields[0].value.split("\n\n")[0].replace("Manager: ", ""))
            amgr = clean_mentions_str(emb.fields[1].value.split("\n\n")[0].replace("Manager: ", ""))

            if hscore > ascore:
                pts = (3,0)
                res = ("w", "l")
            elif hscore < ascore:
                pts = (0,3)
                res = ("l", "w")
            else:
                pts = (1,1)
                res = ("d", "d")
            if check_if_open(hmgr, amgr):
                df_table = update_sg_table(df_table, hmgr, res[0], hscore, ascore, pts[0])
                df_table = update_sg_table(df_table, amgr, res[1], ascore, hscore, pts[1], sort=True)
                df_table = update_elo(df_table, hmgr, amgr, res)
                df_table.to_csv(sg_table_loc, index=False)
                await message_after.channel.send("Result counted towards table.\n{}: {}\n{}: {}".format(home, hscore, away, ascore))
            else:
                await message_after.channel.send("Result does not count. One or more teams are closed for competitive matches.")
# poll commands

@bot.command(hidden=True)
async def addpoll(ctx, code, limit, *poll_args):
    poll = ' '.join(poll_args)
    code = code.lower()
    polls = pd.read_csv('data_wol/polls.csv')

    if poll_code_exists(polls, code):
        msg = "Code '{}' already exists. Try a new code.".format(code)
    else:
        add_polls_row(polls, code, poll, limit)
        await bot.get_channel(poll_channel).send("New poll added:\n**{}**\n"
                                                 "Code: **{}**\nResponse limit: **{}**\n"
                                                 "Respond in #poll-spam with command '$vote {} *RESPONSE*'".format(poll, code, limit, code))
        msg = "Poll added with code {}. Response limited to {} per user.".format(code, limit)
    await ctx.send(msg)

@bot.command(hidden=True)
async def closepoll(ctx, code, delete):
    code = code.lower()
    delete = delete.lower()
    polls = pd.read_csv('data_wol/polls.csv')
    responses = pd.read_csv("data_wol/poll_responses.csv")

    if delete.lower() == "del":
        polls[polls['code'] != code].to_csv('data_wol/polls.csv', index=False)
        responses[responses['code'] != code].to_csv("data_wol/poll_responses.csv", index=False)
        msg = "Poll with code {} removed.".format(code)

    elif delete.lower() == "clo":
        pl_ind = polls.index[polls["code"] == code.lower()].tolist()
        if len(pl_ind) > 0:
            polls.at[pl_ind[0], "open"] = 0
            polls.to_csv('data_wol/polls.csv', index=False)
            close_msg = "Poll closed:\nCode: **{}**".format(code)
            results_msg = get_poll_results(responses, polls, code)
            await bot.get_channel(poll_channel).send(close_msg)
            await bot.get_channel(poll_channel).send(results_msg)
            msg = "Poll with code {} closed.".format(code)
        else:
            msg = "Poll with code {} does not exist.".format(code)
    else:
        msg = "Wrong code. Please use 'del' to delete poll or 'clo' to close poll."
    await ctx.send(msg)

@bot.command(brief=help_brief["openpolls"], description=help_desc["openpolls"])
async def openpolls(ctx):
    polls = pd.read_csv('data_wol/polls.csv')

    open_polls = polls[polls["open"] == 1]
    if open_polls.shape[0] == 0:
        msg = "No open polls."
    else:
        msg = ""
        for index, row in open_polls.iterrows():
            msg += "Poll:**{}**\nCode: **{}**  Vote Limit: **{}**\n\n".format(row["poll"],row["code"], row["vote_limit"])
    await ctx.send(msg.strip())

@bot.command(brief=help_brief["vote"], description=help_desc["vote"])
async def vote(ctx, code, *full_response):
    response = ' '.join(full_response)
    code = code.lower()
    polls = pd.read_csv('data_wol/polls.csv')
    responses = pd.read_csv("data_wol/poll_responses.csv")

    poll_limit = get_poll_info(polls, code)["vote_limit"].to_list()
    if len(poll_limit) > 0:
        prev_response = get_user_responses(responses, code, ctx.author)
        if prev_response.shape[0] >= poll_limit[0]:
            msg = "You already voted {} time(s). Your vote(s):\n".format(prev_response.shape[0])
            for resp in prev_response["response"].to_list():
                msg += resp + ", "
            msg = msg[:-2] + "\nTo change vote, use command '$cvote *CODE* *NEW_RESPONSE*'."
        else:
            add_responses_row(responses, code, response, ctx.author)
            msg = "You voted for {}.".format(response)
    else:
        msg = "Code {} does not exist. Try *$openpolls* to check open polls.".format(code)

    await ctx.send(msg)

@bot.command(brief=help_brief["getvote"], description=help_desc["getvote"])
async def getvote(ctx, code):
    code = code.lower()
    responses = pd.read_csv("data_wol/poll_responses.csv")

    prev_response = get_user_responses(responses, code, ctx.author)
    msg = "Your vote(s):\n"
    for resp in prev_response["response"].to_list():
        msg += resp + ", "

    await ctx.send(msg[:-2] + "\nTo change vote, use command '$cvote *CODE* *RESPONSE*'.")

@bot.command(brief=help_brief["cvote"], description=help_desc["cvote"])
async def cvote(ctx, code, *new_response):
    response = ' '.join(new_response)
    code = code.lower()
    responses = pd.read_csv("data_wol/poll_responses.csv")
    polls = pd.read_csv("data_wol/polls.csv")

    prev_response = get_user_responses(responses, code, ctx.author)
    if prev_response.shape[0] == 0:
        msg = "You have not voted for this poll yet or poll {} does not exist.".format(code)
    else:
        pr = prev_response.iloc[-1]["response"]
        nr = pd.DataFrame({"code": code, "response": response, "user": ctx.author}, index=[0])
        pd.concat([nr, responses.drop(prev_response.iloc[-1].name)]).reset_index(drop=True).to_csv("data_wol/poll_responses.csv", index=False)
        msg = "You replaced '{}' with '{}'.".format(pr, response)

    await ctx.send(msg)

@bot.command(hidden=True)
async def results(ctx, code):
    code = code.lower()
    responses = pd.read_csv("data_wol/poll_responses.csv")
    polls = pd.read_csv("data_wol/polls.csv")

    if poll_code_exists(polls, code):

        msg = get_poll_results(responses, polls, code)
    else:
        msg = "Poll with code {} does not exist.".format(code)

    await ctx.send(msg)

#### SOCCER GURU???? ####

@bot.command(hidden=True)
@commands.cooldown(1, 60, commands.BucketType.user)
async def sg_claim(ctx):
    new_plr = claim()
    new_plr_card = new_plr.get_card()

    try:
        with open('data_sg/clubs/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
            ex_clb = json.load(f)

        ex_clb["squad"].append(new_plr.to_dict())

        with open('data_sg/clubs/{}.json'.format(str(ctx.author.id)), 'w', encoding='utf-8') as f:
            json.dump(ex_clb, f, ensure_ascii=False, indent=4)
    except:
        new_clb = Club(new=(str(ctx.author.id),new_plr)).to_dict()
        new_xi = XI().to_dict()

        with open('data_sg/clubs/{}.json'.format(str(ctx.author.id)), 'w', encoding='utf-8') as f:
            json.dump(new_clb, f, ensure_ascii=False, indent=4)
        with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'w', encoding='utf-8') as f:
            json.dump(new_xi, f, ensure_ascii=False, indent=4)

    await ctx.send("<@{}> {} ({}) joins your club!".format(ctx.author.id, new_plr.name, new_plr.ctype))
    await asyncio.wait([ctx.send(file=discord.File(new_plr_card))])

@bot.command(hidden=True)
@commands.cooldown(1, 5, commands.BucketType.user)
async def sg_club(ctx, page: int):
    try:
        with open('data_sg/clubs/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
            ex_clb = Club(json.load(f))
            ex_clb.to_list(page)
            await asyncio.wait([ctx.send(file=discord.File(TEMP_CLUB))])
    except Exception as e:
        print(e)
        await ctx.send("<@{}> Your club does not exist! Type '$sg_claim' to get a player.".format(ctx.author.id))

@bot.command(hidden=True)
@commands.cooldown(1, 5, commands.BucketType.user)
async def sg_show(ctx, *player: str):
    try:
        with open('data_sg/clubs/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
            ex_clb = Club(json.load(f))

        df_dist = ex_clb.search(" ".join(player))

        if df_dist.shape[0] > 0:
            match = df_dist.loc[0]
            await ctx.send("```{} ({})  Rating: {}\nPosition: {}\nNation: {}\nTeam: {}\nLeague: {}\n\n" \
            "PAC: {}     DRI: {}\nSHO: {}     DEF: {}\nPAS: {}     PHY: {}```".format(match["name"], match["ctype"],
                                match["rat"], match["pos"], match["country"], match["tm"], match["leag"],
                                match["pac"], match["dri"], match["sho"], match["dff"], match["pas"], match["phy"]))
        else:
            await ctx.send("No match for {}".format(player))

    except Exception as e:
        print(e)
        await ctx.send("<@{}> Your club does not exist! Type '$sg_claim' to get a player.".format(ctx.author.id))

@bot.command(hidden=True)
@commands.cooldown(1, 5, commands.BucketType.user)
async def sg_add(ctx, *player: str):
    try:
        with open('data_sg/clubs/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
            ex_clb = Club(json.load(f))
        df_dist = ex_clb.search(" ".join(player))
        if df_dist.shape[0] > 0:
            match = Player(df_dist.loc[0], "", "", "", "", "", "", pd_row_or_dict=True)
            with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
                xi_obj = XI(source=json.load(f))

            empty_ind = ""
            exists = False
            for i in reversed(range(1,12)):
                temp = xi_obj.xi[str(i)]["plr"]
                if temp != "":
                    temp_plr = Player(xi_obj.xi[str(i)]["plr"], "", "", "", "", "", "", pd_row_or_dict=True)
                    if temp_plr.unique_id() == match.unique_id():
                        exists = True
                        break
                if xi_obj.xi[str(i)]["plr"] == "":
                    empty_ind = str(i)

            if empty_ind == "":
                await ctx.send("XI is full.")
            elif exists:
                await ctx.send("Player is already in your XI.")
            else:
                xi_obj.xi[empty_ind]["plr"] = match.to_dict()

                with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'w', encoding='utf-8') as f:
                    json.dump(xi_obj.to_dict(), f, ensure_ascii=False, indent=4)
                await ctx.send("{} was added to your XI.".format(match.name))
        else:
            await ctx.send("No match for {}".format(player))

    except Exception as e:
        print(e)
        print(traceback.format_exc())
        await ctx.send("<@{}> Your club does not exist! Type '$sg_claim' to get a player.".format(ctx.author.id))

@bot.command(hidden=True)
@commands.cooldown(1, 5, commands.BucketType.user)
async def sg_del(ctx, *player: str):
    try:
        with open('data_sg/clubs/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
            ex_clb = Club(json.load(f))
        df_dist = ex_clb.search(" ".join(player))
        if df_dist.shape[0] > 0:
            match = Player(df_dist.loc[0], "", "", "", "", "", "", pd_row_or_dict=True)
            with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
                xi_obj = XI(source=json.load(f))

            rpl_ind = ""
            for i in range(1, 12):
                temp = xi_obj.xi[str(i)]["plr"]
                if temp != "":
                    temp_plr = Player(xi_obj.xi[str(i)]["plr"], "", "", "", "", "", "", pd_row_or_dict=True)
                    if temp_plr.unique_id() == match.unique_id():
                        rpl_ind = str(i)
                        break

            if rpl_ind != "":
                xi_obj.xi[rpl_ind]["plr"] = ""
                with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'w', encoding='utf-8') as f:
                    json.dump(xi_obj.to_dict(), f, ensure_ascii=False, indent=4)
                await ctx.send("{} was removed from your XI.".format(match.name))
            else:
                await ctx.send("{} is not in your XI.".format(match.name))
        else:
            await ctx.send("No match for {}".format(player))

    except Exception as e:
        print(e)
        print(traceback.format_exc())
        await ctx.send("<@{}> Your club does not exist! Type '$sg_claim' to get a player.".format(ctx.author.id))

@bot.command(hidden=True)
@commands.cooldown(1, 5, commands.BucketType.user)
async def sg_swap(ctx, n1: int, n2: int):
    try:
        if (n1 <= 11 and n1 > 0) and (n2 <= 11 and n2 > 0):
            with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
                xi_obj = XI(source=json.load(f))

            temp = xi_obj.xi[str(n1)]["plr"]
            xi_obj.xi[str(n1)]["plr"] = xi_obj.xi[str(n2)]["plr"]
            xi_obj.xi[str(n2)]["plr"] = temp

            with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'w', encoding='utf-8') as f:
                json.dump(xi_obj.to_dict(), f, ensure_ascii=False, indent=4)

            await ctx.send("Swapped positions {} and {}.".format(n1, n2))
        else:
            await ctx.send("Invalid input. Please use numbers 1 to 11: $sg_swap 1 3")
    except:
        await ctx.send("Invalid input. Please use numbers 1 to 11: $sg_swap 1 3")

@bot.command(hidden=True)
@commands.cooldown(1, 5, commands.BucketType.user)
async def sg_xi(ctx):
    with open('data_sg/xis/{}.json'.format(str(ctx.author.id)), 'r', encoding='utf-8') as f:
        xi_obj = XI(source=json.load(f))
    await asyncio.wait([ctx.send(file=discord.File(xi_obj.to_img()))])

## error handlers

@sg_claim.error
async def sg_claim_error(ctx, error):
    if isinstance(error, commands.CommandOnCooldown):
        msg = 'This command is ratelimited, please try again in {:.2f}s'.format(error.retry_after)
        await ctx.send(msg)
    else:
        raise error

@sg_club.error

async def sg_club_error(ctx, error):
    if isinstance(error, commands.MissingRequiredArgument):
        msg = "Please specify which page of your club you want. '$sg_club 1' gets the 1st page."
        await ctx.send(msg)
    else:
        raise error

'''
@bot.event
async def on_message(message):
    if message.clean_content.lower().strip() == "thanks jeff":
        await message.channel.send("You're welcome")
'''
bot.run(token)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import re
import pandas as pd
import numpy as np
from torch.utils.data import Dataset, DataLoader
import torch
codepath = os.path.abspath(sys.path[0])
sys.path.append(codepath+'/../lib')
sys.path.append(os.getcwd())

class MovementHybridDataset(Dataset):

    # def __init__(self, feat_path, dfeat_path,
    #              egroup_path, egroup_weight_path, divider_path,
    #              itype_path, nblist_path, weight_all_path,
    #              energy_path, force_path, ind_img_path, natoms_img_path, data_num, atom_type, is_dfeat_sparse=False
    #              ):  # , natoms_path

    def __init__(self, inputs: list, data_num, atom_type, is_dfeat_sparse=False, alive_atomic_energy=False):  # , natoms_path
        """
            pm.is_dfeat_sparse is True, self.dfeat will not be generated
        """
        self.data_num = data_num
        self.atom_type_input =atom_type
        self.ntypes = len(atom_type)
        self.is_dfeat_sparse = is_dfeat_sparse
        self.alive_atomic_energy = alive_atomic_energy
        self.max_atom_nums = 0
        super(MovementHybridDataset, self).__init__()
        self.device = torch.device(
            'cuda' if torch.cuda.is_available() else 'cpu')

        self.feat, self.dfeat= [], []
        self.egroup, self.egroup_weight, self.divider =[], [], []
        self.itype, self.nblist, self.weight_all, self.ind_img = [], [], [], []
        self.energy, self.force, self.natoms_img = [], [], []
        self.atom_type = []
        self.energy_shift = []

        if self.alive_atomic_energy:
            feat_path, dfeat_path, egroup_path, egroup_weight_path, divider_path, itype_path, \
            nblist_path, weight_all_path, ind_img_path, natoms_img_path, energy_path, force_path = inputs
        else:
            feat_path, dfeat_path, itype_path, nblist_path, weight_all_path, \
            ind_img_path, natoms_img_path, energy_path, force_path = inputs

        for i in range(data_num):
            self.feat.append(np.load(feat_path[i]))

            if self.is_dfeat_sparse==False:
                self.dfeat.append(np.load(dfeat_path[i]))

            if self.alive_atomic_energy:
                self.egroup.append(np.load(egroup_path[i]))
                self.egroup_weight.append(np.load(egroup_weight_path[i]))
                self.divider.append(np.load(divider_path[i]))

            # self.natoms_sum = natoms
            # self.natoms = pd.read_csv(natoms_path)   #/fread_dfeat/NN_output/natoms_train.csv
            self.itype.append(np.load(itype_path[i]))
            self.nblist.append(np.load(nblist_path[i]))
            self.weight_all.append(np.load(weight_all_path[i]))
            self.ind_img.append(np.load(ind_img_path[i]))

            self.energy.append(np.load(energy_path[i]))
            self.force.append(np.load(force_path[i]))

            self.natoms_img.append(np.load(natoms_img_path[i]))
            self.atom_type.append(np.array(self.get_atom_type(list(self.itype[i][0:self.ind_img[i][1]]))))

            if self.atom_type[i].size == len(self.atom_type_input):
                self.energy_shift = self._get_energy_shift(self.ind_img[i], self.itype[i], self.energy[i])

        self.image_num_list = []
        atom_nums_list = []
        feature_type_list =[]
        for i in range(self.data_num):
            image_number = self.ind_img[i].shape[0] - 1
            self.image_num_list.append(image_number)
            feature_type_list.append(self.dfeat[i].shape[2])
            atom_nums_list.append(self.natoms_img[0][0][0])
        self.max_feature_nums = max(feature_type_list)
        self.max_atom_nums = max(atom_nums_list)

    def __get_data_index(self, index, image_num_list):
        t = 0
        for i, image_num in enumerate(image_num_list):
            t += image_num
            if t > index:
                break
        image_index = index - sum(image_num_list[:i])
        return i, image_index

    def __getitem__(self, index):
        # index = index + 10
        data_index, index = self.__get_data_index(index, self.image_num_list)
        ind_image = np.zeros(2)
        ind_image[0] = self.ind_img[data_index][index]
        ind_image[1] = self.ind_img[data_index][index+1]
        dic= {}

        start_index = self.ind_img[data_index][index]
        end_index = self.ind_img[data_index][index+1]

        dic = {
            'input_feat': self.feat[data_index][start_index:end_index],
            # 'input_egroup': self.egroup[data_index][start_index:end_index],
            # 'input_egroup_weight': self.egroup_weight[data_index][start_index:end_index],
            # 'input_divider': self.divider[data_index][start_index:end_index],
            'input_itype': self.itype[data_index][start_index:end_index],
            'input_nblist': self.nblist[data_index][start_index:end_index],
            'atom_type': self.atom_type[data_index],
            'input_weight_all': self.weight_all[data_index][start_index:end_index],

            'output_energy': self.energy[data_index][start_index:end_index],
            'output_force': self.force[data_index][start_index:end_index],
            'ind_image': ind_image,
            'natoms_img': self.natoms_img[data_index][index]
        }
        if self.is_dfeat_sparse==False:
            dic['input_dfeat'] = self.dfeat[data_index][start_index:end_index]
        else:
            dic['input_dfeat'] = []

        if self.alive_atomic_energy:
            dic['input_egroup'] = self.egroup[data_index][start_index:end_index]
            dic['input_egroup_weight'] = self.egroup_weight[data_index][start_index:end_index]
            dic['input_divider'] = self.divider[data_index][start_index:end_index]
        else:
            dic['input_egroup'] = []
            dic['input_egroup_weight'] = []
            dic['input_divider'] = []
        return dic

    def get_atom_type(self, atom_type_list):
        atom_type_data_input = sorted(set(atom_type_list), key=atom_type_list.index)
        return atom_type_data_input

    def __len__(self):
        return sum(self.image_num_list)

    '''
    description:
    get energy shift from first image of input
    param {*} ind_img
    param {*} itype
    param {*} energy
    param {*} atom_type_input
    return {*}
    author: wuxingxing
    '''
    def _get_energy_shift(self, ind_img, itype, energy):
        type_dict = {}
        result = []

        num_atom = ind_img[1] # get atom nums in the first image
        # atom type list of a image
        type_list = itype[0:num_atom] # get atom types of the atoms
        atomic_energy_list = energy[0:num_atom] # get Ei of the atoms

        for atom, energy in zip(type_list, atomic_energy_list):
            if atom not in type_dict:
                type_dict[atom] = [energy]
            else:
                type_dict[atom].append(energy)

        for atom in self.atom_type_input:
            if atom in type_dict.keys():
                result.append(np.mean(type_dict[atom]))

        return result

    '''
    input para:
    examplespath : npy_file_dir
    data_file_frompwmat : read train_data.csv or test_data.csv
    '''
def get_torch_data_hybrid(data_list, data_type = "final_train", alive_atomic_energy = False, atom_type = None, is_dfeat_sparse=False):
    # examplespath='./train_data/final_train'   # for example

    f_feat, f_dfeat, f_egroup, f_egroup_weight, f_divider, \
        f_itype, f_nblist, f_weight_all, ind_img, natoms_img, f_energy, f_force\
        =[], [], [], [], [], [], [], [], [], [], [], []

    for dir in data_list:
        dir = os.path.join(dir, data_type)
        f_feat.append(os.path.join(dir, 'feat_scaled.npy'))
        f_dfeat.append(os.path.join(dir, 'dfeat_scaled.npy'))

        if alive_atomic_energy:
            f_egroup.append(os.path.join(dir, 'egroup.npy'))
            f_egroup_weight.append(os.path.join(dir, 'egroup_weight.npy'))
            f_divider.append(os.path.join(dir, 'divider.npy'))

        f_itype.append(os.path.join(dir, 'itypes.npy'))
        f_nblist.append(os.path.join(dir, 'nblist.npy'))
        f_weight_all.append(os.path.join(dir, 'weight_all.npy'))
        ind_img.append(os.path.join(dir, 'ind_img.npy'))
        natoms_img.append(os.path.join(dir, 'natoms_img.npy'))

        f_energy.append(os.path.join(dir, 'engy_scaled.npy'))
        f_force.append(os.path.join(dir, 'fors_scaled.npy'))
        # f_force = os.path.join(examplespath+'/force.npy')

        if alive_atomic_energy:
            Dataset_list = [f_feat, f_dfeat, f_egroup, f_egroup_weight, f_divider,
                            f_itype, f_nblist, f_weight_all, ind_img, natoms_img, f_energy, f_force]
        else:
            Dataset_list = [f_feat, f_dfeat, f_itype, f_nblist, f_weight_all, ind_img, natoms_img, f_energy, f_force]

    torch_data = MovementHybridDataset(Dataset_list, len(data_list), atom_type, is_dfeat_sparse, alive_atomic_energy)
    # torch_data = MovementHybridDataset(f_feat, f_dfeat,
    #                              f_egroup, f_egroup_weight, f_divider,
    #                              f_itype, f_nblist, f_weight_all,
    #                              f_energy, f_force, ind_img, natoms_img, len(data_list), atom_type, is_dfeat_sparse)
    return torch_data


# importing the modules that will be needed in the project
import pygame
import random

# initialising the pygame modules
pygame.init()

# creating and setting the size of the screen that is going to be used
screen_width = 1040
screen_height = 680
screen = pygame.display.set_mode((screen_width, screen_height))

# Creating the player, the enemies and the prize objects with the chosen images
player = pygame.image.load("game/player.jpg")
enemy1 = pygame.image.load("game/enemy.png")
enemy2 = pygame.image.load("game/enemy.png")
enemy3 = pygame.image.load("game/enemy.png")
prize = pygame.image.load("game/prize.jpg")

# Getting the player, enemies and prize objects' widths and heights
# To be used to detect whenever any of them are off screen or where they are on the screen
player_height = player.get_height()
player_width = player.get_width()

enemy1_height = enemy1.get_height()
enemy1_width = enemy1.get_width()

enemy2_height = enemy2.get_height()
enemy2_width = enemy2.get_width()

enemy3_height = enemy3.get_height()
enemy3_width = enemy3.get_width()

prize_height = prize.get_height()
prize_width = prize.get_width()

# Printing the height and width of the player object (i.e. the position)
print(f"This is the height of the player: {player_height}.")
print(f"This is the width of the player: {player_width}.")

# Storing the player's position in variables in order for them to be changeable
playerX = 100
playerY = 50

# Setting the enemy and prize objects start position off screen and with a random Y-position
enemy1X = screen_width
enemy1Y = random.randint(0, (screen_height - enemy1_height))

enemy2X = screen_width
enemy2Y = random.randint(0, (screen_height - enemy2_height))

enemy3X = screen_width
enemy3Y = random.randint(0, (screen_height - enemy3_height))

prizeX = screen_width
prizeY = random.randint(0, (screen_height - prize_height))

# Detecting whether arrow keys are being pressed or not
keyUp = False
keyDown = False

# Creating the while loop to continually have the game running
while 1:
    # Clearing the screen and drawing the player and enemy on the screen in the specified positions
    screen.fill(0)
    screen.blit(player, (playerX, playerY))
    screen.blit(enemy1, (enemy1X, enemy1Y))
    screen.blit(enemy2, (enemy2X, enemy2Y))
    screen.blit(enemy3, (enemy3X, enemy3Y))
    screen.blit(prize, (prizeX, prizeY))

    # Updates the screen to what is currently supposed to be on screen
    pygame.display.flip()

    # Looping through events that happen during the game
    for event in pygame.event.get():

        # Checking if the user want to quit and then quits the program if it is true
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)

        # Checking if a key has been pressed
        if event.type == pygame.KEYDOWN:

            # Testing if a key we want has been pressed
            if event.key == pygame.K_UP:
                keyUp = True
            if event.key == pygame.K_DOWN:
                keyDown = True

        # Checking if a key is not being pressed
        if event.type == pygame.KEYUP:

            # Testing if a key we want is no longer being pressed
            if event.key == pygame.K_UP:
                keyUp = False
            if event.key == pygame.K_DOWN:
                keyDown = False

    # After the checks are completed in the for loop,
    # Checking if the keyUp or keyDown variables are true and will then move the layer object accordingly
    if keyUp:
        # Checks if the next movement will move the player off screen
        # If it doesn't the player object will move
        if playerY > 0:
            playerY -= 1

    if keyDown:
        # Checks if the next movement will move the player off screen
        # If it doesn't the player object will move
        if playerY < screen_height - player_height:
            playerY += 1

    # Adding a bounding box to the player to be used to check if the enemies collide with the player
    playerBox = pygame.Rect(player.get_rect())

    # Updating the bounding box to the player to ensure it is always around the player
    playerBox.top = playerY
    playerBox.left = playerX

    # Setting the bounding boxes for the first enemy object
    enemy1Box = pygame.Rect(enemy1.get_rect())
    enemy1Box.top = enemy1Y
    enemy1Box.left = enemy1X

    # Setting the bounding boxes for the second enemy object
    enemy2Box = pygame.Rect(enemy2.get_rect())
    enemy2Box.top = enemy2Y
    enemy2Box.left = enemy2X

    # Setting the bounding boxes for the third enemy object
    enemy3Box = pygame.Rect(enemy3.get_rect())
    enemy3Box.top = enemy3Y
    enemy3Box.left = enemy3X

    # Setting the bounding boxes for the prize object
    prizeBox = pygame.Rect(prize.get_rect())
    prizeBox.top = prizeY
    prizeBox.left = prizeX

    # Testing for collisions between the player's box and the enemies' boxes
    if playerBox.colliderect(enemy1Box):

        # Printing losing status if a collision is detected
        print("You Lose!")

        # Quit the game and closing the window
        pygame.quit()
        exit(0)

    if playerBox.colliderect(enemy2Box):

        # Printing losing status if a collision is detected
        print("You Lose!")

        # Quit the game and closing the window
        pygame.quit()
        exit(0)

    if playerBox.colliderect(enemy3Box):

        # Printing losing status if a collision is detected
        print("You Lose!")

        # Quit the game and closing the window
        pygame.quit()
        exit(0)

    # Testing for a player collision
    if playerBox.colliderect(prizeBox):

        # Printing winning status if a collision is detected
        print("You Win!")

        # Quit the game and closing the window
        pygame.quit()
        exit(0)

    # Making the first enemy object move towards the player
    enemy1X -= 0.15

    # Once the first enemy object starts going off screen,
    # the second enemy object starts moving toward the player
    if enemy1X < 0:
        enemy2X -= 0.15

    # Once the second enemy object starts going off screen,
    # the third enemy object starts moving toward the player
    if enemy2X < 0:
        enemy3X -= 0.15

    # Once the third enemy object starts going off screen,
    # the prize object starts moving toward the player
    if enemy3X < 0:
        prizeX -= 0.15

    # If the prize object goes off screen the game is over and the player loses
    if prizeX < 0:
        # Printing losing status
        print("You lose!")

        # Quiting the game and closing the window
        pygame.quit()
        exit(0)