from django.urls import path

from petstagram.main_app.views import home, show_dashboard, show_profile, show_pet_photo_details, like_pet_photo

urlpatterns = [
    path('', home, name='home'),
    path('dashboard/', show_dashboard, name='dashboard'),
    path('profile/', show_profile, name='profile'),
    path('photo/details/<int:pk>/', show_pet_photo_details, name='pet photo details'),
    path('photo/like/<int:pk>/', like_pet_photo, name='like pet photo'),
]


from app.tests.constants import (
    FAKE_COMP_DESC,
    DEFAULT_TEST_START,
    DEFAULT_TEST_END,
    DEFAULT_FAKE_COMP_CSV_OUTPUT,
    DEFAULT_FAKE_COMP_ENTRY_CSV_OUTPUT,
)
from collections import defaultdict
from datetime import timedelta, datetime
from random import choice, shuffle
from app.tests.utils.files import FileWriter
import pprint

class CompetitionEntryGenerator:

    def generate_csv_comp_entries(
        self,
        fake_comps,
        fake_backtests,
        fake_users,
    ):

        # user id to user information
        reverse_user_idx = {}
        for user in fake_users:
            reverse_user_idx[user['id']] = user

        # backtest owner username to backtests
        reverse_back_idx = defaultdict(list)
        for backtest in fake_backtests:
            owner = backtest['owner']
            reverse_back_idx[reverse_user_idx[owner]['username']].append(backtest)

        ret = []
        csv_info = []

        for comp in fake_comps:

            for username in reverse_back_idx:
                poss = reverse_back_idx[username]
                shuffle(poss)
                backtest_submission = None
                for backtest in poss:
                    if backtest['score'] >= 0:
                        backtest_submission = backtest
                        break

                ret.append({
                    'comp_id': comp['id'],
                    'owner': username,
                    'backtest_id': backtest_submission['id'],
                    'backtest_algo': backtest_submission['algo'],
                    'result': backtest_submission['result'],
                    'score': backtest_submission['score'],
                    'code_snapshot': backtest_submission['code'],
                    'test_interval': backtest_submission['test_interval'],
                    'test_start': backtest_submission['test_start'],
                    'test_end': backtest_submission['test_end']
                })

                csv_info.append([
                    str(comp['id']),
                    username,
                    str(backtest_submission['id']),
                    str(backtest_submission['algo']),
                    backtest_submission['result'],
                    str(backtest_submission['score']),
                    backtest_submission['code'],
                    backtest_submission['test_interval'],
                    backtest_submission['test_start'],
                    backtest_submission['test_end']
                ])

        FileWriter.write_csv_to_path(
            DEFAULT_FAKE_COMP_ENTRY_CSV_OUTPUT,
            csv_info,
        )

        return ret

class CompetitionGenerator:

    def __init__(self):
        self.titles = [
            "very long competition title that is a test for stress testing",
            "another competition title for test test test test test test",
            "yet another test test test test test test test test test test test",
        ]

        with open(FAKE_COMP_DESC) as f:
            self.desc = f.read()

        self.end_time = str(datetime.now() + timedelta(days=30))

        self.test_start = DEFAULT_TEST_START
        self.test_end = DEFAULT_TEST_END

        self._curr_id = 1

    def generate_csv_user_comps(self, fake_users, num_comps):

        ret = []
        csv_info = []

        for user in fake_users:
            username = user['username']

            title = choice(self.titles)
            ret.append({
                "id": self._curr_id,
                'title': title,
                'description': self.desc,
                'owner': username,
                'end_time': self.end_time,
                'test_start': self.test_start,
                'test_end': self.test_end,
            })
            csv_info.append([
                title,
                self.desc,
                username,
                self.end_time,
                self.test_start,
                self.test_end,
            ])
            self._curr_id += 1

        FileWriter.write_csv_to_path(
            DEFAULT_FAKE_COMP_CSV_OUTPUT,
            csv_info,
        )

        return ret


from zope import interface, component
from raptus.article.core import interfaces

class NamedDefaultComponent(object):
    """ Provider to define a default component using a named adapter
    """
    interface.implements(interfaces.INamedDefaultComponent)
    component.adapts(interfaces.IArticle)

    def __init__(self, context):
        self.context = context

def SetDefaults(object, event):
    """ Sets the default components defined by the registered adapters providing IDefaultComponents
    """
    for name, provider in component.getAdapters((object,),
                                                interfaces.IDefaultComponents):
        for comp in provider.getComponents():
            interface.alsoProvides(object, comp.interface)
    for name, provider in component.getAdapters((object,),
                                                interfaces.INamedDefaultComponent):
        comp = component.queryAdapter(object,
                                      interface=interfaces.IComponent,
                                      name=name)
        if comp is not None:
            interface.alsoProvides(object, comp.interface)
    object.reindexObject(idxs=['object_provides'])


import time
import datetime
import requests
import json
from playsound import playsound

def bbs(s):
    if not is_alarm_on:
        print('[{}] {}'.format(datetime.datetime.now().strftime('%H:%M:%S'), s))

input('欢迎使用iPhone取货预约助手，请合理使用工具\n正在检查环境：\n即将播放预约提示音，按任意键开始...')
sound_alarm = './alarm.mp3'
playsound(sound_alarm)

print('配置特定型号')
# Config State
type_phone = json.load(open('category.json', encoding='utf-8'))
url_param = ['state', 'city', 'district']
config_param = []
dic_param = {}
lst_choice_param = []
print('--------------------------------')
for index, item in enumerate(type_phone):
    print('[{}] {}'.format(index, item))
input_type = int(input('选择型号：'))
choice_type = list(type_phone)[input_type]

print('--------------------------------')
for index, (key, value) in enumerate(type_phone[choice_type].items()):
    print('[{}] {}'.format(index, value))
input_size = int(input('选择尺寸/颜色：'))
code_iphone = list(type_phone[choice_type])[input_size]
select_size = type_phone[choice_type][code_iphone]
input('您的选择：{} {}，按任意键继续...'.format(choice_type, select_size))

print('选择计划预约的地址')
headers = {
    'sec-ch-ua': '"Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"',
    'Referer': 'https://www.apple.com.cn/shop/buy-iphone/iphone-13-pro/{}'.format(code_iphone),
    'DNT': '1',
    'sec-ch-ua-mobile': '?0',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36',
    'sec-ch-ua-platform': '"macOS"',
}
for step, param in enumerate(url_param):
    print('请稍后...{}/{}'.format(step+1, len(url_param)))
    url = "https://www.apple.com.cn/shop/address-lookup?{}".format('&'.join(lst_choice_param))
    response = requests.request("GET", url, headers=headers, data={})
    response_json = json.loads(response.text)
    result_body = response_json['body']
    result_param = result_body[param]
    if type(result_param) is dict:
        result_data = result_param['data']
        print('--------------------------------')
        for index, item in enumerate(result_data):
            print('[{}] {}'.format(index, item['value']))
        input_index = int(input('请选择序号：'))
        choice_result = result_data[input_index]['value']
        dic_param[param] = choice_result
        lst_choice_param.append('{}={}'.format(param, dic_param[param]))
    else:
        lst_choice_param.append('{}={}'.format(param, result_param))

print('正在加载网络资源...')
url = "https://www.apple.com.cn/shop/address-lookup?{}".format('&'.join(lst_choice_param))
response = requests.request("GET", url, headers=headers, data={})
response_json = json.loads(response.text)
provinceCityDistrict = response_json['body']['provinceCityDistrict']
input('您的选择：{}，按任意键继续...'.format(provinceCityDistrict))

# Loop for checking iPhone status
count = 0
is_alarm_on = False
while True:
    try:
        url = "https://www.apple.com.cn/shop/fulfillment-messages?pl=true&parts.0={}&location={}".format(code_iphone, provinceCityDistrict)
        response = requests.request("GET", url, headers=headers, data={})
        res_text = response.text
        res_json = json.loads(res_text)
        stores = res_json['body']['content']['pickupMessage']['stores']
        is_available = False
        lst_available = []
        print('--------------------------------')
        for item in stores:
            storeName = item['storeName']
            pickupSearchQuote = item['partsAvailability'][code_iphone]['pickupSearchQuote']
            bbs('{} - {}'.format(storeName, pickupSearchQuote))
            if pickupSearchQuote == '今天可取货':
                is_available = True
                lst_available.append(storeName)

        if len(lst_available) > 0:
            if not is_alarm_on:
                is_alarm_on = True
                # Display while iPhone is available
                print('以下直营店预约可用：\n{}\nhttps://www.apple.com.cn/shop/buy-iphone'.format(','.join(lst_available)))
            playsound(sound_alarm)

        if not is_available:
            is_alarm_on = False

    except Exception as err:
        bbs(err)
    count += 1
    if not is_alarm_on:
        bbs('5秒后进行第{}次尝试...'.format(count))
        time.sleep(5)
    else:
        time.sleep(2)


from transformers import AutoTokenizer, AutoModelForCausalLM
from torch import nn

class generator(nn.Module):
    def __init__(self, args):
        super().__init__()
        self.generator = AutoModelForCausalLM.from_pretrained(args.generator)
        self.tokenizer = AutoTokenizer.from_pretrained(args.generator)
        self.beam = args.beam

    def get_tokens(self, prompt):
        inputs = self.tokenizer(prompt, return_tensors="pt")
        generate_ids = self.generator.generate(inputs.input_ids, min_length=inputs.input_ids.shape[1]+1, max_length=inputs.input_ids.shape[1]+1, do_sample=False, num_beams=self.beam, num_return_sequences=self.beam)
        return self.tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)


from typing import Optional

from fastapi_camelcase import CamelModel
from mealie.schema.category import CategoryBase, RecipeCategoryResponse
from pydantic import validator
from slugify import slugify

# Cluge Validator for ISSUE: #671
langs = {
    "el-GR",
    "it-IT",
    "ko-KR",
    "es-ES",
    "ja-JP",
    "zh-CN",
    "tr-TR",
    "ar-SA",
    "hu-HU",
    "pt-PT",
    "no-NO",
    "sv-SE",
    "ro-RO",
    "sk-SK",
    "uk-UA",
    "pl-PL",
    "da-DK",
    "pt-BR",
    "de-DE",
    "ca-ES",
    "sr-SP",
    "cs-CZ",
    "fr-CA",
    "fr-FR",
    "zh-TW",
    "af-ZA",
    "ru-RU",
    "he-IL",
    "nl-NL",
    "en-US",
    "en-GB",
    "fi-FI",
    "vi-VN",
}

class SiteSettings(CamelModel):
    language: str = "en-US"
    first_day_of_week: int = 0
    show_recent: bool = True
    cards_per_section: int = 9
    categories: Optional[list[CategoryBase]] = []

    class Config:
        orm_mode = True

        schema_extra = {
            "example": {
                "language": "en",
                "firstDayOfWeek": 0,
                "showRecent": True,
                "categories": [
                    {"id": 1, "name": "thanksgiving", "slug": "thanksgiving"},
                    {"id": 2, "name": "homechef", "slug": "homechef"},
                    {"id": 3, "name": "potatoes", "slug": "potatoes"},
                ],
            }
        }

    @validator("language")
    def language_validator(cls, v: str):
        if v not in langs:
            return "en-US"
        return v

class CustomPageBase(CamelModel):
    name: str
    slug: Optional[str]
    position: int
    categories: list[RecipeCategoryResponse] = []

    class Config:
        orm_mode = True

    @validator("slug", always=True, pre=True)
    def validate_slug(slug: str, values):
        name: str = values["name"]
        calc_slug: str = slugify(name)

        if slug != calc_slug:
            slug = calc_slug

        return slug

class CustomPageOut(CustomPageBase):
    id: int

    class Config:
        orm_mode = True


from django.http import HttpResponse,HttpResponseRedirect
from .models import Question,Choice
from django.template import loader
from django.shortcuts import render,get_object_or_404
from django.http import Http404
from django.urls import reverse
from django.views import generic
from django.utils import timezone
from django.core.mail import send_mail
from django.core.mail import EmailMessage

def index(request):

    '''
    msg=EmailMessage('file','sending a file','sriharshanagulakonda@gmail.com',['jayakrishna7878@gmail.com'])
    msg.attach_file('/polls/detail.html')
    msg.send()

    for i in range(1,6):
        send_mail(
            'Hii raa edava',
            'edava  '+str(i),
            'sriharshanagulakonda@gmail.com',
        ['hemanthnambu@gmail.com'],
            fail_silently=False,
        )
    '''

    latest_question_list=Question.objects.order_by('pub_date')
    #template=loader.get_template('polls/index.html')
    context={
        'latest_question_list':latest_question_list,
    }
    #output="\n".join([str(q.id)+" "+str(q) for q in latest_question_list])
    return  HttpResponse('hii')#template.render(context,request))
    #return render(request,'polls/index.html',context)

def admin(request):
    return render(request,'admin/admin.html')
    #HttpResponse("<I'm admin</b>")

def add_question(request):
    return render(request,'admin/add_question.html')
    #HttpResponse('add question here')

def insert_question(request):
    try:
        #selected_choice=question.choice_set.get(pk=request.POST['choice'])
        q=Question(question_text=request.POST['question'],pub_date=timezone.now())
        x=q
        q.save()
        for i in range(1,4):
            x.choice_set.create(choice_text=request.POST['choice'+str(i)],votes=0)

    except Exception as e:
        q.delete()
        return render(request,'admin/add_question.html',{
            'error_message':e,#"You didn't selected a choice",
        })
    else:
        x.save()
        return HttpResponse('''
        question inserted''')

def edit_question(request):
    latest_question_list=Question.objects.all()
    return render(request,'admin/edit.html',{'latest_question_list':latest_question_list})

def change_question(request,question_id):
    question=Question.objects.get(pk=question_id)
    return render(request,'admin/change.html',{'question':question})

def update(request,question_id):
    q=get_object_or_404(Question,pk=question_id)
    q.question_text=request.POST['question']
    q.save()
    j=1
    for i in q.choice_set.all():
        i.choice_text=request.POST['choice'+str(j)]
        j+=1
        i.save()
    return HttpResponse('updated')

def detail(request,question_id):
    try:
        question=Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request,'polls/detail.html',{'question':question})
    #return HttpResponse("You are looking at %s." % question_id)

def results(request,question_id):
    question=get_object_or_404(Question,pk=question_id)
    return render(request,'polls/results.html',{'question':question})

    #response="You are looking at results of question %s."
    #return HttpResponse(response % question_id)

def vote(request,question_id):
    question=get_object_or_404(Question,pk=question_id)
    try:
        selected_choice=question.choice_set.get(pk=request.POST['choice'])
    except:
        return render(request,'polls/detail.html',{
            'question':question,
            'error_message':"You didn't selected a choice",
        })
    else:
        selected_choice.votes+=1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results',args=(question.id,)))
        #return HttpResponse("You're voting on question %s." % question_id)

'''

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'
    def get_queryset(self):
        return Question.objects.order_by('pub_date')

class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

class ResultsView(generic.DetailView):
    model = Question
    template_name='polls/results.html'

'''


from tensorflow import keras
import tf2onnx
from models.TCSVT import DownSampling, UpSampling, Scene_Understanding
import onnxruntime
import os
from onnxruntime.quantization import CalibrationDataReader
import data.pano_loader as loader
from data import data
from onnxruntime.quantization import quantize_static, QuantType, QuantFormat
from options import custom_func

pano_path = "/data3/awong/pano/M3D_low/"
train = loader.generate_dataframe("./splits/M3D_v1_train.yaml", pano_path)
train_generator = data.DataGenerator(
            train, batch_size=32, shuffle=False, wrap=64
        )

class MobileNetDataReader(CalibrationDataReader):
    def __init__(self, model_path):
        self.enum_data = None

        # Use inference session to get input shape.
        session = onnxruntime.InferenceSession(model_path, None)
        (_, _, height, width) = session.get_inputs()[0].shape
        self.input_name = session.get_inputs()[0].name

    def get_next(self):
        if self.enum_data is None:
            self.enum_data = iter(train_generator)

        vals = next(self.enum_data, None)
        if vals:
            return {self.input_name: vals[0]}
        return None

    def rewind(self):
        self.enum_data = None

def optimize_model(model_name, loss_function):
    custom_func["loss_function"] = loss_function
    model = keras.models.load_model(model_name, custom_objects=custom_func)
    output_path = model_name[:-3] + ".onnx"

    model_proto, _ = tf2onnx.convert.from_keras(model, opset=13, output_path=output_path)
    return output_path

def quantize_model(model_name, loss_function):
    if ".onnx" in model_name:
        input_model_path = model_name
    else:
        input_model_path = optimize_model(model_name, loss_function)
    output_model_path = input_model_path[:-5] + "_quant.onnx"
    dr = MobileNetDataReader(input_model_path)

    quantize_static(
        input_model_path,
        output_model_path,
        dr,
        quant_format=QuantFormat.QDQ,
        per_channel=False,
        weight_type=QuantType.QInt8,
        optimize_model=False,
    )
    return output_model_path


#GOAL" learn how to calculate and plot daily mean speed
# we want to create a plot where the y-axis is the average speed/per day and in the x-axis the time in days
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import datetime

textfile = "bird_tracking.csv"
birddata = pd.read_csv(textfile)
# What is printed
# Int64Index: 61920 entries, 0 to 61919
# Data columns (total 8 columns):
# altitude              61920 non-null int64
# date_time             61920 non-null object
# device_info_serial    61920 non-null int64
# direction             61477 non-null float64
# latitude              61920 non-null float64
# longitude             61920 non-null float64
# speed_2d              61477 non-null float64
# bird_name             61920 non-null object
# dtypes: float64(4), int64(2), object(2)
# memory usage: 4.3+ MB
# None

timestamps = []
for k in range(len(birddata)):
    timestamps.append(datetime.datetime.strptime(birddata.date_time.iloc[k][:-3], '%Y-%m-%d %H:%M:%S'))
birddata['timestamp'] = pd.Series(timestamps, index= birddata.index)
data = birddata[birddata.bird_name == 'Eric']
times = data.timestamp
speed2D = np.array(data.speed_2d)
elapsed_time = [time - times[0] for time in times]
elapsed_days = np.array(elapsed_time)/datetime.timedelta(days=1)

# gustavo
next_day = 1
avg_speed=0
count=1

time = []
speed= []
for i, d in enumerate(elapsed_days):
    if d > next_day :
        avg_speed /= count
        time.append(next_day-1)  # to start at 0
        speed.append(avg_speed)

        next_day +=1
        avg_speed=0
        count=1
    else:
        if ~np.isnan(speed2D[i]):
            avg_speed = (avg_speed + speed2D[i])
            count+=1

# course:
next_day = 1
inds= []
daily_mean_speed= []
for i, t in enumerate(elapsed_days):
    if t < next_day:
        inds.append(i)
    else:
        #compute mean speed
        daily_mean_speed.append(np.mean(data.speed_2d[inds]))
        next_day +=1
        inds = []

k=len(daily_mean_speed)
plt.figure(figsize=(8,6))
plt.plot(daily_mean_speed[0:k], label = 'course')
plt.plot(time[0:k], speed[0:k], label = 'gustavo')
plt.xlabel('Day')
plt.ylabel('Mean speed [m/s]')
plt.legend(loc='lower right')
plt.savefig('DailyMeanSpeed.pdf')


# The functions in this file are modified from:
# https://github.com/fgnt/pb_chime5/blob/master/pb_chime5/utils/numpy_utils.py

import re

import cupy as cp
from numpy.core.einsumfunc import _parse_einsum_input

def _normalize(op):
    op = op.replace(",", "")
    op = op.replace(" ", "")
    op = " ".join(c for c in op)
    op = op.replace(" * ", "*")
    op = op.replace("- >", "->")
    op = op.replace(". . .", "...")
    return op

def _shrinking_reshape(array, source, target):
    source, target = source.split(), target.replace(" * ", "*").split()

    if "..." in source:
        assert "..." in target, (source, target)
        independent_dims = array.ndim - len(source) + 1
        import string

        ascii_letters = [
            s for s in string.ascii_letters if s not in source and s not in target
        ]
        index = source.index("...")
        source[index : index + 1] = ascii_letters[:independent_dims]
        index = target.index("...")
        target[index : index + 1] = ascii_letters[:independent_dims]

    input_shape = {key: array.shape[index] for index, key in enumerate(source)}

    output_shape = []
    for t in target:
        product = 1
        if not t == "1":
            t = t.split("*")
            for t_ in t:
                product *= input_shape[t_]
        output_shape.append(product)

    return array.reshape(output_shape)

def _expanding_reshape(array, source, target, **shape_hints):

    try:  # Check number of inputs for unflatten operations
        assert len(re.sub(r".\*", "", source.replace(" ", ""))) == array.ndim, (
            array.shape,
            source,
            target,
        )
    except AssertionError:  # Check number of inputs for ellipses operations
        assert (
            len(re.sub(r"(\.\.\.)|(.\*)", "", source.replace(" ", ""))) <= array.ndim
        ), (array.shape, source, target)

    def _get_source_grouping(source):
        """
        Gets axis as alphanumeric.
        """

        source = " ".join(source)
        source = source.replace(" * ", "*")
        groups = source.split()
        groups = [group.split("*") for group in groups]
        return groups

    if "*" not in source:
        return array

    source, target = source.split(), target.replace(" * ", "*").split()

    if "..." in source:
        assert "..." in target, (source, target)
        independent_dims = array.ndim - len(source) + 1
        import string

        ascii_letters = [
            s for s in string.ascii_letters if s not in source and s not in target
        ]
        index = source.index("...")
        source[index : index + 1] = ascii_letters[:independent_dims]
        index = target.index("...")
        target[index : index + 1] = ascii_letters[:independent_dims]

    target_shape = []

    for axis, group in enumerate(_get_source_grouping(source)):
        if len(group) == 1:
            target_shape.append(array.shape[axis : axis + 1])
        else:
            shape_wildcard_remaining = True
            for member in group:
                if member in shape_hints:
                    target_shape.append([shape_hints[member]])
                else:
                    if shape_wildcard_remaining:
                        shape_wildcard_remaining = False
                        target_shape.append([-1])
                    else:
                        raise ValueError("Not enough shape hints provided.")

    target_shape = cp.concatenate(target_shape, 0)
    array = array.reshape(target_shape)
    return array

def morph(operation, array, reduce=None, **shape_hints):
    """This is an experimental version of a generalized reshape.
    See test cases for examples.
    """
    operation = _normalize(operation)
    source, target = operation.split("->")

    # Expanding reshape
    array = _expanding_reshape(array, source, target, **shape_hints)

    # Initial squeeze
    squeeze_operation = operation.split("->")[0].split()
    for axis, op in reversed(list(enumerate(squeeze_operation))):
        if op == "1":
            array = cp.squeeze(array, axis=axis)

    # Transpose
    transposition_operation = operation.replace("1", " ").replace("*", " ")
    try:
        in_shape, out_shape, (array,) = _parse_einsum_input(
            [transposition_operation.replace(" ", ""), array.get()]
        )

        if len(set(in_shape) - set(out_shape)) > 0:
            assert reduce is not None, (
                "Missing reduce function",
                reduce,
                transposition_operation,
            )

            reduce_axis = tuple(
                [i for i, s in enumerate(in_shape) if s not in out_shape]
            )
            array = reduce(array, axis=reduce_axis)
            in_shape = "".join([s for s in in_shape if s in out_shape])

        array = cp.einsum(f"{in_shape}->{out_shape}", array)
    except ValueError as e:
        msg = (
            f"op: {transposition_operation} ({in_shape}->{out_shape}), "
            f"shape: {cp.shape(array)}"
        )

        if len(e.args) == 1:
            e.args = (e.args[0] + "\n\n" + msg,)
        else:
            print(msg)
        raise

    # Final reshape
    source = transposition_operation.split("->")[-1]
    target = operation.split("->")[-1]

    return _shrinking_reshape(array, source, target)


from .sa_dataset_utils import PYCOX_DATASETS, ASAUR_DATASETS, DATASETS, PYCOX_DATASET_TO_FUNC, DATASET_TARGET_DECODER

from typing import Tuple
import numpy as np
import pandas as pd
from constants import RANDOM_STATE, TEST_SIZE, TRAIN_PATH, TEST_PATH, FULL_DATASETS_PATH, log
from sklearn.model_selection import train_test_split
import os
os.environ['R_HOME'] = '/Users/shakedcaspi/opt/anaconda3/envs/sa-proj/lib/R'

class SADataset(object):
    @classmethod
    def __init__(self, dataset_name: str) -> None:
        assert dataset_name in DATASETS, f"This dataset is not valid, choose one from {DATASETS}"

        self.dataset_name = dataset_name
        self.dataset = None
        self.X = None
        self.y = None

    @staticmethod
    def get_datasets() -> list:
        return DATASETS

    @staticmethod
    def get_downloaded_datasets() -> list:
        return [name.split(".csv")[0] for name in os.listdir(TRAIN_PATH)]

    @classmethod
    def load_dataset(self, train: bool = True) -> pd.DataFrame:

        full_dataset_path = os.path.join(
            FULL_DATASETS_PATH, f"{self.dataset_name}.csv")
        train_dataset_path = os.path.join(
            TRAIN_PATH, f"{self.dataset_name}.csv")
        test_dataset_path = os.path.join(TEST_PATH, f"{self.dataset_name}.csv")

        if self.dataset_name not in self.get_downloaded_datasets():  # if the dataset is not downloaded yet
            log("DOWNLOADING THE DATASET...", 1)

            if self.dataset_name in ASAUR_DATASETS:
                df = self._asaur_get_dataset()
            if self.dataset_name in PYCOX_DATASETS:
                df = self._pycox_get_dataset()

            # rename y columns to standart names
            duration, event = DATASET_TARGET_DECODER[self.dataset_name]
            df.rename(columns={duration: 'duration',
                      event: 'event'}, inplace=True)

            train_df, test_df = train_test_split(
                df, test_size=TEST_SIZE, random_state=RANDOM_STATE)

            df.to_csv(full_dataset_path, index=False)

            train_df.to_csv(train_dataset_path, index=False)
            log(f"TRAIN Dataset {self.dataset_name}, {train_df.shape[0]} samples", 1)
            test_df.to_csv(test_dataset_path, index=False)
            log(f"TEST Dataset {self.dataset_name}, {test_df.shape[0]} samples", 1)

        if train:
            df = pd.read_csv(train_dataset_path)
        else:
            df = pd.read_csv(test_dataset_path)

        self.dataset = df
        return df

    @classmethod
    def _asaur_get_dataset(self):
        import rpy2.robjects.packages as rpackages
        import rpy2.robjects as robjects
        from rpy2.robjects.vectors import StrVector
        from rpy2.robjects import pandas2ri
        from rpy2 import rinterface_lib
        utils = rpackages.importr('utils')
        utils.chooseCRANmirror(ind=1)
        # change the callbacks, all errors inside buf and can be printing if nessecary
        buf = []
        def f(x): buf.append(x)
        rinterface_lib.callbacks.consolewrite_print = f
        rinterface_lib.callbacks.consolewrite_warnerror = f

        packnames = ['asaur']
        names_to_install = [
            x for x in packnames if not rpackages.isinstalled(x)]
        if len(names_to_install) > 0:
            utils.install_packages(StrVector(names_to_install))
            log(f"DOWNLOAD {names_to_install} (R PACKAGES)", 1)

        if self.dataset_name == "prostateSurvival":
            robjects.r("df <- asaur::prostateSurvival")

            with (robjects.default_converter + pandas2ri.converter).context():
                df = robjects.conversion.get_conversion().rpy2py(
                    robjects.r["df"])
            # special preprocessing for prostateSurvival dataset
            df["grade"] = df["grade"].map({"mode": 1, "poor": 0})
            df["stage"] = df["stage"].map({"T1ab": 1, "T1c": 2, "T2": 3})
            df["ageGroup"] = df["ageGroup"].map(
                {"66-69": 1, "70-74": 2, "75-79": 3, "80+": 4})
            df = df[df["status"] != 2]

            feature_cols = df.drop(["status", "survTime"], axis=1).columns
            df[feature_cols] = df[feature_cols].astype('float32')

        if self.dataset_name == "hepatoCellular":
            robjects.r("df <- asaur::hepatoCellular")

            with (robjects.default_converter + pandas2ri.converter).context():
                df = robjects.conversion.get_conversion().rpy2py(
                    robjects.r["df"])

            df.drop(["Number", "RFS", "Recurrence"], axis=1, inplace=True)

            # imputation using mean value
            df.fillna(value=df.mean(), inplace=True)

        return df

    @classmethod
    def _pycox_get_dataset(self):

        func = PYCOX_DATASET_TO_FUNC[self.dataset_name]

        df = func.read_df()

        # special preprocessing for KKBOX dataset
        if self.dataset_name == "KKBOX":
            # remove olumns with missing values (there is a lot of missing values in each col)
            missing_vals_cols = list(df.columns[df.isna().sum(axis=0) > 0])
            # remove unnecessary columns
            missing_vals_cols += ["msno", "censor_duration"]
            df.drop(missing_vals_cols, axis=1, inplace=True)
            for col in list(df.select_dtypes(include=bool).columns) + list(df.select_dtypes(include=pd.CategoricalDtype).columns):
                df[col] = df[col].astype(np.int64)
        return df

    @classmethod
    def seperate_X_y(self, train: bool = True) -> Tuple[pd.DataFrame, pd.DataFrame]:
        if self.dataset is None:
            self.load_dataset(train)

        X = self.dataset.drop(["event", "duration"], axis=1)
        y = self.dataset[["event", "duration"]]
        self.X, self.y = X, y

        return X, y


from interpret_community.common.chained_identity import ChainedIdentity

class PureStructuredModelMixin(ChainedIdentity):
    """The base PureStructuredModelMixin API for explainers used on specific models.

    :param model: The grey box model to explain.
    :type model: A grey box model.
    """

    def __init__(self, model=None, **kwargs):
        """Initialize the PureStructuredModelExplainer.

        :param model: The grey box model to explain.
        :type model: A grey box model.
        """
        super(PureStructuredModelMixin, self).__init__(**kwargs)
        self._logger.debug("Initializing PureStructuredModelMixin")
        self.model = model


import telebot
from telebot import types
# your token
token="6184086339:AAF-9545ABC7Um99YmcAUzorxIeAJ5TgyFM"
bot=telebot.TeleBot(token)
my_chat_id='yourchatid'
corz_f = []
corz_d = []
corz_p = []
corz_b = []
corz_c = []
corz_n = []
f1 = True
f2 = True
f3 = True
f4 = True
f5 = True
f6 = True
f7 = True
f8 = True
f9 = True
f10 = True
f11 = True
f12 = True
f13 = True
f14 = True
f15 = True
pricem = ['Изначальная стоимость сайта без опций-3000']
priced = ['Цены услуг дизайна:', 'адаптивный дизайн - умножение конечной стоимости сайта на 1,6', 'Добавление страниц сайта - 3000р (на одной странице по умолчанию 9 блоков обычных и один функциональный)', 'Создание дизайна от 3000', 'Темный режим сайта - 4000р', 'Наполнение текстом и картинками - 3000р', ]
pricef = ['Цены услуг функционала:', 'Домен, хостинг - 6000 за пол года', 'Интернет магазин - от 10000', 'Блог - от 8000', 'CMS - от 8000', 'Функциональный блок - от 1000р', 'Seo - 15000', 'Форма обратной связи - 2000р', 'Настройка счетчиков аналитики - 2000р', 'Поддержка после окончания проекта - 2000р в месяц']
pl = []
po = []
def help(message):
    keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
    button46 = types.KeyboardButton(text="о нас")
    button47 = types.KeyboardButton(text="услуги")
    button48 = types.KeyboardButton(text="сделать заказ")
    button49 = types.KeyboardButton(text="консультация")
    button55 = types.KeyboardButton(text="цены")
    keyboard.add(button46, button47, button48, button49, button55)
    bot.send_message(message.chat.id,"вы потерялись? Ничего")
    bot.send_message(message.chat.id,"Кнопка -о нас- расскажет вам о нашей компании")
    bot.send_message(message.chat.id,"Кнопка -услуги- расскажет вам о каталоге наших дополнительных услугах")
    bot.send_message(message.chat.id,"Кнопка -консультация- поможет вам с определением вашего заказа")
    bot.send_message(message.chat.id,"Кнопка -заказ- поможет вам оставить заявку")
    bot.send_message(message.chat.id,"Кнопка -цены- поможет вам узнать цены на услуги")

def order_message(message):
    keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
    button5 = types.KeyboardButton(text="назад к меню")
    keyboard.add(button5)
    bot.send_message(message.chat.id,"Хотите сделать заказ?")
    bot.send_message(message.chat.id,"тогда напишите свои данные")

@bot.message_handler(commands=["start"])
def start_message(message):
    keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
    button1 = types.KeyboardButton(text="о нас")
    button2 = types.KeyboardButton(text="услуги")
    button3 = types.KeyboardButton(text="сделать заказ")
    button4 = types.KeyboardButton(text="консультация")
    button56 = types.KeyboardButton(text="цены")
    keyboard.add(button1, button2, button3, button4, button56)
    bot.send_message(message.chat.id,'Вас приветствует rgorodov.ru', reply_markup=keyboard)
    bot.send_message(message.chat.id,'как вам помочь?', reply_markup=keyboard)

def info_message(message):
    keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
    button5 = types.KeyboardButton(text="назад к меню")
    keyboard.add(button5)
    keyboard = types.InlineKeyboardMarkup()
    url_button = types.InlineKeyboardButton(text="переходите и узнайте больше:)", url="https://rgorodov.ru")
    keyboard.add(url_button)
    bot.send_message(message.chat.id,"ссылка на наш сайт", reply_markup=keyboard)

def cont(message):
     if corz_p == corz_n:
          bot.send_message(message.chat.id, "без прохождения консультации вы не можете сделать заказ")
          start2_message(message)
     else:
          bot.send_message(my_chat_id, f'новая заявка:{message.text}, корзина услуг-{corz_d}, заказ на тему:{corz_c}, {corz_b}, {corz_p}')
          bot.send_message(message.chat.id, "спасибо за заявку! оператор с вами в скорем времени свяжется!")

def start2_message(message):
    keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
    button1 = types.KeyboardButton(text="о нас")
    button2 = types.KeyboardButton(text="услуги")
    button3 = types.KeyboardButton(text="консультация")
    button4 = types.KeyboardButton(text="заказ")
    button55 = types.KeyboardButton(text="цены")
    keyboard.add(button1, button2, button3, button4, button55)
    bot.send_message(message.chat.id,'как вам помочь?', reply_markup=keyboard)

def make(message):
    keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
    button5 = types.KeyboardButton(text="назад к меню")
    button6 = types.KeyboardButton(text="дизайн")
    button7 = types.KeyboardButton(text="функционал")
    button30 = types.KeyboardButton(text="корзина")
    keyboard.add(button6, button7, button5, button30)
    bot.send_message(message.chat.id,"выберите раздел", reply_markup=keyboard)

def dis(message):
     keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
     button10 = types.KeyboardButton(text="Наполнение текстами и картинками")
     button11 = types.KeyboardButton(text="Адаптивный дизайн")
     button12 = types.KeyboardButton(text="Создание дизайна: Персонального или ультра")
     button13 = types.KeyboardButton(text="Темный режим")
     button23 = types.KeyboardButton(text="Дополнительные страницы")
     button26 = types.KeyboardButton(text="Назад в виды услуг")
     button27 = types.KeyboardButton(text="корзина")
     button28 = types.KeyboardButton(text="clear корзина")
     keyboard.add(button10, button11, button12, button13, button28, button26, button27, button23)
     bot.send_message(message.chat.id,"выберите услугу", reply_markup=keyboard)

def cohs(message):
     keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
     button32 = types.KeyboardButton(text="разработка сайта")
     button33 = types.KeyboardButton(text="разарботка тг бота")
     button42 = types.KeyboardButton(text="назад к меню")
     keyboard.add(button33, button32, button42)
     bot.send_message(message.chat.id,"что вас интересует?", reply_markup=keyboard)

def ord(message):
     keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
     button34 = types.KeyboardButton(text="одностраничный сайт")
     button35 = types.KeyboardButton(text="многостраничный сайт")
     button43 = types.KeyboardButton(text="назад к выбору разработки")
     keyboard.add(button34, button35, button43)
     bot.send_message(message.chat.id,"какое кол-во страниц на сайте вас интресует?", reply_markup=keyboard)

def ord2(message):
     keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
     button36 = types.KeyboardButton(text="меньше 5 блоков на сайте")
     button37 = types.KeyboardButton(text="от 5 до 10 блоков на сайте")
     button38 = types.KeyboardButton(text="от 10 до 15 блоков на сайте")
     button39 = types.KeyboardButton(text="больше 15 блоков на сайте")
     button44 = types.KeyboardButton(text="назад к выбору количества страниц на сайте")
     keyboard.add(button36, button37, button38, button39, button44)
     bot.send_message(message.chat.id,"сколько блоков вас интересует?", reply_markup=keyboard)

def ord3(message):
     keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
     button40 = types.KeyboardButton(text="да, интересует")
     button41 = types.KeyboardButton(text="нет, не интересует")
     button41 = types.KeyboardButton(text="очистить начальные услуги")
     button45 = types.KeyboardButton(text="назад к выбору количества блоков на сайте")
     keyboard.add(button40, button41, button45)
     bot.send_message(message.chat.id,"интересуют ли вас доп.услуги?", reply_markup=keyboard)

def fyn(message):
     keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
     button14 = types.KeyboardButton(text="CMS")
     button15 = types.KeyboardButton(text="SEO оптимизация")
     button16 = types.KeyboardButton(text="Форма обратной связи")
     button17 = types.KeyboardButton(text="Домен и хостинг")
     button18 = types.KeyboardButton(text="Создание функционала Интернет Магазина")
     button19 = types.KeyboardButton(text="Создание функционального блога")
     button20 = types.KeyboardButton(text="Поддержка сайта после окончания проекта")
     button21 = types.KeyboardButton(text="Функциональные блоки")
     button22 = types.KeyboardButton(text="Настройка счетчиков и аналитики")
     button25 = types.KeyboardButton(text="Назад в виды услуг")
     button24 = types.KeyboardButton(text="корзина")
     button31 = types.KeyboardButton(text="clear корзина")
     keyboard.add(button14, button15, button16, button17, button18, button19, button20, button21, button22, button25, button24, button31)
     bot.send_message(message.chat.id,"добавление в корзину функционала", reply_markup=keyboard)
def corz_d1(message):
     corz_d.append(message.text)
     bot.send_message(message.chat.id, f"В корзину добавлено: {message.text}")
def corz_f2(message):
     corz_f.append(message.text)
     bot.send_message(message.chat.id, f"В корзину добавлено: {message.text}")
def all_corz(message):
     bot.send_message(message.chat.id, f"В корзина дизайна:")
     corz_f1 = list(dict.fromkeys(corz_f))
     corz_d1 = list(dict.fromkeys(corz_d))
     for i in corz_d1:
          ff =0
          if i == 'Наполнение текстами и картинками':
               pl.append('3000')
          if i == 'Адаптивный дизайн':
               pl.append('0')
          if i == 'Создание дизайна: Персонального или ультра':
               pl.append('0')
          if i == 'Темный режим':
               pl.append('4000')
          if i == 'Дополнительные страницы':
               pl.append('5000')
          bot.send_message(message.chat.id, i)
     for i in pl:
          ff += int(i)
     bot.send_message(message.chat.id, f' Примерная цена дизайна:{ff}')
     bot.send_message(message.chat.id, f"В корзина функционала:")
     for i in corz_f1:
          bb = 0
          if i == 'Домен и хостинг':
               po.append('6000')
          if i == 'Создание функционала Интернет Магазина':
               po.append('10000')
          if i == 'Функциональные блоки':
               po.append('8000')
          if i == 'CMS':
               po.append('8000')
          if i == 'SEO оптимизация':
               po.append('15000')
          if i == 'Форма обратной связи':
               po.append('2000')
          if i == 'Настройка счетчиков и аналитики':
               po.append('2000')
          if i == 'Создание функционального блога':
               po.append('0')
          if i == 'Поддержка сайта после окончания проекта':
               po.append('2000')
          if i == 'SEO оптимизация':
               po.append('15000')
          bot.send_message(message.chat.id, i)
     for i in po:
          bb += int(i)
     bot.send_message(message.chat.id, f' Примерная функционала:{bb}')
     aa = bb + ff
     bot.send_message(message.chat.id, f' Примерная общяя цена:{aa}')

     yn(message)
def clear_corz(message):
     corz_f.clear()
     corz_d.clear()
     bot.send_message(message.chat.id, 'корзина очистена')
def yn(message):
     keyboard = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
     button50 = types.KeyboardButton(text="ДА, готов сделать заказ")
     button51 = types.KeyboardButton(text="НЕТ, хочу продолжить покупки")
     keyboard.add(button50, button51)
     bot.send_message(message.chat.id,"готовы сделать заказ?", reply_markup=keyboard)
def ready(message):
     cont(message)
     bot.send_message(message.chat.id,"")
def notready(message):
     bot.send_message(message.chat.id,"Продолжайте покупки")
     start2_message(message)
def clear_main(message):
     corz_b.clear()
     corz_c.clear()
     corz_p.clear()
     bot.send_message(message.chat.id, 'корзина очистена')
def pr(message):
     for i in priced:
          bot.send_message(message.chat.id, i)
     for elem in pricef:
          bot.send_message(message.chat.id, elem)

@bot.message_handler(content_types=["text"])
def menu_message(message):
     if message.text.lower() == 'о нас':
          info_message(message)
     elif message.text.lower() == 'сделать заказ':
          bot.send_message(message.chat.id, "будем рады вас обслужить! оставьте свои контактные данные:)")
          bot.register_next_step_handler(message,cont)
     elif message.text.lower() == 'услуги':
          make(message)
     elif message.text.lower() == 'заказ':
          bot.send_message(message.chat.id, "будем рады вас обслужить! оставьте свои контактные данные:)")
          bot.register_next_step_handler(message,cont)
     elif message.text.lower() == 'назад к меню':
          start2_message(message)
     elif message.text.lower() == 'дизайн':
          dis(message)
     elif message.text.lower() == 'функционал':
          fyn(message)
     elif message.text.lower() == "наполнение текстами и картинками":
          if f1 ==  True:
               f1 == False
               corz_d1(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'адаптивный дизайн':
          if f2 ==  True:
               f2 == False
               corz_d1(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'создание дизайна: персонального или ультра':
          if f3 ==  True:
               f3 == False
               corz_d1(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'темный режим':
          if f4 ==  True:
               f4 == False
               corz_d1(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'дополнительные страницы':
          if f5 ==  True:
               f5 == False
               corz_d1(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'cms':
          if f6 ==  True:
               f6 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'seo оптимизация':
          if f7 ==  True:
               f7 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'форма обратной связи':
          if f8 ==  True:
               f8 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'домен и хостинг':
          if f9 ==  True:
               f9 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'создание функционала интернет магазина':
          if f10 ==  True:
               f10 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'создание функционального блога':
          if f11 ==  True:
               f11 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'поддержка сайта после окончания проекта':
          if f12 ==  True:
               f12 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'функциональные блоки':
          if f13 ==  True:
               f13 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'поддержка сайта после окончания проекта':
          if f14 ==  True:
               f14 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'настройка счетчиков и аналитики':
          if f15 ==  True:
               f15 == False
               corz_f2(message)
          else:
               bot.send_message(message.chat.id, 'товар уже добавлен')
               dis(message)
     elif message.text.lower() == 'корзина':
          all_corz(message)
     elif message.text.lower() == 'назад в виды услуг':
          make(message)
     elif message.text.lower() == 'clear корзина':
          clear_corz(message)
     elif message.text.lower() == 'консультация':
          cohs(message)
     elif message.text.lower() == 'разработка сайта':
          corz_c.append(message.text)
          ord(message)
     elif message.text.lower() == 'разарботка тг бота':
          corz_c.append(message.text)
          ord(message)
     elif message.text.lower() == 'одностраничный сайт':
          corz_p.append(message.text)
          ord2(message)
     elif message.text.lower() == 'многостраничный сайт':
          corz_p.append(message.text)
          ord2(message)
     elif message.text.lower() == 'меньше 5 блоков на сайте':
          corz_b.append(message.text)
          ord3(message)
     elif message.text.lower() == 'от 5 до 10 блоков на сайте':
          corz_b.append(message.text)
          ord3(message)
     elif message.text.lower() == 'от 10 до 15 блоков на сайте':
          corz_b.append(message.text)
          ord3(message)
     elif message.text.lower() == 'больше 15 блоков на сайте':
          corz_b.append(message.text)
          ord3(message)
     elif message.text.lower() == 'да, интересует':
          make(message)
     elif message.text.lower() == 'нет, не интересует':
          bot.send_message(message.chat.id, "будем рады вас обслужить! оставьте свои контактные данные:)")
          bot.register_next_step_handler(message,cont)
     elif message.text.lower() == 'назад к выбору разработки':
          corz_c.clear()
          cohs(message)
     elif message.text.lower() == 'назад к выбору количества страниц на сайте':
          corz_p.clear()
          ord(message)
     elif message.text.lower() == 'назад к выбору количества блоков на сайте':
          corz_b.clear()
          ord2(message)
     elif message.text.lower() == 'да, интересует':
          make(message)
     elif message.text.lower() == 'да, готов сделать заказ':
          bot.send_message(message.chat.id, "будем рады вас обслужить! оставьте свои контактные данные:)")
          bot.register_next_step_handler(message,cont)
     elif message.text.lower() == 'нет, хочу продолжить покупки':
          notready(message)
     elif message.text.lower() == 'очистить начальные услуги':
          notready(message)
     elif message.text.lower() == 'цены':
          pr(message)
     else:
          help(message)

if __name__=='__main__':
    bot.infinity_polling()

for  i in range(0, 5):
    i += 1
    print('error')

    '''
    bot.send_message(message.chat.id,'Услуги разработки сайтов:', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Дополнительные страницы(по умолчанию одна)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Темный режим(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'CMS(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Функциональные блоки(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Наполнение текстами и картинками(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Настройка счетчиков и аналитики(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'CMS(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'SEO оптимизация(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Адаптивный дизайн(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Форма обратной связи(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Домен и хостинг(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Создание функционала Интернет Магазина(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Создание функционального блога(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Поддержка сайта после окончания проекта(по умолчанию нет)', reply_markup=keyboard)-
    bot.send_message(message.chat.id,'Создание дизайна "Персонального или ультра"(по умолчанию нет)', reply_markup=keyboard)-
    '''


import pygame

screen = pygame.display.set_mode((900, 800))
# left margin
lm = 20
# top margin
tm = 20

class Square:
    def __init__(self, row, column, w, h, value, base):
        self.row = row
        self.temp_value = 0
        self.column = column
        self.value = value
        self.base = base
        self.w = w
        self.h = h
        self.clicked = False

    # Square Styling
    def render(self, scr):
        font = pygame.font.SysFont("Arial", 50)
        temp_font = pygame.font.SysFont("Arial", 40)
        separation = self.w / 9
        x = self.column * separation + lm
        y = self.row * separation + tm
        if self.temp_value != 0 and self.value == 0:
            output = temp_font.render(str(self.temp_value), 1, (255, 0, 0))
            scr.blit(
                output,
                (
                    x + (separation / 2.1 - output.get_width() / 2),
                    y + (separation / 2.1 - output.get_height() / 2),
                ),
            )
        elif self.value != 0 and self.base == True:
            output = font.render(str(self.value), 1, (0, 0, 0))
            scr.blit(
                output,
                (
                    x + (separation / 2.1 - output.get_width() / 2),
                    y + (separation / 2.1 - output.get_height() / 2),
                ),
            )
        elif self.value != 0 and self.base == False:
            output = font.render(str(self.value), 1, (50, 90, 200))

            scr.blit(
                output,
                (
                    x + (separation / 2.1 - output.get_width() / 2),
                    y + (separation / 2.1 - output.get_height() / 2),
                ),
            )
        if self.clicked:
            pygame.draw.rect(screen, (50, 90, 155), (x, y, separation, separation), 4)

    def fill_cell_color(self, scr ):
        font = pygame.font.SysFont("Arial", 50)
        separation = self.w / 9
        x = self.column * separation + lm
        y = self.row * separation + tm
        if (self.value != 0):
            output = font.render(str(self.value), 1, (255, 90, 200))
            scr.blit(
                output,
                (
                    x + (separation / 2.1 - output.get_width() / 2),
                    y + (separation / 2.1 - output.get_height() / 2),
                ),
            )

    # Sets a value for the square
    def set_value(self, value):
        self.value = value

    # Sets a temporary value to the square (not commited)
    def set_temp_value(self, temp_value):
        self.temp_value = temp_value


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time, datetime
class qcontact(object):
    def __init__(self, ctype = None, name = None, uin = None, fromdict = None):
        if fromdict:
            self.ctype = fromdict['ctype']
            self.name = fromdict['name']
            self.uin = fromdict['uin']
            self.role = fromdict['role']
            self.createtime = fromdict['time']
        else:
            self.ctype = ctype
            self.name = name
            self.uin = uin
            self.role = 'undef'
            self.createtime = time.time()
    def __repr__(self):
        return "util.qcontact(fromdict = " + repr({'ctype': self.ctype, 'name': self.name, 'uin': self.uin, 'role': self.role, 'time': self.createtime}) + ")"

class logger():
    def __init__(self, filepath, loglevel):
        self.filepath = filepath + '\\' + time.ctime()[4:].replace(' ','_').replace(':','') + '.log'
        with open(self.filepath, 'w', encoding='utf-8') as logfile:
            logfile.write('Log file created.')
        if loglevel.upper() == 'ERROR':
            self.loglevel = 1
        elif loglevel.upper() == 'WARN':
            self.loglevel = 2
        elif loglevel.upper() == 'INFO':
            self.loglevel = 3
        elif loglevel.upper() == 'DEBUG':
            self.loglevel = 4
        else:
            self.loglevel = 4
        self.INFO('Logger initiate complete.')
    def ERROR(self, message):
        if self.loglevel > 0:
            message = '[ERROR]'+ self.gettime() + message
            print(message)
            self.writelog('\n' + message)
    def WARN(self, message):
        if self.loglevel > 1:
            message = '[WARN] '+ self.gettime() + message
            print(message)
            self.writelog('\n' + message)
    def INFO(self, message):
        if self.loglevel > 2:
            message = '[INFO] '+ self.gettime() + message
            print(message)
            self.writelog('\n' + message)
    def DEBUG(self, message):
        if self.loglevel > 3:
            message = '[DEBUG]'+ self.gettime() + message
            print(message)
            self.writelog('\n' + message)
    def gettime(self):
        return '[' + str(datetime.datetime.now())[:-7] + ']'
    def writelog(self, message):
        with open(self.filepath, 'a', encoding='utf-8') as logfile:
            logfile.write(message)

def findcontact(bot, uin, guin = None, type = 'buddy'):
    if type == 'group':
        if not uin in bot.contact['group'].keys():
            UpdateGroup(bot, uin)
        if not uin in bot.contact['group'].keys():
            bot.contact['group'][uin] = {'qcontact':qcontact('group', '群'+uin, uin), 'member':{}}
        if isOld(bot.contact['group'][uin]['qcontact']):
            UpdateGroup(bot, uin)
        return bot.contact['group'][uin]['qcontact']
    elif type == 'discuss':
        if not uin in bot.contact['discuss'].keys():
            bot.contact['discuss'][uin] = {'qcontact':qcontact('discuss', '讨论组' + uin, uin), 'member':{}}
        return bot.contact['discuss'][uin]['qcontact']
    elif type == 'buddy':
        if uin in bot.contact['buddy'].keys():
            if isOld(bot.contact['buddy'][uin]):
                UpdatePerson(bot, uin, guin, type)
        else:
            UpdatePerson(bot, uin, guin, type)
        return bot.contact['buddy'][uin]
    elif type == 'group-member':
        try:
            if uin in bot.contact['group'][guin]['member'].keys():
                if isOld(bot.contact['group'][guin]['member'][uin]):
                    UpdateGroupMember(bot, guin)
            else:
                UpdateGroupMember(bot, guin)
            if not uin in bot.contact['group'][guin]['member'].keys():
                UpdatePerson(bot, uin, guin, type)
        except:
            UpdatePerson(bot, uin, guin, type)
        return bot.contact['group'][guin]['member'][uin]
    elif type == 'discuss-member':
        if uin in bot.contact['discuss'][guin]['member'].keys():
            if isOld(bot.contact['discuss'][guin]['member'][uin]):
                UpdatePerson(bot, uin, guin, type)
        else:
            UpdatePerson(bot, uin, guin, type)
        return bot.contact['discuss'][guin]['member'][uin]
def isOld(contact):
    if contact.ctype == 'group':
        return time.time() - contact.createtime > 7200
    elif contact.ctype == 'group-member':
        return time.time() - contact.createtime > 1800
    else:
        return time.time() - contact.createtime > 300

def UpdateGroup(bot, group = None):
    grouplist = bot.bot.get_group_list()
    for g in grouplist:
        uin = str(g['group_id'])
        name = g['group_name']
        qcon = qcontact('group', name, uin)
        if uin in bot.contact['group'].keys():
            bot.contact['group'][uin]['qcontact'] = qcon
        else:
            bot.contact['group'][uin] = {'qcontact':qcon, 'member':{}}
        if uin == group or not group:
            UpdateGroupMember(bot, uin)

def UpdateGroupMember(bot, group):
    memberlist = bot.bot.get_group_member_list(group_id = int(group))
    for mem in memberlist:
        if len(mem['card']) > 0:
            memname = mem['card']
        else:
            memname = mem['nickname']
        memqcon = qcontact('group-member', memname, str(mem['user_id']))
        memqcon.role = mem['role']
        bot.contact['group'][group]['member'][str(mem['user_id'])] = memqcon

def UpdatePerson(bot, uin, guin = None, type = 'buddy'):
    if type == 'buddy':
        try:
            name = bot.bot.get_stranger_info(user_id = int(uin))['nickname']
        except:
            name = ''
        bot.contact['buddy'][uin] = qcontact('buddy', name, uin)
    elif type == 'group-member':
        try:
            name = bot.bot.get_stranger_info(user_id = int(uin))['nickname']
        except:
            name = ''
        if not guin in bot.contact['group'].keys():
            bot.contact['group'][guin] = {'qcontact':qcontact('group', '', guin), 'member':{}}
        bot.contact['group'][guin]['member'][uin] = qcontact('group-member', name, uin)
    elif type == 'discuss-member':
        try:
            name = bot.bot.get_stranger_info(user_id = int(uin))['nickname']
        except:
            name = ''
        bot.contact['discuss'][guin]['member'][uin] = qcontact('discuss-member', name, uin)


from __future__ import annotations

import datetime
import logging
import re
import urllib.parse
from dataclasses import dataclass
from datetime import datetime
from enum import Enum

import prov.model

from mlflow2prov.domain.constants import ProvType
from mlflow2prov.utils.prov_utils import document_factory, qualified_name

log = logging.getLogger(__name__)

@dataclass
class User:
    name: str
    email: str
    username: str = ""
    prov_role: str | None = None

    def __post_init__(self):
        self.email = self.email.lower()

    @classmethod
    def from_username_str(cls, username: str, name: str = "", email: str = "") -> User:
        return cls(name=name, email=email, username=username)

    @classmethod
    def from_splitable_user_string(cls, user_str: str) -> User:
        regex = re.compile("[^>]<([^>]+)>")
        strlist = list(filter(None, regex.split(user_str)))

        return cls(name=strlist[0], email=strlist[1])

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)
        email = urllib.parse.quote_plus(self.email, safe="", encoding=None, errors=None)

        return qualified_name(f"User?name={name}&email={email}")

    def to_prov(self) -> prov.model.ProvAgent:
        prov_attributes = [
            ("name", self.name),
            ("email", self.email),
            ("username", self.username),
            (prov.model.PROV_ROLE, self.prov_role),
            (prov.model.PROV_TYPE, ProvType.USER),
        ]

        return prov.model.ProvAgent(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class File:
    name: str
    path: str
    commit: str

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)
        path = urllib.parse.quote_plus(self.path, safe="", encoding=None, errors=None)
        commit = urllib.parse.quote_plus(
            self.commit, safe="", encoding=None, errors=None
        )

        return qualified_name(f"File?name={name}&path={path}&commit={commit}")

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("path", self.path),
            ("commit", self.commit),
            (prov.model.PROV_TYPE, ProvType.FILE),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class FileRevision(File):
    status: str
    file: File | None = None
    previous: FileRevision | None = None

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)
        path = urllib.parse.quote_plus(self.path, safe="", encoding=None, errors=None)
        commit = urllib.parse.quote_plus(
            self.commit, safe="", encoding=None, errors=None
        )
        status = urllib.parse.quote_plus(
            self.status, safe="", encoding=None, errors=None
        )

        return qualified_name(
            f"FileRevision?name={name}&path={path}&commit={commit}&status={status}"
        )

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("path", self.path),
            ("status", self.status),
            (prov.model.PROV_TYPE, ProvType.FILE_REVISION),
        ]

        return prov.model.ProvEntity(
            document_factory(),
            self.prov_identifier,
            prov_attributes,
        )

@dataclass
class Commit:
    sha: str
    title: str
    message: str
    author: User | None
    committer: User | None
    parents: list[str]
    authored_at: datetime
    committed_at: datetime

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        sha = urllib.parse.quote_plus(self.sha, safe="", encoding=None, errors=None)

        return qualified_name(f"Commit?sha={sha}")

    def to_prov(self) -> prov.model.ProvActivity:
        prov_attributes = [
            ("sha", self.sha),
            ("title", self.title),
            ("message", self.message),
            ("authored_at", self.authored_at),
            ("committed_at", self.committed_at),
            (prov.model.PROV_ATTR_STARTTIME, self.authored_at),
            (prov.model.PROV_ATTR_ENDTIME, self.committed_at),
            (prov.model.PROV_TYPE, ProvType.COMMIT),
        ]

        return prov.model.ProvActivity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class Creation:
    uid: str
    resource_type: str
    start_time: datetime
    end_time: datetime | None = (
        None  # also allow None, because a run may be still running
    )

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        uid = urllib.parse.quote_plus(self.uid, safe="", encoding=None, errors=None)
        resource_type = urllib.parse.quote_plus(
            self.resource_type, safe="", encoding=None, errors=None
        )

        return qualified_name(f"Creation?uid={uid}&resource_type={resource_type}")

    def to_prov(self) -> prov.model.ProvActivity:
        prov_attributes = [
            ("uid", self.uid),
            (prov.model.PROV_ATTR_STARTTIME, self.start_time),
            (prov.model.PROV_ATTR_ENDTIME, self.end_time) if self.end_time else None,
            (prov.model.PROV_TYPE, ProvType.CREATION),
        ]

        return prov.model.ProvActivity(
            document_factory(), self.prov_identifier, prov_attributes
        )

    @classmethod
    def from_experiment(cls, experiment: Experiment) -> Creation:
        return cls(
            uid=experiment.experiment_id,
            resource_type=ProvType.EXPERIMENT,
            start_time=experiment.created_at,
            end_time=experiment.last_updated if experiment.last_updated else None,
        )

    @classmethod
    def from_run(cls, run: Run) -> Creation:
        return cls(
            uid=run.run_id,
            resource_type=ProvType.RUN,
            start_time=run.start_time,
            end_time=run.end_time if run.end_time else None,
        )

    @classmethod
    def from_registered_model(cls, registered_model: RegisteredModel) -> Creation:
        return cls(
            uid=registered_model.name,
            resource_type=ProvType.REGISTERED_MODEL,
            start_time=registered_model.created_at,
            end_time=registered_model.last_updated_at
            if registered_model.last_updated_at
            else None,
        )

    @classmethod
    def from_registered_model_version(
        cls, registered_model_version: RegisteredModelVersion
    ) -> Creation:
        return cls(
            uid=f"{registered_model_version.name}-version-{registered_model_version.version}",
            resource_type=ProvType.REGISTERED_MODEL_VERSION,
            start_time=registered_model_version.created_at,
            end_time=registered_model_version.last_updated_at
            if registered_model_version.last_updated_at
            else None,
        )

@dataclass
class Deletion:
    uid: str
    resource_type: str
    start_time: datetime
    end_time: datetime | None  # also allow None, because a run may be still running

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        uid = urllib.parse.quote_plus(self.uid, safe="", encoding=None, errors=None)
        resource_type = urllib.parse.quote_plus(
            self.resource_type, safe="", encoding=None, errors=None
        )

        return qualified_name(f"Deletion?uid={uid}&resource_type={resource_type}")

    def to_prov(self) -> prov.model.ProvActivity:
        prov_attributes = [
            ("uid", self.uid),
            (prov.model.PROV_ATTR_STARTTIME, self.start_time),
            (prov.model.PROV_ATTR_ENDTIME, self.end_time),
            (prov.model.PROV_TYPE, ProvType.DELETION),
        ]

        return prov.model.ProvActivity(
            document_factory(), self.prov_identifier, prov_attributes
        )

    @classmethod
    def from_experiment(cls, experiment: Experiment) -> Deletion:
        return cls(
            uid=experiment.experiment_id,
            resource_type=ProvType.EXPERIMENT,
            start_time=experiment.last_updated,
            end_time=experiment.last_updated,
        )

    @classmethod
    def from_run(cls, run: Run) -> Deletion:
        return cls(
            uid=run.run_id,
            resource_type=ProvType.RUN,
            start_time=run.end_time if run.end_time else run.start_time,
            end_time=run.end_time,
        )

    @classmethod
    def from_registered_model_version(
        cls, registered_model_version: RegisteredModelVersion
    ) -> Deletion:
        return cls(
            uid=f"{registered_model_version.name}-version-{registered_model_version.version}",
            resource_type=ProvType.REGISTERED_MODEL_VERSION,
            start_time=registered_model_version.last_updated_at,
            end_time=registered_model_version.last_updated_at,
        )

@dataclass
class Experiment:
    experiment_id: str
    name: str
    user: User | None
    artifact_location: str
    lifecycle_stage: LifecycleStage
    tags: list[ExperimentTag] | None
    created_at: datetime
    last_updated: datetime

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        experiment_id = urllib.parse.quote_plus(
            self.experiment_id, safe="", encoding=None, errors=None
        )
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)

        return qualified_name(f"Experiment?experiment_id={experiment_id}&name={name}")

    @property
    def creation(self) -> Creation:
        return Creation.from_experiment(self)

    @property
    def deletion(self) -> Deletion:
        return Deletion.from_experiment(self)

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("experiment_id", self.experiment_id),
            ("name", self.name),
            ("artifact_location", self.artifact_location),
            ("lifecycle_stage", LifecycleStage.to_string(self.lifecycle_stage)),
            (prov.model.PROV_TYPE, ProvType.EXPERIMENT),
            (prov.model.PROV_TYPE, ProvType.COLLECTION),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class Run:
    run_id: str
    name: str
    experiment_id: str
    user: User | None
    status: RunStatus
    start_time: datetime
    end_time: datetime | None
    lifecycle_stage: LifecycleStage | None
    artifact_uri: str | None
    metrics: list[Metric] | None
    params: list[Param] | None
    tags: list[RunTag] | None
    artifacts: list[Artifact] | None
    model_artifacts: list[ModelArtifact] | None
    note: str | None
    source_type: SourceType | None
    source_name: str | None
    source_git_commit: str | None
    source_git_branch: str | None
    source_git_repo_url: str | None

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        run_id = urllib.parse.quote_plus(
            self.run_id, safe="", encoding=None, errors=None
        )
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)

        return qualified_name(f"Run?run_id={run_id}&name={name}")

    @property
    def creation(self) -> Creation:
        return Creation.from_run(self)

    @property
    def deletion(self) -> Deletion:
        return Deletion.from_run(self)

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("run_id", self.run_id),
            ("name", self.name),
            ("status", RunStatus.to_string(self.status)),
            ("lifecycle_stage", LifecycleStage.to_string(self.lifecycle_stage))
            if self.lifecycle_stage
            else None,
            ("artifact_uri", self.artifact_uri),
            ("note", self.note),
            (prov.model.PROV_TYPE, ProvType.RUN),
            (prov.model.PROV_TYPE, ProvType.COLLECTION),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class Metric:
    run_id: str
    name: str
    value: float
    timestamp: datetime
    step: int

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        run_id = urllib.parse.quote_plus(
            self.run_id, safe="", encoding=None, errors=None
        )
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)
        step = urllib.parse.quote_plus(
            str(self.step), safe="", encoding=None, errors=None
        )

        return qualified_name(f"Metric?run_id={run_id}&name={name}&step={step}")

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("value", self.value),
            ("timestamp", self.timestamp),
            ("step", self.step),
            (prov.model.PROV_TYPE, ProvType.METRIC),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class Param:
    run_id: str
    name: str
    value: str

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        run_id = urllib.parse.quote_plus(
            self.run_id, safe="", encoding=None, errors=None
        )
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)

        return qualified_name(f"Param?run_id={run_id}&name={name}")

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("value", self.value),
            (prov.model.PROV_TYPE, ProvType.PARAM),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class Artifact:
    run_id: str
    path: str
    is_dir: bool
    file_size: int  # in bytes

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        run_id = urllib.parse.quote_plus(
            self.run_id, safe="", encoding=None, errors=None
        )
        path = urllib.parse.quote_plus(self.path, safe="", encoding=None, errors=None)

        return qualified_name(f"Artifact?run_id={run_id}&path={path}")

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("path", self.path),
            ("is_dir", self.is_dir),
            ("file_size", self.file_size),
            (prov.model.PROV_TYPE, ProvType.ARTIFACT),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class ModelArtifact(Artifact):
    artifact: Artifact | None = None

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        run_id = urllib.parse.quote_plus(
            self.run_id, safe="", encoding=None, errors=None
        )
        path = urllib.parse.quote_plus(self.path, safe="", encoding=None, errors=None)

        return qualified_name(f"ModelArtifact?run_id={run_id}&path={path}")

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("path", self.path),
            ("is_dir", self.is_dir),
            ("file_size", self.file_size),
            (prov.model.PROV_TYPE, ProvType.MODEL_ARTIFACT),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class RegisteredModel:
    name: str
    created_at: datetime
    last_updated_at: datetime
    description: str | None
    user: User | None
    versions: list[RegisteredModelVersion]
    tags: list[RegisteredModelTag]

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)

        return qualified_name(f"RegisteredModel?name={name}")

    @property
    def creation(self) -> Creation:
        return Creation.from_registered_model(self)

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("created_at", self.created_at),
            ("last_updated_at", self.last_updated_at),
            ("description", self.description),
            (prov.model.PROV_TYPE, ProvType.REGISTERED_MODEL),
            (prov.model.PROV_TYPE, ProvType.COLLECTION),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class RegisteredModelVersion:
    name: str
    version: str
    created_at: datetime
    last_updated_at: datetime
    description: str | None
    user: User | None
    registered_model_version_stage: RegisteredModelVersionStage | None
    source_path: str | None
    run_id: str | None
    status: str
    status_message: str | None
    tags: list[RegisteredModelVersionTag] | None
    run_link: str | None

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)
        version = urllib.parse.quote_plus(
            self.version, safe="", encoding=None, errors=None
        )

        return qualified_name(f"RegisteredModelVersion?name={name}&version={version}")

    @property
    def creation(self) -> Creation:
        return Creation.from_registered_model_version(self)

    @property
    def deletion(self) -> Deletion:
        return Deletion.from_registered_model_version(self)

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("version", self.version),
            ("created_at", self.created_at),
            ("last_updated_at", self.last_updated_at),
            ("description", self.description),
            (
                "registered_model_version_stage",
                RegisteredModelVersionStage.to_string(
                    self.registered_model_version_stage
                ),
            )
            if self.registered_model_version_stage
            else None,
            ("source_path", self.source_path),
            ("status", self.status),
            ("status_message", self.status_message),
            ("run_link", self.run_link),
            (prov.model.PROV_TYPE, ProvType.REGISTERED_MODEL_VERSION),
            (prov.model.PROV_TYPE, ProvType.COLLECTION),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class Tag:
    name: str
    value: str

@dataclass
class ExperimentTag(Tag):
    experiment_id: str

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)
        experiment_id = urllib.parse.quote_plus(
            self.experiment_id, safe="", encoding=None, errors=None
        )

        return qualified_name(
            f"ExperimentTag?experiment_id={experiment_id}&name={name}"
        )

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("value", self.value),
            (prov.model.PROV_TYPE, ProvType.EXPERIMENT_TAG),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class RunTag(Tag):
    run_id: str

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        run_id = urllib.parse.quote_plus(
            self.run_id, safe="", encoding=None, errors=None
        )
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)

        return qualified_name(f"RunTag?run_id={run_id}&name={name}")

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("value", self.value),
            (prov.model.PROV_TYPE, ProvType.RUN_TAG),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class RegisteredModelTag(Tag):
    registered_model_name: str

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        registered_model_name = urllib.parse.quote_plus(
            self.registered_model_name, safe="", encoding=None, errors=None
        )
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)

        return qualified_name(
            f"RegisteredModelTag?registered_model_name={registered_model_name}&name={name}"
        )

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("value", self.value),
            (prov.model.PROV_TYPE, ProvType.REGISTERED_MODEL_TAG),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

@dataclass
class RegisteredModelVersionTag(Tag):
    registered_model_name: str
    registered_model_version: str

    @property
    def prov_identifier(self) -> prov.model.QualifiedName:
        registered_model_name = urllib.parse.quote_plus(
            self.registered_model_name, safe="", encoding=None, errors=None
        )
        registered_model_version = urllib.parse.quote_plus(
            self.registered_model_version, safe="", encoding=None, errors=None
        )
        name = urllib.parse.quote_plus(self.name, safe="", encoding=None, errors=None)

        return qualified_name(
            f"RegisteredModelVersionTag?registered_model_name={registered_model_name}&registered_model_version={registered_model_version}&name={name}"
        )

    def to_prov(self) -> prov.model.ProvEntity:
        prov_attributes = [
            ("name", self.name),
            ("value", self.value),
            (prov.model.PROV_TYPE, ProvType.REGISTERED_MODEL_VERSION_TAG),
        ]

        return prov.model.ProvEntity(
            document_factory(), self.prov_identifier, prov_attributes
        )

class LifecycleStage(Enum):
    ACTIVE = "active"
    DELETED = "deleted"

    def __str__(self) -> str:
        return self.value

    @staticmethod
    def from_string(stage_str: str) -> LifecycleStage:
        if stage_str in ("active", "Active", "ACTIVE"):
            return LifecycleStage.ACTIVE
        elif stage_str in ("deleted", "Deleted", "DELETED"):
            return LifecycleStage.DELETED
        else:
            raise NotImplementedError

    @staticmethod
    def to_string(stage: LifecycleStage) -> str:
        return str(stage)

class RunStatus(Enum):
    RUNNING = "running"
    SCHEDULED = "scheduled"
    FINISHED = "finished"
    FAILED = "failed"
    KILLED = "killed"

    def __str__(self) -> str:
        return self.value

    @staticmethod
    def from_string(status_str: str) -> RunStatus:
        if status_str in ("running", "Running", "RUNNING"):
            return RunStatus.RUNNING
        elif status_str in ("scheduled", "Scheduled", "SCHEDULED"):
            return RunStatus.SCHEDULED
        elif status_str in ("finished", "Finished", "FINISHED"):
            return RunStatus.FINISHED
        elif status_str in ("failed", "Failed", "FAILED"):
            return RunStatus.FAILED
        elif status_str in ("killed", "Killed", "KILLED"):
            return RunStatus.KILLED
        else:
            raise NotImplementedError

    @staticmethod
    def to_string(status: RunStatus) -> str:
        return str(status)

class SourceType(Enum):
    NOTEBOOK = "Notebook"
    JOB = "Job"
    PROJECT = "Project"
    LOCAL = "Local"
    RECIPE = "Recipe"
    UNKNOWN = "Unknown"

    def __str__(self) -> str:
        return self.value

    @staticmethod
    def from_string(source_str: str) -> SourceType:
        if source_str in ("notebook", "Notebook", "NOTEBOOK"):
            return SourceType.NOTEBOOK
        elif source_str in ("job", "Job", "JOB"):
            return SourceType.JOB
        elif source_str in ("project", "Project", "PROJECT"):
            return SourceType.PROJECT
        elif source_str in ("local", "Local", "LOCAL"):
            return SourceType.LOCAL
        elif source_str in ("recipe", "Recipe", "RECIPE"):
            return SourceType.RECIPE
        elif source_str in ("unknown", "Unknown", "UNKNOWN"):
            return SourceType.UNKNOWN
        else:
            raise NotImplementedError

    @staticmethod
    def to_string(source: SourceType) -> str:
        return str(source)

class RegisteredModelVersionStage(Enum):
    NONE = "None"
    STAGING = "Staging"
    PRODUCTION = "Production"
    ARCHIVED = "Archived"
    DELETED_INTERNAL = "Deleted_Internal"

    def __str__(self) -> str:
        return self.value

    @staticmethod
    def from_string(stage_str: str) -> RegisteredModelVersionStage:
        if stage_str in ("none", "None", "NONE"):
            return RegisteredModelVersionStage.NONE
        elif stage_str in ("staging", "Staging", "STAGING"):
            return RegisteredModelVersionStage.STAGING
        elif stage_str in ("production", "Production", "PRODUCTION"):
            return RegisteredModelVersionStage.PRODUCTION
        elif stage_str in ("archived", "Archived", "ARCHIVED"):
            return RegisteredModelVersionStage.ARCHIVED
        elif stage_str in ("deleted_internal", "Deleted_Internal", "DELETED_INTERNAL"):
            return RegisteredModelVersionStage.DELETED_INTERNAL
        else:
            raise NotImplementedError

    @staticmethod
    def to_string(stage: RegisteredModelVersionStage) -> str:
        return str(stage)


"""cis498Final URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from django.contrib.auth import views as auth_views

from cis498 import views as cisviews

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^$', cisviews.home, name='home'),
    url(r'^login/$', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
    url(r'^logout/$', auth_views.LogoutView.as_view(), name='logout'),
    url(r'^stafflogin/$', cisviews.stafflogin, name='stafflogin'),
    url(r'^signup/$', cisviews.signup, name='signup'),
    url(r'^staffhome/$', cisviews.staffhome, name='staffhome'),
    url(r'^updateOrders/(?P<item_id>[-\w]+)/$', cisviews.updateOrders, name='updateOrders'),
    url(r'^updateDriverOrders/(?P<item_id>[-\w]+)/$', cisviews.updateDriverOrders, name='updateDriverOrders'),
    url(r'^checkout/$', cisviews.checkout, name='checkout'),
    url(r'^ordertracker/$', cisviews.ordertracker, name='ordertracker'),
    url(r'^driverhome/$', cisviews.driverhome, name='driverhome'),
    url(r'^add_to_cart/(?P<item_id>[-\w]+)$', cisviews.add_to_cart, name='add_to_cart'),
    url(r'^delete_from_cart/(?P<item_id>[-\w]+)$', cisviews.delete_from_cart, name='delete_from_cart'),
    url(r'^editMenuItem/$', cisviews.editMenuItem, name='editMenuItem'),
]


import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import pandas as pd
from colorama import init
import sys

init(strip=not sys.stdout.isatty())
from termcolor import cprint
from pyfiglet import figlet_format
from re import sub
from decimal import Decimal
from twilio.rest import Client
import config

# -----------------------------------------------------------------------------------------------------------------------
# Twilio API
account_sid = config.account_sid
auth_token = config.auth_token
client = Client(account_sid, auth_token)

# Welcome Banner
text = "NBA TOPShot Price Monitor"
cprint(figlet_format(text, font="standard"), "green")

# Prints description of the script
print("\n\nThis script checks an excel sheet for players and their corresponding prices."
      "\nThen searches NBATopShot to see if the price is lower than the ones from the excel."
      "\nIf the prices are lower then it will send a text and update the excel sheet!\n")

time.sleep(18)

# Chrome options if wanted to use it headless
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--window-size=192,1080")
chrome_options.add_argument("--start-maximized")

# Defines where the driver path is
driver_path = r"C:\Users\\Downloads\chromedriver_win32\chromedriver.exe"

# The first option is for headless the second option will display the browser

# browser = webdriver.Chrome(chrome_options=chrome_options, executable_path=driver_path)
browser = webdriver.Chrome(executable_path=driver_path)

# To have a divider when providing output to screen
divider = "-----------------------------------------------------------------------------------------"
# To track how many times the script has checked prices
iteration = 0

site_maint = 0

# The beginning of the while loop to constantly check prices and update the excel sheet
while True:

    # Tracking how many iterations and printing it out
    iteration += 1
    print("\nIteration: " + str(iteration))

    # The three lines below define where the excel file and what to read from the excel file
    file_name = r'C:\Users\\Downloads\NBATopShot_V2\NBATopShot\input.xlsx'
    sheet = 'Input'
    sheet2 = 'Output'
    select_columns = 'A:D'

    # This reads the excel file into a dataframe to use the data in the code and prints out what the script is checking for
    df = pd.read_excel(io=file_name, sheet_name=sheet, usecols=select_columns)
    print("\nThe list of links and players it's checking for:\n")
    print(df)

    # This reads the second output sheet to make sure we don't overwrite the data when making updates
    trigger_df = pd.read_excel(io=file_name, sheet_name=sheet2, usecols=select_columns)

    # creates a list of items from the columns on the excel sheet
    links = df['Links'].tolist()
    prices = df['Prices'].tolist()
    players = df['Players'].tolist()

    # converting the prices from the excel from string to floats to be able to compare prices
    [float(i) for i in prices]

    # an empty list to store the prices of the moments from the website
    current_price_list = []

    # This for loop iterates through the list of links and pulls the price from each moment
    # it then converts those prices to decimal and appends it to the list above
    for i in range(len(links)):
        while True:
            try:
                browser.get(links[i])
                # Printing out the link it's pulling the price for so if the script breaks you can know which link isn't
                # working to remove from the excel sheet
                print("\n\nGetting the current price for: " + str(links[i]))
                # give the browser time to load the page before searching for the price
                time.sleep(2)
                # If the website makes any changes on how it displays data the line below might not work to pull the price
                # Also if the page does not load in time or if the site isn't responding it won't be able to  pull the price
                # If you see the page loaded but it didn't pull the price that means you need to increase the sleep time above
                span_element = browser.find_element_by_xpath(
                    "/html/body/div[1]/div/main/div[3]/div/div[3]/div/div[2]/div[1]/div[1]/span")
                current_price = span_element.text
                break
            except:
                site_maint += 1
                if site_maint == 1:
                    message = ("The site seems to be under maintenance. Will keep trying to load the site.")
                    txt_message = client.messages \
                        .create(
                        body=message,
                        from_=config.tw_cell,
                        to=config.per_cell
                    )
                    print(txt_message.sid)
                    continue
                else:
                    continue
                break

        current_price = Decimal(sub(r'[^\d.]', '', current_price))
        current_price_list.append(current_price)

    writer = pd.ExcelWriter(file_name, engine='xlsxwriter')
    workbook = writer.book
    worksheet = workbook.add_worksheet('Input')
    writer.sheets['Input'] = worksheet
    worksheet2 = workbook.add_worksheet('Output')
    writer.sheets['Output'] = worksheet2

    # This for loop compares the prices from the website to the ones on the excel sheet.
    for i in range(len(current_price_list)):
        if current_price_list[i] < prices[i]:
            print("\n\nThe price for: " + str(players[i]) + " is lower.")
            trigger_df = trigger_df.append(
                [{'Players': str(players[i]), 'Links': str(links[i]), 'Prices': str(prices[i])}], ignore_index=True)
            df = df[df.Links != links[i]]
            message = ("The current price for " + str(players[i]) + " has been triggered at: " + str(current_price_list[
                                                                                i]) + ". Here's the link to make the purchase if you would like to make a purchase: " + str(
                links[i]))
            txt_message = client.messages \
                .create(
                body=message,
                from_=config.tw_cell,
                to=config.per_cell
            )
            print(txt_message.sid)

        else:
            print("\nThe current price for " + str(players[i]) + " is higher than the check from the input.xlsx\n")

    print(divider)

    # Updating both excel sheet
    trigger_df.to_excel(writer, sheet_name='Output', startrow=0, startcol=0, index=False)
    df.to_excel(writer, sheet_name='Input', startrow=0, startcol=0, index=False)
    worksheet.set_column(0, 0, 15)
    worksheet.set_column(1, 1, 50)
    worksheet2.set_column(0, 0, 15)
    worksheet2.set_column(1, 1, 50)
    writer.save()

    # The time between each iteration
    time.sleep(21)