from flask import Flask, request, g, redirect, url_for, render_template, send_from_directory
from flask_cors import CORS, cross_origin
from contextlib import closing
import sqlite3
import json
import sys
import os
import requests
import time
import datetime

args = sys.argv
# SERVER_NAME = "localhost:" + str(4000 + int(sys.argv[1]))
HOST = "0.0.0.0"
PORT = 5000
DEBUG = False
DATABASE = "models/5sec-server_" + sys.argv[1] + ".db"

app = Flask(__name__)
app.config.from_object(__name__)
CORS(app)


def connect_db():
    return sqlite3.connect(app.config['DATABASE'])


def init_db():
    with closing(connect_db()) as db:
        with app.open_resource('models/schema.sql') as f:
            db.cursor().executescript(f.read().decode('utf-8'))
        db.commit()


@app.route('/favicon.ico')
@cross_origin()
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static/img'), 'stopwatch.png')


@app.route('/')
def index():
    user_name = request.args.get("userName")
    if user_name == None:
        user_name = "user_1"
    return render_template('index.html', user_name=user_name)


@app.route('/play')
def play():
    user_name = request.args.get("userName")
    print(user_name)
    return render_template('play.html', user_name=user_name, is_auto=False)


@app.route("/autoplay")
def auto_play():
    user_name = request.args.get("userName")
    return render_template('play.html', user_name=user_name,  is_auto=True)


@app.route("/connection", methods=["GET"])
@cross_origin()
def get_connection():
    user_name = request.args.get("userName")
    with open("./graph.json") as f:
        connection = json.load(f)[user_name]
        return {"status": 200, "connection": connection}


@app.route("/game", methods=["GET"])
@cross_origin()
def get_game():
    game_tuple = g.db.execute("SELECT id, max(start_time) FROM games WHERE start_time >= (SELECT DATETIME('NOW', 'LOCALTIME'))").fetchone()
    game_dict = dict(id=game_tuple[0], start_time=game_tuple[1])
    return {"status": 200, "game": game_dict}


@app.route("/game", methods=["POST"])
@cross_origin()
def create_game():
    g.db.execute("INSERT INTO games(start_time) VALUES ((SELECT DATETIME(DATETIME('NOW', 'LOCALTIME'), '+5 SECONDS')))")
    g.db.commit()
    game_tuple = g.db.execute("SELECT id, max(start_time) FROM games").fetchone()
    game_dict = dict(id=game_tuple[0], start_time=game_tuple[1])

    # multicast
    with open("./graph.json") as f:
        for server in json.load(f)["server_" + sys.argv[1]]:
            url = "http://" + server["allocation"] + "/sync_game"
            requests.post(url, data=game_dict)

    return {"status": 200, "game": game_dict}


@app.route("/sync_game", methods=["POST"])
@cross_origin()
def sync_game():
    g.db.execute("INSERT INTO games(id, start_time) VALUES (?, ?)", [request.form["id"], request.form["start_time"]])
    g.db.commit()
    return {"status": 200}


@app.route("/player", methods=["GET"])
@cross_origin()
def get_player():
    game_id = request.args.get("gameId")
    players = g.db.execute("SELECT id, user_name FROM players WHERE game_id = ?", [game_id])
    players_list = [dict(id=row[0], user_name=row[1]) for row in players.fetchall()]
    return {"status": 200, "players": players_list}


@app.route("/player", methods=["POST"])
@cross_origin()
def create_player():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    g.db.execute("INSERT INTO players(game_id, user_name) VALUES (?, ?)", [game_id, user_name])
    g.db.commit()

    # multicast
    with open("./graph.json") as f:
        for server in json.load(f)["server_" + sys.argv[1]]:
            url = "http://" + server["allocation"] + "/sync_player"
            requests.post(url, data=request.form)

    return {"status": 200}


@app.route("/sync_player", methods=["POST"])
@cross_origin()
def sync_player():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    g.db.execute("INSERT INTO players(game_id, user_name) VALUES (?, ?)", [game_id, user_name])
    g.db.commit()
    return {"status": 200}


@app.route('/result', methods=["POST"])
@cross_origin()
def update_result():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    score = request.form["score"]

    with open("./graph.json") as f:
        graph = json.load(f)
        datetime_now = datetime.datetime.now()
        time_delta = datetime.timedelta(milliseconds=(graph["max_server_server_delay"] + graph["max_user_server_delay"] - graph[user_name]["delay"]))
        determined_time = datetime_now + time_delta

        g.db.execute("UPDATE players SET score = ?, determined_time = ? WHERE game_id = ? AND user_name = ?",
                     [score, determined_time, game_id, user_name])
        g.db.commit()

        # multicast
        for server in graph["server_" + sys.argv[1]]:
            url = "http://" + server["allocation"] + "/sync_result"
            time.sleep(server["delay"] / 1000)
            requests.post(url, data=request.form)

    return {"status": 200}


@app.route('/sync_result', methods=["POST"])
@cross_origin()
def sync_result():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    score = request.form["score"]

    with open("./graph.json") as f:
        graph = json.load(f)
        datetime_now = datetime.datetime.now()
        time_delta = datetime.timedelta(milliseconds=(graph["max_user_server_delay"] - graph[user_name]["delay"]))
        determined_time = datetime_now + time_delta

        g.db.execute("UPDATE players SET score = ?, determined_time = ? WHERE game_id = ? AND user_name = ?", [score, determined_time, game_id, user_name])
        g.db.commit()
        return {"status": 200}


@app.route("/result", methods=["GET"])
@cross_origin()
def get_result():
    game_id = request.args.get("gameId")
    players = g.db.execute("SELECT id, user_name, score FROM players WHERE game_id = ? AND score NOT NULL AND determined_time < (SELECT DATETIME('NOW', 'LOCALTIME')) ORDER BY score", [game_id])
    players_list = [dict(id=row[0], user_name=row[1], score=row[2]) for row in players.fetchall()]
    return {"status": 200, "players": players_list}


@app.before_request
def before_request():
    g.db = connect_db()


@app.after_request
def after_request(response):
    g.db.close()
    return response


if __name__ == '__main__':
    init_db()
    app.run()

from flask import Flask, request, g, redirect, url_for, render_template, send_from_directory
from flask_cors import CORS, cross_origin
from contextlib import closing
import sqlite3
import json
import sys
import os
import requests
import time
import datetime

args = sys.argv
# SERVER_NAME = "localhost:" + str(4000 + int(sys.argv[1]))
HOST = "0.0.0.0"
PORT = 5000
DEBUG = False
DATABASE = "models/5sec-server_" + sys.argv[1] + ".db"

app = Flask(__name__)
app.config.from_object(__name__)
CORS(app)


def connect_db():
    return sqlite3.connect(app.config['DATABASE'])


def init_db():
    with closing(connect_db()) as db:
        with app.open_resource('models/schema.sql') as f:
            db.cursor().executescript(f.read().decode('utf-8'))
        db.commit()


@app.route('/favicon.ico')
@cross_origin()
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static/img'), 'stopwatch.png')


@app.route('/')
def index():
    user_name = request.args.get("userName")
    if user_name == None:
        user_name = "user_1"
    return render_template('index.html', user_name=user_name)


@app.route('/play')
def play():
    user_name = request.args.get("userName")
    print(user_name)
    return render_template('play.html', user_name=user_name, is_auto=False)


@app.route("/autoplay")
def auto_play():
    user_name = request.args.get("userName")
    return render_template('play.html', user_name=user_name,  is_auto=True)


@app.route("/connection", methods=["GET"])
@cross_origin()
def get_connection():
    user_name = request.args.get("userName")
    with open("./graph.json") as f:
        connection = json.load(f)[user_name]
        return {"status": 200, "connection": connection}


@app.route("/game", methods=["GET"])
@cross_origin()
def get_game():
    game_tuple = g.db.execute("SELECT id, max(start_time) FROM games WHERE start_time >= (SELECT DATETIME('NOW', 'LOCALTIME'))").fetchone()
    game_dict = dict(id=game_tuple[0], start_time=game_tuple[1])
    return {"status": 200, "game": game_dict}


@app.route("/game", methods=["POST"])
@cross_origin()
def create_game():
    g.db.execute("INSERT INTO games(start_time) VALUES ((SELECT DATETIME(DATETIME('NOW', 'LOCALTIME'), '+5 SECONDS')))")
    g.db.commit()
    game_tuple = g.db.execute("SELECT id, max(start_time) FROM games").fetchone()
    game_dict = dict(id=game_tuple[0], start_time=game_tuple[1])

    # multicast
    with open("./graph.json") as f:
        for server in json.load(f)["server_" + sys.argv[1]]:
            url = "http://" + server["allocation"] + "/sync_game"
            requests.post(url, data=game_dict)

    return {"status": 200, "game": game_dict}


@app.route("/sync_game", methods=["POST"])
@cross_origin()
def sync_game():
    g.db.execute("INSERT INTO games(id, start_time) VALUES (?, ?)", [request.form["id"], request.form["start_time"]])
    g.db.commit()
    return {"status": 200}


@app.route("/player", methods=["GET"])
@cross_origin()
def get_player():
    game_id = request.args.get("gameId")
    players = g.db.execute("SELECT id, user_name FROM players WHERE game_id = ?", [game_id])
    players_list = [dict(id=row[0], user_name=row[1]) for row in players.fetchall()]
    return {"status": 200, "players": players_list}


@app.route("/player", methods=["POST"])
@cross_origin()
def create_player():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    g.db.execute("INSERT INTO players(game_id, user_name) VALUES (?, ?)", [game_id, user_name])
    g.db.commit()

    # multicast
    with open("./graph.json") as f:
        for server in json.load(f)["server_" + sys.argv[1]]:
            url = "http://" + server["allocation"] + "/sync_player"
            requests.post(url, data=request.form)

    return {"status": 200}


@app.route("/sync_player", methods=["POST"])
@cross_origin()
def sync_player():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    g.db.execute("INSERT INTO players(game_id, user_name) VALUES (?, ?)", [game_id, user_name])
    g.db.commit()
    return {"status": 200}


@app.route('/result', methods=["POST"])
@cross_origin()
def update_result():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    score = request.form["score"]

    with open("./graph.json") as f:
        graph = json.load(f)
        datetime_now = datetime.datetime.now()
        time_delta = datetime.timedelta(milliseconds=(graph["max_server_server_delay"] + graph["max_user_server_delay"] - graph[user_name]["delay"]))
        determined_time = datetime_now + time_delta

        g.db.execute("UPDATE players SET score = ?, determined_time = ? WHERE game_id = ? AND user_name = ?",
                     [score, determined_time, game_id, user_name])
        g.db.commit()

        # multicast
        for server in graph["server_" + sys.argv[1]]:
            url = "http://" + server["allocation"] + "/sync_result"
            time.sleep(server["delay"] / 1000)
            requests.post(url, data=request.form)

    return {"status": 200}


@app.route('/sync_result', methods=["POST"])
@cross_origin()
def sync_result():
    user_name = request.form["userName"]
    game_id = request.form["gameId"]
    score = request.form["score"]

    with open("./graph.json") as f:
        graph = json.load(f)
        datetime_now = datetime.datetime.now()
        time_delta = datetime.timedelta(milliseconds=(graph["max_user_server_delay"] - graph[user_name]["delay"]))
        determined_time = datetime_now + time_delta

        g.db.execute("UPDATE players SET score = ?, determined_time = ? WHERE game_id = ? AND user_name = ?", [score, determined_time, game_id, user_name])
        g.db.commit()
        return {"status": 200}


@app.route("/result", methods=["GET"])
@cross_origin()
def get_result():
    game_id = request.args.get("gameId")
    players = g.db.execute("SELECT id, user_name, score FROM players WHERE game_id = ? AND score NOT NULL AND determined_time < (SELECT DATETIME('NOW', 'LOCALTIME')) ORDER BY score", [game_id])
    players_list = [dict(id=row[0], user_name=row[1], score=row[2]) for row in players.fetchall()]
    return {"status": 200, "players": players_list}


@app.before_request
def before_request():
    g.db = connect_db()


@app.after_request
def after_request(response):
    g.db.close()
    return response


if __name__ == '__main__':
    init_db()
    app.run()

# SERVER_NAME = "localhost:" + str(4000 + int(sys.argv[1])) # multicast # multicast # multicast