from contextlib import asynccontextmanager
from datetime import datetime

RAPID_POSITION = 'G00'
LINEAR_MOVE = 'G01'
CIRCULAR_CLOCKWISE_MOVE = 'G02'
CIRCULAR_ANTICLOCKWISE_MOVE = 'G03'
PAUSE = 'G04'
SET_ORIGIN = 'G10'
USE_INCHES = 'G20'
USE_MM = 'G21'
RETURN_HOME = 'G28'
SERVO_CLOCKWISE_MOVE = 'M3'

class ScriptStage(object):
    reason = ''

    def __str__(self):
        return self.reason

    def as_json(self):
        return {
            'message': self.reason,
        }

class ChangePenStage(ScriptStage):
    def __init__(self,colour):
        self.reason = f'Change the pen to {colour}'
        self.colour = colour

    def as_json(self):
        data = super().as_json()
        data.update({
            'colour': self.colour,
        })
        return data

class SerialException(Exception):
    pass

class GCodeSender(object):

    transform_fn = lambda p: p
    # A transformation applied to all points

    speed = 2000
    # Default feed rate, in mm/minute

    RX_BUFFER_SIZE = 50
    # Size of the device's input buffer

    WAIT_TIME = 0.01

    PEN_UP_POSITION = 0
    PEN_DOWN_POSITION = 50

    MIN_MOVE = 0.1
    # Minimum distance to bother moving

    INTERRUPT_PERIOD = 1
    # The amount of time to spend running commands before interrupting and letting the rest of the event loop continue

    def __init__(self, device, flip_x = False, flip_y = False, flip_z = False, number_precision=3, immediate=False, debug=False):
        """
            Initialise a GCode sender.

            This sends GRBL-compatible commands by default, with the pen holder controlled by a servo.
            For other plotters, you should create a subclass of this and override the methods to produce different commands.

            Arguments:
                device: A pySerial Serial object
                flip_x: Should x coordinates be flipped? +x is mapped to -x
                flip_y: Should y coordinates be flipped? +y is mapped to -y
                flip_z: Should z coordinates be flipped? +z is mapped to -z
                number_precision: The number of decimal places to write numbers.
        """
        self.device = device
        self.flip_x = flip_x
        self.flip_y = flip_y
        self.flip_z = flip_z
        self.number_precision = number_precision

        #self.device.reset_input_buffer()

        self.staged_script = []

        self.immediate = immediate
        self.debug = debug

        self.current_pos = (0,0)

    def reset_connection(self, device):
        self.device = device

    def format_number(self, n):
        """
            Format a number for use in GCode.
            Rounds to `self.number_precision`.

            Argument:
                n - float

            Returns:
                string
        """

        return ('{:.' + str(self.number_precision) + 'f}').format(n)

    def format_coordinates(self, position, axes=('X','Y','Z')):
        """
            Format a set of 2D or 3D coordinates for GCode.

            Arguments:
                position - (float,float) or (float,float,float)
                axes - the names of the axes

            Returns
                list of strings
        """

        return [axis+self.format_number(n) for axis,n in zip(axes,position)]

    def transform_coordinates(self,coordinates):
        """
        Transform a pair of coordinates into the machine's coordinates.

        At the moment: apply flips.
        """
        return [-n if flip else n for n,flip in zip(self.transform_fn(coordinates), (self.flip_x, self.flip_y, self.flip_z))]

    def get_output(self):
        """
            Get a line of output from the plotter.

            Returns:
                string
        """

        out = ''
        while True:
            r = self.device.read_until()
            if r and r not in (b'\r\n',b'ok\r\n'):
                out += r.decode('ascii')
            else:
                break
        return out

    def send_command(self,command,arguments=[],immediate=False):
        """
        Send a command to the machine.

        Arguments:
            command: the g-code, for example 'G00'
            arguments: a list of string arguments.
            immediate: if true, run the command immediately. Otherwise, add it to the staged script.
        """

        line = ' '.join([command]+arguments)+'\n'
        if not immediate:
            self.staged_script.append(line)
        else:
            self.run_script([line])

    async def run_script(self,script=None, startline=0):
        """
            Run lines from the staged script until self.INTERRUPT_PERIOD seconds have elapsed, a `ScriptStage` object is reached, or the end of the script is reached.

            Arguments:
                script - a list of commands or `ScriptStage` objects
                startline - the index of the line to start from.

            Returns:
                (line, message) - the next line to evaluate, and a `ScriptStage` object or None
        """

        if script is None:
            script = self.staged_script

        if self.debug:
            print("running script")
            print(script)

        s = self.device

        if startline==0:
            try:
                s.reset_input_buffer()
            except Exception as e:
                raise SerialException()

            s.write(b'\r\n')
            s.readline()

        o = ''

        progress = 0

        t1 = datetime.now()

        i = 0

        for i,line in enumerate(script[startline:],startline):
            if isinstance(line,ScriptStage):
                return i+1, line
            # Send the command to the machine
            s.write(line.encode('ascii')) # Send g-code block to grbl
            oline = s.readline().decode('ascii').strip()
            o += oline
            t2 = datetime.now()
            if (t2-t1).total_seconds()> self.INTERRUPT_PERIOD:
                return i, None

        return i+1, None

    def before_script(self):
        """
            This is run by the `script` context manager before any other commands.
        """
        self.return_home()

    def after_script(self):
        """
            This is run by the `script` context manager at the end of the context.
        """
        self.return_home()

    @asynccontextmanager
    async def script(self,transform_fn=lambda p: p):
        """
            A context manager to stage a script for the plotter.

            Example:
                async with plotter.script():
                    plotter.move((0,0))
                    plotter.line((10,10))

            Argument:
                transform_fn - a function which applies a transformation to all points sent through the plotter.
        """
        try:
            self.transform_fn = transform_fn
            self.before_script()
            self.staged_script = []
            self.colour = None
            yield self
        finally:
            self.after_script()
            script = self.staged_script

    def move(self, position):
        """
            Move the pen up, then move the plotter to the given position, then move the pen down.
            Doesn't move if the distance from the current position is less than `self.MIN_MOVE`.

            Argument:
                position - (float,float)
        """
        x1,y1 = self.current_pos
        x2,y2 = position
        dx,dy = x2-x1,y2-y1
        d = dx*dx+dy*dy
        if d>self.MIN_MOVE**2:
            self.pen_up()
            self.send_command(RAPID_POSITION,self.format_coordinates(self.transform_coordinates(position)))
            self.pen_down()

        self.current_pos = position

    def line(self, position, speed=None):
        """
        Move to the given coordinates.

        Arguments:
            position: the coordinates to move to: a tuple of either two or three numbers.
            speed: optional speed to move, in mm/minute. If not given, the machine's most recent speed is used.
        """

        tposition = self.transform_coordinates(position)
        args = self.format_coordinates(tposition)

        if speed is None:
            speed = self.speed

        args.append('F'+self.format_number(speed))

        self.send_command(LINEAR_MOVE,args)

        self.current_pos = position

    def arcto(self, position, radius, speed=None, clockwise=True):
        """
            Draw a circular arc to the given position.

            Arguments:
                position - (float,float) - the position to move to.
                radius - float - the radius of the circle.
                speed - float - the speed to move, in mm/hour
                clockwise - if True, draw the clockwise arc between the two points, otherwise anti-clockwise.
        """
        tposition = self.transform_coordinates(position)

        if self.flip_x:
            clockwise = not clockwise
        if self.flip_y:
            clockwise = not clockwise

        args = self.format_coordinates(tposition)+['R'+self.format_number(radius)]

        command = CIRCULAR_CLOCKWISE_MOVE if clockwise else CIRCULAR_ANTICLOCKWISE_MOVE

        self.send_command(command, args)

        self.current_pos = position

    def move_pen(self,position):
        """
            Move the pen to the given position.

            Argument:
                position - float
        """
        self.send_command(SERVO_CLOCKWISE_MOVE,['S'+self.format_number(position)])

    def pen_up(self):
        """
            Move the pen up, to `self.PEN_UP_POSITION`.
        """
        self.move_pen(self.PEN_UP_POSITION)

    def pen_down(self):
        """
            Move the pen down, to `self.PEN_DOWN_POSITION`.
        """
        self.move_pen(self.PEN_DOWN_POSITION)

    def get_status(self):
        """
            Get the status output from the plotter.

            Returns:
                string
        """
        self.device.write(b'?')
        return self.get_output().strip()

    def return_home(self):
        """
            Move the pen up, then move the plotter to its home position.
            Unless you change it, home is (0,0).
        """
        if self.current_pos != (0,0):
            self.pen_up()
            self.send_command(RETURN_HOME)

        self.current_pos = (0,0)

    def change_pen(self, colour):
        """
            Get the plotter ready to change pen: move the plotter to its home position, and keep the pen up.
            Adds a `ChangePenStage` line to the script.

            Argument:
                colour - the colour to change to.
        """
        if self.colour != colour:
            self.return_home()
            self.pen_up()
            self.staged_script.append(ChangePenStage(colour))
            self.move(self.current_pos)
        self.colour = colour


from datetime import datetime

def fabricar_leilao(cur, id_, descricao='teste', criador='c153c124-7daa-4328-8f04-1dd824f5c309', data=None, diferenca_minima=100):
  cur.execute(f"""
    insert into leiloes (id, descricao, criador, data, diferenca_minima)
    values (%s, %s, %s, %s, %s)
  """, (
    id_,
    descricao,
    criador,
    data if data is not None else datetime.now(),
    diferenca_minima
  ))

def fabricar_lance(cur, id_, id_leilao, comprador='8f1061a8-a687-436a-8b1b-7a302994474a', valor=100, data=None):
  cur.execute(f"""
    insert into lances (id, id_leilao, comprador, valor, data)
    values (%s, %s, %s, %s, %s)
  """, (
    id_,
    id_leilao,
    comprador,
    valor,
    data if data is not None else datetime.now()
  ))


#!/usr/bin/env python3

import requests
import os
import hashlib
import io

def on_vocareum():
    return os.path.exists('.voc')

def get_url_base():
    return "https://cse6040.gatech.edu/datasets/us-flights/"

def get_data_path(filebase=""):
    if on_vocareum():
        DATA_PATH = "./resource/asnlib/publicdata/"
    else:
        DATA_PATH = ""
    return f"{DATA_PATH}{filebase}"

def download(file, local_dir=None, url_base=None, checksum=None):
    if local_dir is None: local_dir = get_data_path()
    if url_base is None: url_base = get_url_base()
    assert (local_dir is not None) and (url_base is not None)

    local_file = "{}{}".format(local_dir, file)
    if not os.path.exists(local_file):
        if url_base is None:
            url_base = "https://cse6040.gatech.edu/datasets/"
        url = "{}{}".format(url_base, file)
        print("Downloading: {} ...".format(url))
        r = requests.get(url)
        with open(local_file, 'wb') as f:
            f.write(r.content)

    if checksum is not None:
        with io.open(local_file, 'rb') as f:
            body = f.read()
            body_checksum = hashlib.md5(body).hexdigest()
            assert body_checksum == checksum, \
                "Downloaded file '{}' has incorrect checksum: '{}' instead of '{}'".format(local_file,
                                                                                body_checksum,
                                                                                checksum)
    print("'{}' is ready!".format(file))

def download_airport_dataset():
    datasets = {'L_AIRPORT_ID.csv': 'e9f250e3c93d625cce92d08648c4bbf0',
                'L_CITY_MARKET_ID.csv': 'f430a16a5fe4b9a849accb5d332b2bb8',
                'L_UNIQUE_CARRIERS.csv': 'bebe919e85e2cf72e7041dbf1ae5794e',
                'us-flights--2017-08.csv': 'eeb259c0cdd00ff1027261ca0a7c0332',
                'flights_atl_to_lax_soln.csv': '4591f6501411de90af72693cdbcc08bb',
                'origins_top10_soln.csv': 'de85c321c45c7bf65612754be4567086',
                'dests_soln.csv': '370f4c632623616b3bf26b6f79993fe4',
                'dests_top10_soln.csv': '4c7dd7edf48c4d62466964d6b8c14184',
                'segments_soln.csv': '516a78d2d9d768d78bfb012b77671f38',
                'segments_outdegree_soln.csv': 'b29d60151c617ebafd3a1c58541477c8'
               }
    for filename, checksum in datasets.items():
        download(filename, checksum=checksum)

# Pandas-based
def canonicalize_tibble(X):
    var_names = sorted(X.columns)
    Y = X[var_names].copy()
    Y.sort_values(by=var_names, inplace=True)
    Y.reset_index(drop=True, inplace=True)
    return Y

# Pandas-based
def tibbles_are_equivalent (A, B):
    A_canonical = canonicalize_tibble(A)
    B_canonical = canonicalize_tibble(B)
    cmp = A_canonical.eq(B_canonical)
    return cmp.all().all()

# eof


"""
File: recursive.py

Prints a trace of a recursive function.
"""

import os

def displayFiles(pathname):
    """Returns name of file and its contents"""
    if os.path.isfile(pathname):
        name = os.path.basename(pathname)
        openFile = open(pathname, "r")
        fileContents = openFile.readlines()
        for eachContent in fileContents:
            print(eachContent)

    elif os.path.isdir(pathname):
        getDirectories = os.listdir(pathname)
        for eachItem in getDirectories:
            completePath = os.path.join(pathname, eachItem)
            print("Filename: ", completePath)
            isdirectory = os.path.isdir(completePath)
            if isdirectory or os.path.isfile(completePath):
                displayFiles(completePath)

"""A simple test."""
pathname = input("Enter the filename or directory path: ")
displayFiles(pathname)


import tensorflow as tf
from PIL import Image, ImageOps
import numpy as np
import matplotlib.pyplot as plt
from keras.datasets import mnist

model=tf.keras.models.load_model('MNIST/MNIST_Model')
(x_train,y_train),(x_test,y_test)=mnist.load_data()

image=Image.open() #'picture'
image_gray = ImageOps.grayscale(image)
image_small = image_gray.resize((28,28))

# n = np.random.randint(len(x_train))
# img = x_train[n]
# print(y_train[n])
# x_trial = x_train[y_train==2]
# y_trial = y_train[y_train ==2]

#img = x_trial[0]

img=np.asarray(image_small)
plt.imshow(img)
plt.show()
#print(img.shape)

tf.keras.utils.normalize(img)
img=img.reshape(1,28,28,1)
prediction = model.predict(img)[0]
prediction_list = prediction.tolist()
max_value = max(prediction_list)
max_index = prediction_list.index(max_value)
print("The Predicted number is {}".format(max_index))

#print(y_trial)
#print(model.weights)


# 0123 4567
# 0000 0000
# RRR
def getSeatID(seatCode):
    seatRow = seatCode[0:7]
    seatCol = seatCode[7:]

    rowLeftIndex, rowRightIndex = 0, 128
    colLeftIndex, colRightIndex = 0, 8

    # Row
    for letter in seatRow:
        if letter == "F":
            rowRightIndex = (rowLeftIndex + rowRightIndex) // 2
        else:
            rowLeftIndex = (rowLeftIndex + rowRightIndex) // 2
    row = (rowLeftIndex + rowRightIndex) // 2

    # Col
    for letter in seatCol:
        if letter == "L":
            colRightIndex = (colLeftIndex + colRightIndex) // 2
        else:
            colLeftIndex = (colLeftIndex + colRightIndex) // 2
    col = (colRightIndex + colLeftIndex) // 2
    return row * 8 + col

maxSeatID = -1
seatList = []
with open("input.txt", "r") as handle:
    for line in handle:
        seatCode = line.strip()
        seatID = getSeatID(seatCode)
        maxSeatID = max(maxSeatID, seatID)
        seatList.append(seatID)
print(f"highest seat ID: {maxSeatID}")
# print(f"seats: {sorted(seatList)}")

# part 2
seatList.sort()
for i in range(len(seatList) - 1):
    if seatList[i + 1] - seatList[i] > 1:
        print(f"Your seat: {seatList[i] + 1}")
        break


import sys
import os
import seq

def make_info_table(clusterd,idn, outfile):
    cli = {}
    clns = []
    spls = {}
    for i in os.listdir(clusterd):
        if ".fa" not in i:
            continue
        sps = set()
        num = 0
        avl = 0
        for j in seq.read_fasta_file_iter(clusterd+"/"+i):
            sps.add(idn[j.name])
            if idn[j.name] not in spls:
                spls[idn[j.name]] = []
            spls[idn[j.name]].append(i)
            num += 1
        cli[i] = sps
        clns.append([i,len(sps)])
    clns = sorted(clns, key=lambda x: x[1], reverse=True)
    keep = []
    if len(spls) > 20:
        for i in clns:
            if i[1] >= 4:
                keep.append(i)
    else:
        keep = clns
    outfile = open(outfile,"w")
    outfile.write("species")
    for i in keep:
        outfile.write(","+i[0])
    outfile.write("\n")
    for j in spls:
        outfile.write(j)
        for i in keep:
            if j in cli[i[0]]:
                outfile.write(",x")
            else:
                outfile.write(",")
        outfile.write("\n")
    outfile.close()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("python "+sys.argv[0]+" maindir")
        sys.exit(0)

    cld = sys.argv[1]
    #take off the trailing slash if there is one
    if cld[-1] == "/":
        cld = cld[0:-1]
    idn = {}
    tf = open(cld+"/"+cld.split("/")[-1]+".table","r")
    for i in tf:
        spls = i.strip().split("\t")
        idn[spls[3]] = spls[4]
    tf.close()

    count = 0

    for root, dirs, files in os.walk(cld,topdown=False):
        if "clusters" in root:
            continue
        if "clusters" in dirs:
            make_info_table(root+"/clusters",idn, root+"/info.csv")
            count += 1


# -*-coding:utf-8 -*-
# @Author   ：pr1s0n
# @Time     : 2020/4/23 15:21
# @FileNAme : generation.py
# @Blog     : http://www.pr1s0n.com
# 生成器和迭代器
# 如何得到自定义的迭代器：
# 在函数内一旦存在yield关键字，调用函数并不会执行函数体代码
# 会返回一个生成器对象，生成器即自定义的迭代器

def my_range(start,stop,step=1):
    while start < stop:
        yield start
        start += step

for n in my_range(0,155,2):
    print(n)

'''
什么是可迭代对象，什么是迭代器对象
    可迭代对象都有__iter__方法
    迭代器对象既有__iter__也有__next__
    和return不同的是，yield可以多次使用
迭代器优缺点
    优点：
        1. 获得了一种不依赖索引的迭代方案
        2. 惰性计算（能够进行无限次计算但是占用极小内存）
    缺点：
        1. 一次性
for循环原理
    for x in 可迭代对象: # 可迭代对象__iter__() ->迭代器对象 ->next(迭代器对象)
        print(x)

如果函数体中有yield，再去调用函数，函数中的代码不会直接执行。只有在函数被调用后执行next才可以被作为生成器执行

'''


from flask import render_template, abort, url_for, jsonify, request
from src.models.Genre import Genre
from src.models.Artist import Artist,artist_genre
from src.models.Venue import Venue, venue_genre
from src.models.Show import Show
from typing import Optional

from src import app,db

@app.route('/')
def index():
    return "yoo"

@app.route('/create/genre',methods=['GET', 'POST'])
def create_genre():
    json_object = request.json
    name= json_object['name']
    genre = Genre(name=name)
    db.session.add(genre)
    db.session.commit()
    print(Genre.query.all())
    return jsonify({"response":"Genre has been created!"})

@app.route('/create/artist',methods=['GET', 'POST'])
def create_artist():
    json_object = request.json
    name= json_object['name']
    city = json_object['city']
    phone = json_object['phone']
    fb_link = json_object['fb_link']
    artist = Artist(name=name,city=city,phone=int(phone),fb_link=fb_link)
    genre = Genre.query.filter_by(name=json_object['genres']).first()
    artist.genres.append(genre)
    db.session.add(artist)
    db.session.commit()
    print(Artist.query.all())
    return jsonify({"response":"Artist has been created!"})

@app.route('/create/venue',methods=['GET', 'POST'])
def create_venue():
    json_object = request.json
    name= json_object['name']
    city = json_object['city']
    phone = json_object['phone']
    fb_link = json_object['fb_link']
    venue = Venue(name=name,city=city,phone=int(phone),fb_link=fb_link)
    genre = Genre.query.filter_by(name=json_object['genres']).first()
    venue.genres.append(genre)
    db.session.add(venue)
    db.session.commit()
    print(Venue.query.first().name)
    return jsonify({"response":"Venue has been created!"})

@app.route('/create/show',methods=['GET', 'POST'])
def create_show():
    json_object = request.json
    # artist_name= json_object['artist_name']
    # venue_name = json_object['venue_name']
    # start_time = json_object['start_time']
    # artist = Artist.query.filter_by(name=artist_name).first()
    # venue = Venue.query.filter_by(name=venue_name).first()
    artist_id = json_object['id_artist']
    id_venue = json_object['id_venue']
    start_time = json_object['start_time']

    show = Show(id_artist=artist_id,id_venue=id_venue,start_time=start_time)
    db.session.add(show)
    db.session.commit()
    print(Show.query.first().start_time)
    return jsonify({"response":"Show has been created!"})

def to_dict(table,data,joined=None):
    table_cols = []
    table_cols += [column.key for column in table.__table__.columns]
    all_data_json = {table.__table__.name : []}
    for element in data:
        data_json = {}
        for col in table_cols:
            data_json[col]=  getattr(element,col)
        if(joined):
            print(getattr(element,joined.__table__.name))
            data_json[joined.__table__.name] = to_dict(joined,getattr(element,joined.__table__.name))
        all_data_json[table.__table__.name].append(data_json)
    return all_data_json[table.__table__.name]

def to_dict_single(table,data,joined=None):
    table_cols = []
    table_cols += [column.key for column in table.__table__.columns]
    all_data_json = {table.__table__.name : []}
    data_json = {}
    for col in table_cols:
        data_json[col]=  getattr(data,col)
    if(joined):
        print(getattr(data,joined.__table__.name))
        data_json[joined.__table__.name] = to_dict(joined,getattr(data,joined.__table__.name))
    all_data_json[table.__table__.name].append(data_json)
    return all_data_json[table.__table__.name]

@app.route('/artists')
def get_artists():
    artists = Artist.query.all()
    artists_json = to_dict(Artist,artists,Genre)
    return jsonify({"artists":artists_json})

@app.route('/genres')
def get_genres():
    genres = Genre.query.all()
    genres_json = to_dict(Genre,genres)
    return jsonify({"genres":genres_json})

@app.route('/venues')
def get_venues():
    venues = Venue.query.all()
    venues_json = to_dict(Venue,venues,Genre)
    return jsonify({"venues":venues_json})

@app.route('/shows')
def get_shows():
    shows = Show.query.all()
    shows_json = to_dict(Show,shows)
    return jsonify({"shows":shows_json})

@app.route("/genre/<int:genre_id>")
def get_genre(genre_id):
    genre = Genre.query.get_or_404(genre_id)
    genre_json = to_dict_single(Genre,genre)
    return jsonify({"genre":genre_json})

@app.route("/show/<int:show_id>")
def get_show(show_id):
    show = Show.query.get_or_404(show_id)
    show_json = to_dict_single(Show,show)
    return jsonify({"show":show_json})

@app.route("/venue/<int:venue_id>")
def get_venue(venue_id):
    venue = Venue.query.get_or_404(venue_id)
    venue_json = to_dict_single(Venue,venue,Genre)
    return jsonify({"venue":venue_json})

@app.route("/artist/<int:artist_id>")
def get_artist(artist_id):
    artist = Artist.query.get_or_404(artist_id)
    artist_json = to_dict_single(Artist,artist,Genre)
    return jsonify({"artist":artist_json})

@app.route("/genre/<int:genre_id>/delete",methods=['POST','GET'])
def delete_genre(genre_id):
    genre = Genre.query.get_or_404(genre_id)
    try :
        db.session.delete(genre)
        db.session.commit()
    except:
        pass
    return jsonify({"genre":f"genre with id {genre_id} deleted"})

@app.route("/venue/<int:venue_id>/delete",methods=['POST','GET'])
def delete_venue(venue_id):
    venue = Venue.query.get_or_404(venue_id)
    try :
        db.session.delete(venue)
        db.session.commit()
    except:
        print("cant")
        return jsonify({"venue":f"cant :venue with id {venue_id} already have a show"})
    return jsonify({"venue":f"venue with id {venue_id} deleted"})

@app.route("/artist/<int:artist_id>/delete",methods=['POST','GET'])
def delete_artist(artist_id):
    artist = Artist.query.get_or_404(artist_id)
    try :
        db.session.delete(artist)
        db.session.commit()
    except:
        return jsonify({"artist":f"cant :artist with id {artist_id} already have a show"})
    return jsonify({"artist":f"artist with id {artist_id} deleted"})

@app.route("/show/<int:show_id>/delete",methods=['POST','GET'])
def delete_show(show_id):
    show = Show.query.get_or_404(show_id)
    try :
        db.session.delete(show)
        db.session.commit()
    except:
        pass
    return jsonify({"show":f"show with id {show_id} deleted"})

@app.route("/genre/<int:genre_id>/update",methods=['POST','GET'])
def update_genre(genre_id):
    json_object = request.json
    genre = Genre.query.get_or_404(genre_id)
    genre.name = json_object['name']
    db.session.commit()
    return jsonify({"response":"Genre has been updated!"})

@app.route("/venue/<int:venue_id>/update",methods=['POST','GET'])
def update_venue(venue_id):
    json_object = request.json
    venue = Venue.query.get_or_404(venue_id)
    venue.name = json_object['name']
    venue.city = json_object['city']
    venue.phone = json_object['phone']
    venue.fb_link = json_object['fb_link']
    genre = Genre.query.filter_by(name=json_object['genres']).first()
    venue.genres = [genre]
    db.session.commit()
    return jsonify({"response":"Venue has been updated!"})

@app.route("/artist/<int:artist_id>/update",methods=['POST','GET'])
def update_artist(artist_id):
    json_object = request.json
    artist = Artist.query.get_or_404(artist_id)
    artist.name = json_object['name']
    artist.city = json_object['city']
    artist.phone = json_object['phone']
    artist.fb_link = json_object['fb_link']
    genre = Genre.query.filter_by(name=json_object['genres']).first()
    artist.genres = [genre]
    db.session.commit()
    return jsonify({"response":"Artist has been updated!"})

@app.route('/show/<int:show_id>/update',methods=['GET', 'POST'])
def update_show(show_id):
    json_object = request.json
    show = Show.query.get_or_404(show_id)
    show.id_artist = json_object['id_artist']
    show.id_venue = json_object['id_venue']
    show.start_time = json_object['start_time']

    db.session.add(show)
    db.session.commit()
    return jsonify({"response":"Show has been updated!"})


import platform, os, subprocess, shutil, argparse

def run_cmd(cmd):
    print(f'\n\n{cmd}')
    print('--------------------------------------------------------')
    subprocess.Popen(cmd, shell=True).communicate()

parser = argparse.ArgumentParser(description='args to Run SCM app')
parser.add_argument('--fresh_db', dest='fresh_db', type=bool, help='run app with fresh DB', default=False, action=argparse.BooleanOptionalAction)
args = parser.parse_args()
if(args.fresh_db):
    fresh_db_arg = '--fresh_db'
else:
    fresh_db_arg = ''

if __name__ == '__main__':
    try:
        src_dir = os.path.dirname(__file__)
        data_dir = os.path.join(src_dir,'storage')
        if (args.fresh_db):
            run_cmd('minikube delete')
            # cleanup and fresh create the database folder
            shutil.rmtree(data_dir, ignore_errors=True)
            os.makedirs(data_dir)
            run_cmd(f'minikube start --mount-string "{data_dir}:/scm-storage" --mount --driver=docker')
        else:
            run_cmd(f'minikube start --driver=docker')
        # navigate to setup directory
        os.chdir(os.path.join(src_dir, 'setup'))
        # set the environment variables for docker env in shell and setup SCM application
        if (platform.system() == 'Windows'):
            run_cmd(f'powershell -ExecutionPolicy bypass "& minikube -p minikube docker-env --shell powershell | Invoke-Expression; python setup.py {fresh_db_arg}"')
        else:
            run_cmd(f'eval $(minikube docker-env) && python setup.py {fresh_db_arg}')
    except KeyboardInterrupt:
        print('!!!!!!script run terminated from keyboard!!!!!!')
        exit()


import math
import turtle

bob = turtle.Turtle()
print(bob)

# 画一个正方形
def square(t, length):
    for i in range(4):
        t.fd(length)
        t.lt(90)
    turtle.mainloop()

# 画一个正N边形,n边数，length每个边的长度
def polygon(t, n, length):
    angle = 360 / n
    polyline(t, n, length, angle)
    turtle.mainloop()

# 画一个圆，r半径
def circle(t, r):
    circumference = 2 * math.pi * r
    n = int(circumference / 3) + 1
    length = circumference / n
    for i in range(n):
        t.fd(length)
        t.lt(360.0 / n)
    t.lt(90)
    t.fd(r * 2)
    turtle.mainloop()
    # 也可用arc(t, r, 360)

# 画一段圆弧，r半径长度，n边数， angle角度
def arc(t, r, angle):
    arc_length = 2 * math.pi * r * (angle / 360)
    n = int(arc_length / 3) + 1
    step_length = arc_length / n
    step_angle = angle / n

    polyline(t, n, step_length, step_angle)

    turtle.mainloop()

def polyline(t, n, length, angle):
    for i in range(n):
        t.fd(length)
        t.lt(angle)

# circle(bob, r=200)
# polygon(bob, 16, 100)
arc(bob, r=200, angle=128)