#import os
from config import DATABASE_URL
from app import app
from datetime import datetime
import random

from sqlalchemy import create_engine, Column, String, Integer, ForeignKey, DateTime, func, PrimaryKeyConstraint,text
from sqlalchemy import Table, Text,MetaData
from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy.orm import relationship, backref, sessionmaker, scoped_session
from sqlalchemy.schema import Table
from sqlalchemy.event import listen
from flask_migrate import Migrate
from offylist import offyusers
from functions import sc
from attachements import offyvalues
#create database

db_name = DATABASE_URL
engine = create_engine(db_name)

#metadata = MetaData()
Base = declarative_base()

migrate = Migrate(app, Base)
#connection = engine.connect()
#trans = connection.begin()

Session = sessionmaker(bind=engine, expire_on_commit=False)
#expire_on_commit=False
session= Session()

class User(Base):
    __tablename__= 'users'
    id = Column(Integer, primary_key=True)
    slack_id =  Column(String(10), index=True)
    real_name = Column(String(40), index=True)
    slack_name = Column(String(40), index=True)
    last_activity = Column(DateTime, default=func.now(),index=True)
    job = Column(String(255), default= None )
    last_match = Column(String(255), default= None)

    cause = relationship('Cause', secondary='user_cause')
    #,cascade="save-update,delete" lazy='joined'

    def __init__(self, slack_id, real_name, slack_name, last_activity, job=None,last_match =None):
        self.slack_id = slack_id
        self.real_name = real_name
        self.job = job
        self.last_activity = last_activity
        self.last_match = last_match
        if slack_name is None:
            self.slack_name = real_name
        else:
            self.slack_name = slack_name
    def __repr__(self):
        return f"User(slack_id:'{self.slack_id}', real_name:'{self.real_name}' ,slack_name: '{self.slack_name}', last_activity:'{self.last_activity}', job:'{self.job}',last_match'{self.last_match})"

class Cause(Base):
    __tablename__ = 'causes'

    id = Column(Integer, primary_key=True)
    name = Column(String(40))
    user = relationship('User', secondary='user_cause')
    def __init__(self,name):
        self.name = name

    def __repr__(self):
        return f"Cause(name='{self.name}')"

class UserCause(Base):
    __tablename__ = 'user_cause'
    user_id = Column(Integer, ForeignKey('users.id'), primary_key = True)
    cause_id = Column(Integer, ForeignKey('causes.id'), primary_key = True)

class Planning(Base):
    __tablename__ = "planning"
    id = Column(Integer, primary_key = True)
    day = Column(DateTime, default=func.now(), index=True)
    value = Column(String(255))
    def __init__(self,value,day =func.now() ):
        self.value = value;
        sel.day = day
def comit():
    try:
        session.flush()
        session.commit()
    except:
        session.rollback()
    finally:
        session.close()
def add_bdd(obj):
    session.add(obj)
    try:
        session.flush()
        session.expire_on_commit=True
        session.commit()
    except:
        session.rollback()
    finally:
        session.close()

def add_multiple(list_obj):
    session.add_all(list_obj)
    try:
        session.flush()
        session.expire_on_commit=True
        session.commit()
    except:
        session.rollback()
    finally:
        session.close()

def delete_bdd(obj):
    try:
        session.delete(obj)
    except:
        session.rollback()
    finally:
        session.close()

def add_user_causes(slack_id,list_id_cause):
    user = session.query(User).filter(User.slack_id == slack_id)

    for c in range(1,len(list_id_cause)):
        c_id = session.query(Cause).filter(Cause.id == list_id_cause[c])
        user.cause.append(c_id)
def  add_user_cause(slack_id,id_cause):
    user = session.query(User).filter(User.slack_id == slack_id)
    cause = session.query(Cause).filter(Cause.id == id_cause)
    user.cause.append(cause)

def query_users(user_dict_info):
    u = user_dict_info
    user = session.query(User).filter(User.slack_id == u.slack_id).first()
    if user == None:
        add_bdd(u)
        mes = "non"
    else:
        mes = "oui"
    return mes
def users():
    query = session.query(User).all()
    for u in query:
        print(u)

def verif_user(id):
    """ recherche si l'user est unique """
    #query = session.query(func.count(User.slack_id).filter(User.slack_id == id))

    query = session.query(User).filter(User.slack_id == id).all()
    for u in query:
        print(u)

def update_cause(slack_id,list_cause):
    print("hello")
    #remove all user cause dans add new list of cause `
    # # s cause if from user_cause w user = ( s userid f user w u.slackid = slack id)
    #for c in cause add_usser_cause()
    #query = query(User).filter(Cause.id_user == "user.id_user")

def update_arg(user,Table,element,newvalue):
    """update last match , last activity , """
    query = session.query(Table).filter(Table.slack_id == user.slack_id)
    query.update({Table.element : newvalue})
    comit()

def update_user_info(slack_id,element,newvalue):
    """update last match , last activity , """
    session.query(User).filter(User.slack_id == slack_id).\
            update({User.element : newvalue})
    comit()

   #to update for week update

def search_user_value(user_id):
    causes = session.query(UserCause).filter(text(user_id = user_id)).all()
    print("hello")

def match(slack_id, list_causes):
    print("hello")
    #list_causes is
    #s random lim 1O
    # if last match == none get n import et up
    # update last match with user id
    #subquery = session.query(UserCause).filter(UserCause.cause_id.in_(list_causes).\
    #   count(UserCause.cause_id).group_by(UserCause.user_id).order_by()

    #search user
    user = session.query(User).filter(User.slack_id == slack_id)
    id = user.id
    query = session.query(User).\
        filter(text(id+" NOT IN (SELECT count(cause_id) AS nbCauses FROM user_cause WHERE cause_id IN ("+list_causes+") GROUP BY user_id ORDER BY nbcauses DESC LIMIT 3) ORDER BY last_activity DESC LIMIT 10"))
    #query = session.query(User).filter(User.id.notin_(subquery), )
    match = random.choice(query)
    update_user_info(slack_id,"last_match",match.slack_id)
    #seéarch match value
    causes = session.query(UserCause).filter(text(user_id = match.id)).all()
    #list User_causes
    for c in causes:
        if len(causes) == 1:
            message = "hello,\n@"+match.real_name+" avez "+offyvalues[c.cause_id]+"cette cause en commun "

        else:
            message = "hello,\n@"+match.real_name+ " partagez ces causes:\n"
            for i in range(len(causes)):
                message = message + "\n"+offyvalues[c.cause_id]

    return message

def init_bdd():
    #Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)
    #c1 = Cause("DÉVELOPPER LE VIETNAM")
    #c2 = Cause("LA MONDIALISATION POSITIVE")
    #c3 = Cause("CRÉER DE LA VALEUR PARTAGÉE")
    #c4 = Cause("PENSER ET AGIR DURABLE")
    #c5 = Cause("PARTAGER LE SAVOIR")

    #session.add_all([c1,c2,c3,c4,c5])

    #session.add_all([u1,u2,u3,u4,u5])

    u = session.query(User).filter(User.id == 1).all()
    c = session.query(Cause).filter(User.id == 1)
    #import pdb; pdb.set_trace()

    for user in u:
        print ( "id:"+u.slack_id )

   # session.add(UserCause(u.id, c.id,1))
    #u1.cause.append(c1)

    try:
        session.flush()
        session.expire_on_commit=True
        session.commit()
        print("EVERYTHING IN GIRL")
    except:
        session.rollback()
        print("EXEPTION BITCH")
    finally:
        session.close()
        print("CLOSE BITCH")

    for user in u:
        print ( "id:"+u.slack_id )

    #u1.cause.append(c4)


import sys

sys.path.append("/usr/local/lib/python3.9/site-packages")
from xlwt import Workbook

wb = Workbook()
sheet = wb.add_sheet('Order Book', cell_overwrite_ok=True)
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By

s = Service(ChromeDriverManager().install())

from bs4 import BeautifulSoup
import secrets
import json

from websocket import create_connection

from binance.client import Client
from binance.enums import *
from binance.exceptions import BinanceAPIException, BinanceOrderException
import math

import time

blacklist = ["REEFBTC", "CELRBTC", "VIBBTC", "ETCBTC", "COSBTC", "PHBBTC", "DGBBTC", "ADABTC", "ETHBTC", "SOLBTC",
             "MATICBTC"]

sheet.write(0, 0, "Coin")
sheet.write(0, 1, "Qty")
sheet.write(0, 3, "Buy Price")
sheet.write(0, 4, "Sell Price")
sheet.write(0, 6, "Pnl amount")
sheet.write(0, 7, "Pnl %")
sheet.write(0, 9, "Capital Used")

sheet.write(0, 11, "Recent Vol %")
sheet.write(0, 12, "Pings")
sheet.write(0, 13, "Net Vol %")

sheet.write(0, 15, "Buy time")
sheet.write(0, 16, "Sell time")

client = Client("QoukvJkask8R91Ql1A122wtuW1IykLIDcmBYFdav1ftrqEyPY5XkrtAOTqkZDP3l",
                "EC1kzfy9K8R5hqyJHYEEPdfvrRNHLYa1oqDhi17svEXutjWy4HCYRVQndHlVWYfr")

profit_percentage = 1
stoploss_percentage = 1.5
trail_stoploss_percentage = 0.2

coin_recent_vol_percentage = 0
coin_pings = 0
coin_net_vol_percentage = 0

op = webdriver.ChromeOptions()
op.add_argument('--headless')

driver = webdriver.Chrome(options=op, service=s)

profit = 0
file_log = open("guru.txt", "w+")
prcount = 0
lscouunt = 0

SIDE_BUY = 'BUY'
SIDE_SELL = 'SELL'

ORDER_TYPE_LIMIT = 'LIMIT'
ORDER_TYPE_MARKET = 'MARKET'
ORDER_TYPE_STOP_LOSS = 'STOP_LOSS'
ORDER_TYPE_STOP_LOSS_LIMIT = 'STOP_LOSS_LIMIT'
ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT'
ORDER_TYPE_TAKE_PROFIT_LIMIT = 'TAKE_PROFIT_LIMIT'
ORDER_TYPE_LIMIT_MAKER = 'LIMIT_MAKER'

TIME_IN_FORCE_GTC = 'GTC'  # Good till cancelled
TIME_IN_FORCE_IOC = 'IOC'  # Immediate or cancel
TIME_IN_FORCE_FOK = 'FOK'  # Fill or kill
TIME_IN_FORCE_GTX = 'GTX'  # Post only order

res = client.get_exchange_info()

def check_availability(order_coin_name):
    for item in res['symbols']:
        if item['symbol'] == order_coin_name.upper():
            return True
    return False

def truncate(f, n):
    return math.floor(f * 10 ** n) / 10 ** n

def get_percent(order_coin_name):
    tickers = client.get_ticker(symbol=order_coin_name)
    latest_percnt_change = float(tickers['priceChangePercent'])
    return latest_percnt_change

def get_quantity_in_precison(order_coin_name, qty):
    # print(client.get_account_snapshot())
    # print(" here ",client.get_symbol_info(order_coin_name),order_coin_name)
    dc = client.get_symbol_info(order_coin_name)
    n = int(dc['baseAssetPrecision'])
    # qty ="{:f}".format(truncate(qty,n))
    # print(qty,type(qty))
    step_size = 0
    filters = dc['filters']
    for f in filters:
        # print("filter~~~~~~~~~~~~ " + str(f))
        if f['filterType'] == 'LOT_SIZE':
            step_size = float(f['stepSize'])

    # bal = self._client.get_asset_balance(asset='BNB')
    # quantity = (float(bal['free']))/self._price*0.9995

    min_qty = client.get_symbol_info(order_coin_name)['filters'][5]['minQty']  # to get min qty of coin
    min_qty = float(min_qty)
    max_qty = client.get_symbol_info(order_coin_name)['filters'][5]['maxQty']  # max
    max_qty = float(max_qty)

    qty2 = float(qty)
    # print(min_qty,max_qty,qty)
    precise = len(str(min_qty).split('.')[1])
    qty2 = truncate(qty, precise)
    if step_size:
        precision = int(round(-math.log(step_size, 10), 0))
        quantity = float(truncate(qty, precision))
        return "{:f}".format(min(qty2, truncate(quantity, step_size)))
    return "{:f}".format(min(truncate(qty, 8), qty2))

def round_down(coin, number):
    number = float(number)
    info = client.get_symbol_info(coin)
    step_size = [float(_['stepSize']) for _ in info['filters'] if _['filterType'] == 'LOT_SIZE'][0]
    step_size = '%.8f' % step_size
    step_size = step_size.rstrip('0')
    decimals = len(step_size.split('.')[1])
    return math.floor(number * 10 ** decimals) / 10 ** decimals

def cancel_order(order_coin_name, oid):
    return client.cancel_order(symbol=order_coin_name, orderId=oid)

def get_filtered_price(order_coin_name, price):
    mp = client.get_symbol_info(order_coin_name)['filters'][0]['minPrice']
    decimalPts = len(mp.rstrip('0').split('.')[1])
    price = "{:f}".format(truncate(price, decimalPts))
    print("new limit price set ", price)
    return price

# def get_price(coin):
#      return float(client.get_ticker(symbol=coin)['lastPrice'])

def get_price(order_coin_name):
    # print("Check one")
    ws = create_connection("wss://stream.binance.com:9443/ws/" + order_coin_name.lower() + "@trade")
    result = ws.recv()
    result = json.loads(result)
    ws.close()
    # print("check two")
    return float(result['p'])

def get_free_asset(coin):
    balance = float(client.get_asset_balance(asset=coin)['free'])

    # balance ="{:f}".format(balance)
    return balance

def check_valid_qty(order_coin_name, qty):
    min_qty = client.get_symbol_info(order_coin_name)['filters'][5]['minQty']  # to get min qty of coin
    min_qty = float(min_qty)
    max_qty = client.get_symbol_info(order_coin_name)['filters'][5]['maxQty']  # max
    max_qty = float(max_qty)

    qty = float(qty)
    # print(min_qty,max_qty,qty)
    precise = len(str(min_qty).split('.')[1])
    qty = truncate(qty, precise)
    if min_qty >= qty:
        return False
    if max_qty < qty:
        return False

    return True

def average_of_market_order(fills):
    qty = 0
    tcost = 0
    for trade in fills:
        qty += float(trade['qty'])
        tcost += float(trade['qty']) * float(trade['price'])

    return tcost / qty

def convert_volume(coin, quantity, last_price):
    """Converts the volume given in QUANTITY from BTC to the each coin's volume"""

    quantity = float(quantity)
    last_price = float(last_price)
    try:
        info = client.get_symbol_info(coin)
        step_size = info['filters'][2]['stepSize']
        lot_size = {coin: step_size.index('1') - 1}

        if lot_size[coin] < 0:
            lot_size[coin] = 0

    except:
        print("Ran except block for lot size")
        lot_size = {coin: 0}
        pass

    # print(lot_size[coin])
    # calculate the volume in coin from QUANTITY in USDT (default)
    volume = float(quantity / float(last_price))

    # define the volume with the correct step size
    if coin not in lot_size:
        volume = float('{:.1f}'.format(volume))

    else:
        # if lot size has 0 decimal points, make the volume an integer
        if lot_size[coin] == 0:
            volume = int(volume)
        else:
            volume = float('{:.{}f}'.format(volume, lot_size[coin]))
    #  print(volume,float(info['filters'][2]['minQty'])," inside convert")
    #  volume=max(volume,float(info['filters'][2]['minQty']))
    return volume

def create_buy_order(coin, qty):
    """
    Creates simple buy order and returns the order
    """
    return client.create_order(
        symbol=coin,
        side=SIDE_BUY,
        type='MARKET',
        quantity=qty
    )

def create_sell_order(coin, qty):
    """
    Creates simple buy order and returns the order
    """
    return client.create_order(
        symbol=coin,
        side=SIDE_SELL,
        type='MARKET',
        quantity=qty
    )

def create_limit_sell_order(coin, qty, pr):
    """
    Creates simple buy order and returns the order
    """
    # print(qty,type(qty))
    return client.create_order(
        symbol=coin,
        side=SIDE_SELL,
        type=ORDER_TYPE_LIMIT,
        quantity=qty,
        timeInForce=TIME_IN_FORCE_GTC,
        price=pr
    )

def create_limit_buy_order(coin, qty, pr):
    """
    Creates simple buy order and returns the order
    """
    # print(qty,type(qty))
    return client.create_order(
        symbol=coin,
        side=SIDE_BUY,
        type=ORDER_TYPE_LIMIT,
        quantity=qty,
        timeInForce=TIME_IN_FORCE_GTC,
        price=pr
    )

def get_order_status(order_coin_name, target_order_id):
    return client.get_order(symbol=order_coin_name, orderId=target_order_id)["status"]

def run_starter():
    global client

    client = Client("QoukvJkask8R91Ql1A122wtuW1IykLIDcmBYFdav1ftrqEyPY5XkrtAOTqkZDP3l",
                    "EC1kzfy9K8R5hqyJHYEEPdfvrRNHLYa1oqDhi17svEXutjWy4HCYRVQndHlVWYfr")

    op = webdriver.ChromeOptions()
    op.add_argument('--headless')
    global driver

    driver = webdriver.Chrome(options=op, service=s)
    global SIDE_BUY
    SIDE_BUY = 'BUY'

    global SIDE_SELL
    SIDE_SELL = 'SELL'

    global ORDER_TYPE_LIMIT
    ORDER_TYPE_LIMIT = 'LIMIT'
    global ORDER_TYPE_MARKET
    ORDER_TYPE_MARKET = 'MARKET'
    global ORDER_TYPE_STOP_LOSS
    ORDER_TYPE_STOP_LOSS = 'STOP_LOSS'

    global TIME_IN_FORCE_GTC
    TIME_IN_FORCE_GTC = 'GTC'  # Good till cancelled

    global TIME_IN_FORCE_IOC
    TIME_IN_FORCE_IOC = 'IOC'  # Immediate or cancel

    global TIME_IN_FORCE_FOK
    TIME_IN_FORCE_FOK = 'FOK'  # Fill or kill

    global TIME_IN_FORCE_GTX
    TIME_IN_FORCE_GTX = 'GTX'  # Post only order

    global profit

    profit = 0
    global prcount
    prcount = 0
    global btc_price
    btc_price = get_price("BTCUSDT")
    global lscouunt
    lscouunt = 0
    global file_log
    file_log = open("guru.txt", "w+")

def get_token_to_be_baught():
    print("finding tokens")

    driver.get("http://agile-cliffs-23967.herokuapp.com/binance")

    content = driver.page_source
    try:
        soup = BeautifulSoup(content, "html5lib")
    except Exception as e:
        print(str(e))

    ls = []
    #     print("here")
    for a in soup.findAll('tr', attrs={'class': 'coin'}):
        # print(a)
        ln = a.find('a')
        link = ln.get("href")
        pair = link.split("/")[-1]
        newlink = link[:-3] + "USDT"
        print(pair, newlink)
        count = 0
        pings = 0
        net_vol_percentage = 0
        recent_vol_percentage = 0
        recent_net_volume = 0

        coin_symbol, base_coin = pair.split("_")
        base_coin = "USDT"
        coin_name = coin_symbol + base_coin

        if not check_availability(coin_name):
            continue

        tickers = client.get_ticker(symbol=coin_name)
        percent_change_price = tickers['priceChangePercent']
        percent_change_price = float(percent_change_price)

        for dt in a.find_all("th"):
            #
            new_data = dt.text.replace('\n', ' ').strip()
            # print(new_data)
            if count == 1:
                pings = int(new_data)
            elif count == 2:
                net_vol_btc = float(new_data)
            elif count == 3:
                net_vol_percentage = float(new_data[:-1])
            elif count == 5:
                recent_vol_percentage = float(new_data[:-1])
            elif count == 6:
                recent_net_volume = float(new_data)
                # print(recent_net_volume)

            count += 1

        print(coin_name)
        if (recent_vol_percentage > 0.7 and pings > 3 and pings < 10 and net_vol_percentage > 0.8):
            print("chosen ", pair)
            ls.append([coin_name, percent_change_price, coin_symbol, base_coin, recent_vol_percentage, pings,
                       net_vol_percentage])

    # ls.sort(key=lambda x:-x[1])

    # print("returning list: ", ls)
    return ls

btc_price = 60000  # get_price("BTCUSDT")

# run_starter()
row = 1
pnl = 0
total_pnl_amount = 0

def placeBuyOrderExcel(coin, qty, price):
    global pnl
    pnl = qty * price
    sheet.write(row, 0, coin)
    sheet.write(row, 1, qty)
    sheet.write(row, 3, price)
    sheet.write(row, 9, price * qty)  # capital used

    sheet.write(row, 11, coin_recent_vol_percentage)
    sheet.write(row, 12, coin_pings)
    sheet.write(row, 13, coin_net_vol_percentage)

    t = time.localtime()
    sheet.write(row, 15, time.strftime("%H:%M:%S", t))
    wb.save('orderBookExcel.xls')

def placeSellOrderExcel(coin, qty, price):
    global row
    global pnl
    global total_pnl_amount
    pnlAmount = qty * price - pnl
    pnlPercentage = pnlAmount / pnl * 100

    sheet.write(row, 4, price)
    sheet.write(row, 6, pnlAmount)
    sheet.write(row, 7, pnlPercentage)

    t = time.localtime()
    sheet.write(row, 16, time.strftime("%H:%M:%S", t))

    total_pnl_amount += pnlAmount
    sheet.write(row + 1, 6, total_pnl_amount)  # total of pnl in last row
    row += 1
    wb.save('orderBookExcel.xls')

#############################################################################################################################################################
########################################################################   BOT FUNCTION   ###################################################################
#############################################################################################################################################################
def bot():
    global prcount
    prcount = 0

    global limit_order_count
    limit_order_count = 0
    order_number = 1

    wait_for_long = 0
    print("\n=========================  BOT Started  =========================\n")
    global coin_recent_vol_percentage
    global coin_pings
    global coin_net_vol_percentage

    while True:

        ls = get_token_to_be_baught()
        if not ls:
            print("Wait 5 sec")
            time.sleep(5)
            continue
        else:
            print("received list: ", ls)
            taken_secret = secrets.choice(ls)
            order_coin_name = taken_secret[0]
            base_coin = taken_secret[3]
            coin_recent_vol_percentage = taken_secret[4]
            coin_pings = taken_secret[5]
            coin_net_vol_percentage = taken_secret[6]

        available_USDT = 25  # get_free_asset("USDT")
        print(available_USDT)
        usage_for_first_trade = 1
        if base_coin == "BTC":
            amount_allotted = float(get_free_asset("BTC")) * usage_for_first_trade
        else:
            amount_allotted = available_USDT * usage_for_first_trade

        quote_length = 3
        if order_coin_name[-4:] == "USDT":
            quote_length = 4

        quantity = 0

        float_coin_price = get_price(order_coin_name)
        quantity = convert_volume(order_coin_name, amount_allotted, float_coin_price)
        base_quantity = quantity

        if not check_valid_qty(order_coin_name, base_quantity):
            print("Re enter Qty not following min max")
            # file_log.write("\n "+str(e))
            continue

        try:
            global original_limit
            placeBuyOrderExcel(order_coin_name, base_quantity, float_coin_price)
            print("bought " + order_coin_name + " avg buy price " + str(float_coin_price))
            startTime = time.time()

            original_limit = float_coin_price * (1 + profit_percentage / 100)

            file_log.write(
                "\n \nOrder " + str(order_number) + " placed :" + order_coin_name + " average buy price " + str(
                    float_coin_price) + " Limit sell at " + str(float_coin_price * (1 + profit_percentage / 100)))
            file_log.write(
                "\nCoin parameters: Recent Volume % = " + str(coin_recent_vol_percentage) + " Pings = " + str(
                    coin_pings) + " Net Volume % = " + str(coin_net_vol_percentage))
            file_log.flush()
            order_number += 1

        except Exception as e:
            print(e)
            file_log.write("\n " + str(e))
            run_starter()
            continue

        limit_price = float_coin_price * (1 + profit_percentage / 100)

        sold = 0
        limit_order_count = 0
        time_start = time.time()
        net_quantity = base_quantity
        while not sold:
            # print("INSIDE TRADE")
            time.sleep(1)
            lastPrice = get_price(order_coin_name)

            print("Avg buy ", float_coin_price, " Current price ", lastPrice, " Limit sell at ", limit_price,
                  "Stoploss at ", (1 - stoploss_percentage / 100) * float_coin_price)

            if lastPrice >= limit_price:

                print("inside profit cell ")
                file_log.write("\n *** Inside profit cell  ***")
                file_log.flush()
                prev_last_price = limit_price

                # lastPrice=get_price(order_coin_name)
                # print(limit_price,lastPrice)
                flag = 0
                maxPrice = lastPrice
                try:
                    while True:
                        time.sleep(1)
                        lastPrice = get_price(order_coin_name)
                        print("\nInside profit : Avg buy ", float_coin_price, " Current price ", lastPrice,
                              " Limit sell at ", maxPrice)
                        if lastPrice > limit_price:
                            limit_price = lastPrice
                            maxPrice = max(lastPrice, maxPrice)
                            file_log.write("\nLimit trailed to :" + str(limit_price))
                            file_log.flush()

                        elif lastPrice < original_limit * 0.998 or lastPrice < maxPrice - (maxPrice-original_limit) * 0.20:
                            file_log.write("max price = "+str(maxPrice)+"\nTrail stoploss hit ✅, Placing sell order now!" + str(limit_price))
                            file_log.flush()
                            break
                        elif time.time() - startTime > 60*60*2:
                            file_log.write("max price = "+str(maxPrice)+"\nTime limit exceeded while trailing, Placing sell order now!" + str(limit_price))
                            file_log.flush()
                            break

                    placeSellOrderExcel(order_coin_name, net_quantity, lastPrice)
                    # print("executed")
                    selling_price = maxPrice

                    file_log.write("\n*** ❤profit❤  ***  bought at " + str(float_coin_price) + " sold at " + str(
                        lastPrice) + " **** \n")
                    file_log.write("\n\nTotal pnl till now is : ====>> " + str(total_pnl_amount) + " $\n")
                    file_log.flush()
                    print("\n* profit bought at " + str(float_coin_price) + " sold at " + str(lastPrice) + " *")
                    sold = 1

                    time.sleep(2)
                    continue

                except Exception as e:
                    print(e)
                file_log.flush()
                prcount += 1

            elif limit_order_count == 0 and float(lastPrice) < float_coin_price - (float_coin_price * 1 / 100):
                limit_order_count += 1
                try:
                    file_log.write("\n updating limit sell order" + str(limit_order_count))
                    file_log.flush()
                except Exception as e:
                    # run_starter()
                    file_log.write("\n " + str(e))
                    print(e)

                quantity_so_far = quantity
                quantity = base_quantity * 2
                net_quantity = quantity_so_far + quantity
                float_coin_price = (lastPrice * quantity + float_coin_price * quantity_so_far) / (net_quantity)
                placeBuyOrderExcel(order_coin_name, net_quantity, float_coin_price)
                limit_price = 1.01 * float_coin_price
                print("\nLimit 1  avg buy ", float_coin_price, " current price ", lastPrice, " limit sell at ",
                      limit_price)
                file_log.write(
                    "\n Limit 1  avg buy price " + str(float_coin_price) + " current price " + str(lastPrice))
                file_log.flush()

            elif limit_order_count == 1 and float(lastPrice) < float_coin_price - (float_coin_price * 2 / 100):
                limit_order_count += 1
                try:
                    file_log.write("\n updating limit sell order" + str(limit_order_count))
                    file_log.flush()
                except Exception as e:
                    # run_starter()
                    file_log.write("\n " + str(e))
                    print(e)

                quantity_so_far = quantity
                quantity = base_quantity * 4
                net_quantity = quantity_so_far + quantity
                float_coin_price = (lastPrice * quantity + float_coin_price * quantity_so_far) / (net_quantity)
                limit_price = 1.01 * float_coin_price
                placeBuyOrderExcel(order_coin_name, net_quantity, float_coin_price)
                print("Limit 2  avg buy ", float_coin_price, " current price ", lastPrice, " limit sell at ",
                      limit_price)
                file_log.write(
                    "\n Limit 2  avg buy price " + str(float_coin_price) + " current price " + str(lastPrice))
                file_log.flush()

            elif limit_order_count == 2 and float(lastPrice) < float_coin_price - (float_coin_price * 4 / 100):
                limit_order_count += 1
                try:
                    file_log.write("\n updating limit sell order" + str(limit_order_count))
                    file_log.flush()
                except Exception as e:
                    # run_starter()
                    file_log.write("\n " + str(e))
                    print(e)

                quantity_so_far = quantity
                quantity = base_quantity * 8
                net_quantity = quantity_so_far + quantity
                float_coin_price = (lastPrice * quantity + float_coin_price * quantity_so_far) / (net_quantity)
                limit_price = 1.01 * float_coin_price
                placeBuyOrderExcel(order_coin_name, net_quantity, float_coin_price)
                print("\nLimit 3  avg buy ", float_coin_price, " current price ", lastPrice, " limit sell at ",
                      limit_price)
                file_log.write(
                    "\n Limit 3  avg buy price " + str(float_coin_price) + " current price " + str(lastPrice))
                file_log.flush()

            elif limit_order_count == 3 and float(lastPrice) < float_coin_price - (float_coin_price * 8 / 100):
                limit_order_count += 1
                try:
                    file_log.write("\n updating limit sell order" + str(limit_order_count))
                    file_log.flush()
                except Exception as e:
                    # run_starter()
                    file_log.write("\n " + str(e))
                    print(e)

                quantity_so_far = quantity
                quantity = base_quantity * 16
                net_quantity = quantity_so_far + quantity
                float_coin_price = (lastPrice * quantity + float_coin_price * quantity_so_far) / (net_quantity)
                limit_price = 1.01 * float_coin_price
                placeBuyOrderExcel(order_coin_name, net_quantity, float_coin_price)
                print("\nLimit 4  avg buy ", float_coin_price, " current price ", lastPrice, " limit sell at ",
                      limit_price)
                file_log.write(
                    "\n Limit 4  avg buy price " + str(float_coin_price) + " current price " + str(lastPrice))
                file_log.flush()

            if time.time() - startTime > 60*60*2:
                balance = get_free_asset(order_coin_name[:-quote_length])
                # balance=get_quantity_in_precison(order_coin_name,balance)
                # lastPrice=average_of_market_order(placed_order['fills'])
                print("\n--->Time limit exceeded  --> loss")
                placeSellOrderExcel(order_coin_name, net_quantity, lastPrice)
                file_log.write("\n--->Time limit exceeded --> loss ☹ ==> buy price " + str(
                    float_coin_price) + " sell price " + str(lastPrice))
                file_log.flush()
                sold = 1

run_starter()
try:

    bot()
except Exception as e:
    file_log.write(str(e))


from flask import (
    Blueprint, flash, g, redirect, render_template, request, url_for, Flask, send_from_directory, current_app,session
)
from werkzeug.exceptions import abort

from flask_login import login_required, current_user
from asc.schema import Flight, SchemaError, Aircraft, Pilot, Slot
from sqlalchemy import func, or_, and_
import datetime
from sqlalchemy import text as sqltext
from sqlalchemy.sql import func, select
# WTForms
from flask_wtf import FlaskForm
from wtforms import Form, StringField, PasswordField, validators, SubmitField, SelectField, BooleanField, RadioField, \
    TextAreaField, TimeField
from wtforms.fields import EmailField, IntegerField, DateField, TimeField, DateTimeField, DecimalField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length

from asc.wtforms_ext import MatButtonField, TextButtonField
from decimal import *
from asc.common import *

try:
    # app = Flask(__name__)
    # from asc import create_app
    # app = create_app()
    app = current_app
except Exception as e:
    print("Failed to load app in flights.py: {}".format(e))

bp = Blueprint('flights', __name__, url_prefix='/flights')
applog = app.logger

constDAYDATE = 'daydate'
constDAYVIEW = 'dayview'

# TODO: Dayend to roll log if empty
# TODO: purge downloads folder
# TODO: ARE you sure for flights where either a start/tug down or landed is already recorded and the user presses that button.

class NewDayForm(FlaskForm):
    newdate = DateField('Date',
                     description="Today's Date",
                     default=datetime.date.today()
                     # validators=[validators.DataRequired()]
                    )
    instructor = StringField('Instructor',
                             description = "Instructor Name",
                             render_kw={'list': "instructors"})
    towpilot = StringField('Tow Pilot',
                             description = "Tow Pilot Name",
                             render_kw={'list': "towies"})
    dutypilot = StringField('Duty Pilot',
                             description = "Duty Pilot Name",
                             render_kw={'list': "dutypilots"})

class FlightForm(FlaskForm):
    id = IntegerField('ID',
                      description='Primary Key')
    pic = StringField('PIC',
                      [validators.DataRequired(message='You cannot have a blank code')],
                      description="Pilot in charge",
                      render_kw={'list': "activepilots"})
    p2 = StringField('P2',
                     description="Passenger or Student",
                     render_kw={'list': "activepilots"})
    flt_date = DateField('Date',
                         description='Flight Date',
                         render_kw={'class': 'mobile_port_supress mobile_land_supress'})
    ac_regn = StringField('Regn',
                          [validators.DataRequired(message='You cannot have a blank code')],
                          description='Last 3 characters of AC Registration',
                          render_kw={'list': "acregns"})
    takeoff = TimeField('Takeoff',
                        [validators.Optional()],
                        description="Takeoff Time",
                        render_kw={'step': "60"})
    tug_down = TimeField('Tug Down',
                         [validators.Optional()],
                         description="Time the Tow plane landed",
                         render_kw={'step': "60"})
    release_height = IntegerField('Release Height',
                                  [validators.Optional()],
                                  description='Release height in feet',
                                  render_kw={'Step': '500'})
    landed = TimeField('Landed',
                       [validators.Optional()],
                       description="Landing Time",
                       render_kw={'step': "60"})
    tow_pilot = StringField('Tow Pilot',
                            description="Tow Pilot",
                            render_kw={'list': "towies"})
    tug_regn = StringField('Tug Regn',
                           description="Tug Registration - Last Three Characters",
                           render_kw={'list': "towregnlist"})
    btnsubmit = MatButtonField('done',
                            id='matdonebtn',
                            icon='done',
                            help="Confirm all Changes")
    cancel = MatButtonField('cancel',
                            id='matcancelbtn',
                            icon='cancel',
                            help="Press to exit and make no changes")  # , render_kw={'formnovalidate':''})
    payment = MatButtonField('payment', id='matpaymentbtn', icon='attach_money',
                             help="Maintain cost and payment")  # , render_kw={'formnovalidate':''})
    note = MatButtonField('note', id='matnotebtn', icon='description',
                          help="Add a note to the flight")
    delete = MatButtonField('delete', id='matdeletebtn',
                            icon='delete',
                            help='Press to delete this record',
                            render_kw={'onclick': 'return ConfirmDelete()'})

class PaymentForm(FlaskForm):
    payer = StringField('Payer',
                        description='Person paying for this flight',
                        render_kw={'list': "pilots"})
    tow_charge = DecimalField('Launch',
                              description="Launch Charge",
                              places=2,
                              rounding=None)
    glider_charge = DecimalField('Glider',
                                 description="Glider Charge",
                                 places=2)
    other_charge = DecimalField('Other',
                                description="Other eg. Trial Flight Charge",
                                places=2)
    payment_note = StringField('Payment',
                               description = "Payment Method",
                               render_kw={'list': "paymentmethods"})
    paid = BooleanField('Paid',
                        description="Checked indicates this flight has been paid")
    btnsubmit = MatButtonField('done',
                            id='matdonebtn',
                            icon='done',
                            help="Confirm all Changes")
    cancel = MatButtonField('cancel',
                            id='matcancelbtn',
                            icon='cancel',
                            help="Press to exit and make no changes")  # , render_kw={'formnovalidate':''})
    # 22 Jan 23:  Removed the delete function
    # We don't want users to be able to delete a record on the payment screen
    # delete = MatButtonField('delete',
    #                         id='matdeletebtn',
    #                         icon='delete',
    #                         help='Press to delete this record',
    #                         render_kw={'onclick': 'return ConfirmDelete()'})
    calc = TextButtonField('Transactions',
                           id="calcbtn",
                           text='Calc',
                           help="Reset default charges")

class NoteForm(FlaskForm):
    flt_date = DateField('Date',
                         description='Flight Date',
                         )
    general_note = TextAreaField('Note',
                               description = "Any Notes for Lionel or yourself",
                                render_kw={'rows':'8'})
    btnsubmit = MatButtonField('done',
                            id='matdonebtn',
                            icon='done',
                            help="Confirm all Changes")
    cancel = MatButtonField('cancel',
                            id='matcancelbtn',
                            icon='cancel',
                            help="Press to exit and make no changes")  # , render_kw={'formnovalidate':''})
    delete = MatButtonField('delete', id='matdeletebtn',
                            icon='delete',
                            help='Press to delete this record',
                            render_kw={'onclick': 'return ConfirmDelete()'})

# TODO: Test Error Handling in Production environment.

@app.before_request
def before_request():
    applog.debug("In before_request")

@bp.route('/daysummary')
@login_required
def daysummary():
    # TODO: Add paging
    sql = sqltext("""
    SELECT
        flt_date,
        count(*) movements,
        max(id) last_id
        FROM flights
        GROUP BY flt_date
        ORDER BY flt_date desc
        """)
    sql = sql.columns(flt_date=db.Date)
    app.logger.info("Main Page accessed")
    try:
        summary = db.engine.execute(sql).fetchall()
        return render_template('flights/daysummary.html', summary=summary)
    except Exception as e:
        flash("An error occurred: {}".format(e))
        app.logger.info("An error occurred: {}".format(e))
        # return e
        abort(404, e)

@bp.route('/newday', methods=['GET','POST'])
@login_required
def newday():
    """
    Start a new day.  Get the roster details and so on.
    """
    if request.method == 'GET':
        instlist = [r.fullname for r in db.session.query(Pilot).filter(Pilot.instructor == True).all()]
        towielist = [r.fullname for r in db.session.query(Pilot).filter(Pilot.towpilot == True).all()]
        dplist = [r.fullname for r in db.session.query(Pilot).filter(Pilot.towpilot == False).filter(Pilot.instructor == False).all()]
        newdate = datetime.date.today()
        thisform = NewDayForm()
        todayroster = Roster.query.filter(Roster.roster_date >= newdate).first()
        if todayroster is None:
            thisform.newdate.data = datetime.date.today()
        else:
            thisform.newdate.data = todayroster.roster_date
            thisform.instructor.data = todayroster.roster_inst
            thisform.towpilot.data = todayroster.roster_tp
            thisform.dutypilot.data = todayroster.roster_dp
    if request.method == 'POST' :
        thisform = NewDayForm(request.form)
        # Add the note here
        notetext = "Instructor:{}, Tow Pilot:{}, Duty Pilot:{}".format(thisform.instructor.data,
                                                                       thisform.towpilot.data,
                                                                       thisform.dutypilot.data)
        daynote = Flight(flt_date=thisform.newdate.data,
                         linetype='NT',
                         general_note=notetext)
        db.session.add(daynote)
        db.session.commit()
        # print("post note: {} / {}".format(thisform.newdate.data,thisform.instructor.data))
        return redirect(url_for('flights.daysheet', date=thisform.newdate.data.strftime('%Y-%m-%d')))
    # if not post....
    return render_template('flights/newday.html', form=thisform, instlist=instlist, towielist=towielist,
                           dplist=dplist)

@bp.route('/daysheet/<date>')
@login_required
def daysheet(date):
    """
    Display flights on a day
    :param date: String.  Can be one of:
        "TODAY" - obvious
        "SESSION" - a date stored in the session cookie "DAYDATE"
        a string in dd-mmm-yyyy format
    :return:
    """
    if date == 'TODAY':
        thisdate = date.today()
    elif date == 'SESSION':
        thisdate = datetime.datetime.strptime(session[constDAYDATE],'%Y-%m-%d').date()
    else:
        thisdate = datetime.datetime.strptime(date, '%Y-%m-%d').date()
    # Now remember it:
    session[constDAYDATE] = datetime.datetime.strftime(thisdate, '%Y-%m-%d')
    # Deal with the view
    if constDAYVIEW in session:
        view = session[constDAYVIEW]
    else:
        view = 'ALL'
    if view is None:
        view = 'ALL'
    if view == 'AIRBORNE':
        thisset = db.session.query(Flight).filter(Flight.linetype == 'FL').filter(Flight.flt_date == thisdate).filter(Flight.takeoff != None).filter(Flight.landed == None).all()
        title = "Airborne " + thisdate.strftime("%a %d %b")
    elif view == 'WAITING':
        thisset = db.session.query(Flight).filter(Flight.linetype == 'FL').filter(Flight.flt_date == thisdate).filter(Flight.takeoff == None).all()
        title = "Gridded " + thisdate.strftime("%a %d %b")
    elif view == 'LANDED':
        thisset = db.session.query(Flight).filter(Flight.linetype == 'FL').filter(Flight.flt_date == thisdate).filter(Flight.landed != None).all()
        title = "Landed " +  thisdate.strftime("%a %d %b")
    elif view == 'UNPAID':
        thisset = db.session.query(Flight).filter(Flight.linetype == 'FL').filter(Flight.flt_date == thisdate).filter(Flight.landed != None).filter(or_(Flight.payment_note == None, Flight.payment_note =='')).all()
        title = "Unpaid"
    else:
        thisset = db.session.query(Flight).filter(Flight.flt_date == thisdate).all()
        title  = "All Flights " + thisdate.strftime("%a %d %b")
    # see if it is possible to record tug down with one button.
    launched = db.session.query(Flight).filter(Flight.linetype == 'FL').filter(Flight.flt_date == thisdate).filter(Flight.takeoff != None).filter(Flight.tug_down == None).all()
    current_glider_under_tow = ''
    id_of_towed_aircraft = 0
    count_of_towed_aircraft = 0
    for l in launched:
        # check if slef launch
        thisaircraft = db.session.query(Aircraft).filter(Aircraft.regn == l.ac_regn).first()
        if thisaircraft is not None and thisaircraft.default_launch != constTOW_FOR_SELF_LAUNCH:
            id_of_towed_aircraft = l.id
            current_glider_under_tow = l.ac_regn
            count_of_towed_aircraft += 1
    if count_of_towed_aircraft > 1:
        flash("Seems we have > 1 aircraft under tow!!")
    try:
        return render_template('flights/daysheet.html', title=title,  flights=thisset ,
                               towcount=count_of_towed_aircraft,
                               towedregn=current_glider_under_tow,
                               towedid=id_of_towed_aircraft
                               )
    except Exception as e:
        flash("An error occurred: {}".format(e))
        app.logger.info("An error occurred: {}".format(e))
        return render_template('flights/daysummary.html')

@bp.route('/changeview', methods=['GET', 'POST'])
@login_required
def changeview():
    if request.method == 'GET':
        return render_template('flights/changeview.html')
    if request.method == 'POST':
        session[constDAYVIEW] = request.form['view']
    return redirect(url_for('flights.daysheet', date='SESSION'))

@bp.route('/changeflight/<id>', methods=['GET', 'POST'])
@login_required
def changeflight(id):
    # --------------------------------------------------------------------------------------------
    # Preparation - get default values, poplulate lists
    # --------------------------------------------------------------------------------------------
    thisrec = Flight.query.get(id)
    # if thisrec is None then we will be adding
    if thisrec is None:
        thisrec = Flight()
        thisrec.flt_date = db.session.query(func.max(Flight.flt_date).label("maxdate")).scalar()
        lastflt = db.session.query(Flight).filter(Flight.linetype == 'FL').order_by(Flight.id.desc()).first()
        # Determine the TUG:
        if lastflt is not None:
            thisrec.tow_pilot = lastflt.tow_pilot
            applog.debug("New rec tow pilot set to {} at point A. LAst flit id is {}".format(lastflt.tow_pilot, lastflt.id))
            thisrec.tug_regn = lastflt.tug_regn
        # on a mobile platform the flight date is always the current date.  On windows or linux it will be prompted.
        # is todays date equal to the flight date?
        applog.info("User Agent:{}".format(request.user_agent.platform))
        if request.user_agent.platform is not None and request.user_agent.platform not in ['windows', 'linux']:
            thisrec.flt_date = datetime.date.today()
    else:
        lastdate = thisrec.flt_date
    #
    thisform = FlightForm(obj=thisrec, name='Flight Maintenance')
    if thisform.cancel.data:
        return redirect(url_for('flights.daysheet', date=thisrec.flt_date.strftime('%Y-%m-%d')))
    # Pilot list
    # Populate the choices list for pilots and
    sql = sqltext("""
          select pic
          from flights
          where flt_date > :date
          and pic <> ''
          and linetype = 'FL'
          union
          select p2
          from flights
          where flt_date > :date
          and p2 <> ''
          and linetype = 'FL'
          union
          select fullname
          from pilots
          """)
    if thisrec.flt_date is not None:
        activepilotdate = thisrec.flt_date - datetime.timedelta(days=180)
    else:
        activepilotdate = datetime.date.today()
    pilotlist = [r[0] for r in db.engine.execute(sql, date=activepilotdate).fetchall()]
    # A/C List
    sql = sqltext("""
        select distinct ac_regn
        from flights
        where flt_date > :date
        and linetype = 'FL'
       union
        select regn
        from aircraft
        order by ac_regn
        """)
    if thisrec.flt_date is not None:
        activeacdate = thisrec.flt_date - datetime.timedelta(days=90)
    else:
        activeacdate = datetime.date.today()
    acregnlist = [r[0] for r in db.engine.execute(sql, date=activeacdate).fetchall()]
    # Add the Tug only if it not already there..(i.e. used in last 90 days) ...
    if constREGN_FOR_TUG_ONLY not in acregnlist:
        acregnlist.append(constREGN_FOR_TUG_ONLY)
    # Towie list
    towielist = [r.fullname for r in db.session.query(Pilot).filter(Pilot.towpilot == True).all()]
    sql = sqltext("""
        select distinct regn
        from aircraft
        where launch = 1
    """)
    towregnlist = [r.regn for r in db.engine.execute(sql).fetchall()]
    towregnlist.append(constTOW_FOR_SELF_LAUNCH)

    # --------------------------------------------------------------------------------------------
    # Processing
    # --------------------------------------------------------------------------------------------
    if request.method == 'POST' and thisform.validate():
        # Provided the field names are the same, this function updates all the fields
        # on the table.  If there are any that are different then each field needs to be
        # assigned manually.
        try:
            thisform.populate_obj(thisrec)
            if thisrec.id is None:
                # thisrec.pic_gnz_no = thisrec.get_pic_gnz_no()
                # thisrec.p2_gnz_no = thisrec.get_p2_gnz_no()
                db.session.add(thisrec)
                applog.info('New Flight added: {}'.format(thisrec.id))
            elif thisform.delete.data:
                db.session.delete(thisrec)
                applog.info('Flight {} deleted'.format(id))
            else:
                # if this a tug only flight make sure that tug down and landed are the same
                # thisrec.pic_gnz_no = thisrec.get_pic_gnz_no()
                # thisrec.p2_gnz_no = thisrec.get_p2_gnz_no()
                if thisrec.ac_regn == constREGN_FOR_TUG_ONLY or thisrec.tug_regn == constTOW_FOR_SELF_LAUNCH:
                    if thisrec.tug_down == None and thisrec.landed != None:
                        thisrec.tug_down = thisrec.landed
                    elif thisrec.tug_down != None and thisrec.landed == None:
                        thisrec.landed = thisrec.tug_down
                applog.info('Flight {} changed'.format(id))
            if thisrec.tug_regn != constTOW_FOR_SELF_LAUNCH and thisrec.ac_regn != constREGN_FOR_TUG_ONLY:
                addupdslot('DEFAULT','LASTTOWIE',thisrec.tow_pilot)
                addupdslot('DEFAULT','LASTTUG',thisrec.tug_regn)
            applog.debug('Just before commit: towie is {}'.format(thisrec.tow_pilot))
            db.session.commit()
            if thisform.note.data:
                return redirect(url_for('flights.flightnote', id=thisrec.id))
            if thisform.payment.data:
                return redirect(url_for('flights.payment', id=thisrec.id))
        except SchemaError as e:
            flash(e)
            return render_template('flights/changeflight.html', form=thisform, pilots=pilotlist, ac=acregnlist, towielist=towielist)
        return redirect(url_for('flights.daysheet', date=thisrec.flt_date.strftime('%Y-%m-%d')))
    applog.debug('About to render changefligt at b with id {}'.format(thisform.id.data))
    return render_template('flights/changeflight.html', form=thisform, pilots=pilotlist, ac=acregnlist, towielist=towielist, towregnlist=towregnlist)

# NOTELINE is a line of type NT that is NOT a flight!
@bp.route('/linenote/<id>', methods=['GET', 'POST'])
@login_required
def linenote(id):
    if constDAYDATE in session:
        thisdate = datetime.datetime.strptime(session[constDAYDATE], '%Y-%m-%d').date()
    else:
        thisdate = datetime.date.today()
    thisrec = Flight.query.get(id)
    if thisrec is None:
        thisrec = Flight()
        thisrec.flt_date = db.session.query(func.max(Flight.flt_date).label("maxdate")).scalar()
        # lastflt = db.session.query(Flight).order_by(Flight.id.desc()).first()
        thisrec.linetype = 'NT'
    thisform = NoteForm(obj=thisrec, name='Notes for Flight')
    if request.method == 'GET':
        # if thisrec is None then we will be adding
        return render_template('flights/changenote.html', form=thisform, line=thisrec)
    if request.method == 'POST' and thisform.validate():
        # Provided the field names are the same, this function updates all the fields
        # on the table.  If there are any that are different then each field needs to be
        # assigned manually.
        try:
            thisform.populate_obj(thisrec)
            if thisrec.id is None:
                db.session.add(thisrec)
                applog.info('New Note added: {}'.format(thisrec.id))
            elif thisform.delete.data:
                db.session.delete(thisrec)
                applog.info('Note {} deleted'.format(id))
            else:
                applog.info('Note {} note details updated'.format(id))
            db.session.commit()
            return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))
        except SchemaError as e:
            flash(e)
            return render_template('flights/changenote.html', form=thisform)
        except Exception as e:
            flash(e)
            return render_template('flights/changenote.html', form=thisform)
        return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))
    return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))

@bp.route('/flightnote/<id>', methods=['GET', 'POST'])
@login_required
def flightnote(id):
    if constDAYDATE in session:
        thisdate = datetime.datetime.strptime(session[constDAYDATE], '%Y-%m-%d').date()
    else:
        thisdate = datetime.date.today()
    thisrec = Flight.query.get(id)
    if thisrec is None:
        flash("Unable to locate record")
        return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))
    # otherwise we have a good record
    thisform = NoteForm(obj=thisrec, name='Notes for Flight')
    if request.method == 'GET':
        return render_template('flights/changenote.html', form=thisform, line=thisrec)
    if request.method == 'POST' and thisform.validate():
        # Provided the field names are the same, this function updates all the fields
        # on the table.  If there are any that are different then each field needs to be
        # assigned manually.
        try:
            thisform.populate_obj(thisrec)
            if thisrec.id is None:
                flash("Unable to locate record")
                return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))
            else:
                applog.info('Flight {} note details updated'.format(id))
            db.session.commit()
        except SchemaError as e:
            flash(e)
            return render_template('flights/changenote.html', form=thisform)
        return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))
    return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))

@bp.route('/tuglanded/<id>')
@login_required
def tuglanded(id):
    if constDAYDATE in session:
        thisdate = datetime.datetime.strptime(session[constDAYDATE], '%Y-%m-%d').date()
    else:
        thisdate = datetime.date.today()
    try:
        thisflight = Flight.query.get(id)
        if thisflight.linetype != 'FL':
            flash("This line is not a flight")
            return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))
        down = datetime.datetime.now()
        # now round to the nearest minute
        if down.second > 30:
            # remove the seconds
            down -= datetime.timedelta(seconds=down.second, microseconds=down.microsecond)
            # Add one minute
            down += datetime.timedelta(minutes=1)
        else:
            # jsut remove the seconds
            down -= datetime.timedelta(seconds = down.second, microseconds=down.microsecond)
        thisflight.tug_down = down.time()
        if thisflight.ac_regn == constREGN_FOR_TUG_ONLY or thisflight.tug_regn == constTOW_FOR_SELF_LAUNCH:
            if thisflight.tug_down == None and thisflight.landed != None:
                thisflight.tug_down = thisflight.landed
            elif thisflight.tug_down != None and thisflight.landed == None:
                thisflight.landed = thisflight.tug_down
        db.session.commit()
    except Exception as e:
        applog.debug("Error updating tug down :{}".format(e))
        flash("Unable to update.  Record via Flight id")
    return redirect(url_for('flights.daysheet', date=thisdate.strftime('%Y-%m-%d')))

@bp.route('/payment/<id>', methods=['GET', 'POST'])
@login_required
def payment(id):
    thisrec = Flight.query.get(id)
    # if thisrec is None then we have an error
    if thisrec is None:
        flash("Cannot locate flight")
        return redirect(url_for('flights.daysummary'))
    thisform = PaymentForm(obj=thisrec, name='Payment Maintenance')
    if thisform.cancel.data:
        return redirect(url_for('flights.changeflight', id=id))
    if thisform.calc.data:
        if not calc_charges(id):
            flash("There was a problem setting the default charges")
        return redirect(url_for('flights.payment', id=id))
    if request.method == 'POST' and thisform.validate():
        # Provided the field names are the same, this function updates all the fields
        # on the table.  If there are any that are different then each field needs to be
        # assigned manually.
        try:
            thisform.populate_obj(thisrec)
            if thisrec.id is None:
                db.session.add(thisrec)
                applog.info('New payment details Added')
            # 22 Jan 23 - do not allow delete on the payment form.
            # elif thisform.delete.data:
            #     db.session.delete(thisrec)
            #     applog.info('Flight {} payment details deleted'.format(id))
            else:
                applog.info('Flight {} payment details updated'.format(id))
            db.session.commit()
        except SchemaError as e:
            flash(e)
            return render_template('flights/payment.html', form=thisform, glider_time = thisrec.glider_mins())
        return redirect(url_for('flights.daysheet', date=thisrec.flt_date.strftime('%Y-%m-%d')))
    # if we are here then we are getting the data for display
    sql = sqltext("""
             select fullname
             from pilots
             """)
    pilotlist = [r[0] for r in db.engine.execute(sql).fetchall()]
    return render_template('flights/payment.html', form=thisform,pilots=pilotlist)

def calc_charges(id):
    """
    For a given id calculate the charges and update the record.
    :param id: The ID of the record
    :return: Boolean to say if all was ok or not
    """
    try:
        thisrec = Flight.query.get(id)
        if thisrec is None:
            return False
        # Launch fee
        tug = Aircraft.query.filter_by(regn=thisrec.tug_regn).first()
        if tug is None and thisrec.tug_regn != constTOW_FOR_SELF_LAUNCH:
            return False
        if thisrec.ac_regn == constREGN_FOR_TUG_ONLY:
            if thisrec.tow_mins() <= 0:
                flash('Insufficient flight data to calculate default charges')
                return False
        elif thisrec.tug_regn == constTOW_FOR_SELF_LAUNCH:
            pass # there are no checks.
        else:  # Not tug only.
            if thisrec.tow_mins is None \
                or (thisrec.release_height is None and thisrec.tug_regn != constTOW_FOR_SELF_LAUNCH) \
                or thisrec.glider_mins() == 0:
                flash('Insufficient flight data to calculate default charges')
                return False
            if thisrec.tow_mins() <= 0 or thisrec.glider_mins() <= 0:
                flash('Incorrect flight data.  Cannot calculate default charges')
                return False
        # Flight fee
        thisac = Aircraft.query.filter_by(regn=thisrec.ac_regn).first()
        if thisac is None:
            # this could be valid.  Could be a visiting a/c
            thisrec.glider_charge = 0
        # BIG IF-ELIF that determins the rates
        # Start with trial flights
        if thisrec.p2.upper() == constTRIAL_FLIGHT_CUST:
            SlotForRate = Slot.query.filter_by(slot_type='DEFAULT').filter_by(slot_key='TRIALFLIGHTPRICE').first()
            if SlotForRate is None:
                thisrec.tow_charge = 100
            else:
                thisrec.tow_charge = SlotForRate.slot_data
            thisrec.payer = thisrec.p2
        # REGN_FOR_TUG_ONLY appears in the Glider Regn field.
        elif thisrec.ac_regn == constREGN_FOR_TUG_ONLY:
            thisrec.glider_charge = 0
            thisrec.tow_charge = Decimal(thisrec.tow_mins() * (tug.rate_per_hour_tug_only / 60))
            thisrec.payer = thisrec.pic_rec().fullname
            # Nothing else to do if the tug is flown on it's own.
        elif thisrec.tug_regn == constTOW_FOR_SELF_LAUNCH:
            thisrec.tow_charge = 0
            thisrec.glider_charge = Decimal(thisrec.glider_mins()) * (thisac.rate_per_hour / 60)
            if thisrec.p2 is not None:
                payer = Pilot.query.filter_by(fullname=thisrec.p2).first()
            if payer is None:
                payer = Pilot.query.filter_by(fullname=thisrec.pic).first()
            if payer is not None:
                if payer.bscheme and thisac.bscheme:
                    thisrec.glider_charge = 0
            if payer is not None:
                thisrec.payer = payer.fullname
        else: # Normal Launch
            # Calculate the tow / launch costs
            thisrec.tow_charge = 0
            if tug.rate_per_height != 0:
                thisrec.tow_charge += Decimal((thisrec.release_height / tug.per_height_basis) * tug.rate_per_height)
            if tug.rate_per_hour != 0:
                thisrec.tow_charge += Decimal(thisrec.tow_mins() * (tug.rate_per_hour / 60))
            if tug.flat_charge_per_launch != 0:
                thisrec.tow_charge += tug.flat_charge_per_launch
            # Calculate the glider charge
            thisrec.glider_charge = Decimal(thisrec.glider_mins()) * (thisac.rate_per_hour / 60)
            if thisrec.p2 is not None:
                payer = Pilot.query.filter_by(fullname=thisrec.p2).first()
            if payer is None:
                payer = Pilot.query.filter_by(fullname=thisrec.pic).first()
            if payer is not None:
                if payer.bscheme and thisac.bscheme:
                    thisrec.glider_charge = 0
            if payer is not None:
                thisrec.payer = payer.fullname
        db.session.commit()
    except Exception as e:
        flash(str(e))
        return False
    return True


import tensorflow as tf

from datasets.cifar10 import Cifar10 as Dataset

EMBEDDING_SIZE = 3

class Cifar10:

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

    """--------------------------------------------------------------------------------------------------------------"""

    @staticmethod
    def architecture(features, params):
        with tf.variable_scope(params.scopes['net_scope']):
            images = tf.cast(features, tf.float32)
            # images = features
            # Input Layer
            with tf.name_scope('Data'):
                input_layer = tf.reshape(images, [-1, Dataset.IMG_SIZE, Dataset.IMG_SIZE, Dataset.NUM_CHANNELS])

            # Convolutional Layer 1
            with tf.variable_scope('Conv1'):
                conv1 = tf.layers.conv2d(inputs=input_layer, filters=32, kernel_size=[3, 3], padding="same", activation=tf.nn.elu)
                pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=1)

            tf.logging.info('Convolutional Layer 1 build successful..')

            # Convolutional Layer 2
            with tf.variable_scope('Conv2'):
                conv2 = tf.layers.conv2d(inputs=pool1, filters=64, kernel_size=[3, 3], padding="same", activation=tf.nn.elu)
                pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=1)

            tf.logging.info('Convolutional Layer 2 build successful..')

            # Convolutional Layer 3
            with tf.variable_scope('Conv3'):
                conv3 = tf.layers.conv2d(inputs=pool2, filters=128, kernel_size=[3, 3], padding="same", activation=tf.nn.elu)
                pool3 = tf.layers.max_pooling2d(inputs=conv3, pool_size=[2, 2], strides=2)

            tf.logging.info('Convolutional Layer 3 build successful..')

            # Convolutional Layer 4
            with tf.variable_scope('Conv4'):
                conv4 = tf.layers.conv2d(inputs=pool3, filters=256, kernel_size=[3, 3], padding="same",
                                         activation=tf.nn.elu)
                pool4 = tf.layers.max_pooling2d(inputs=conv4, pool_size=[2, 2], strides=2)

            tf.logging.info('Convolutional Layer 4 build successful..')

            # Fully Connected Layer
            with tf.variable_scope('FC'):
                pool2_flat = tf.reshape(pool4, [-1, 7 * 7 * 256])
                dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.elu)

            tf.logging.info('Fully Connected Layer build successful..')

            """ ---------------------------------------------------------------------------------------------------- """

            # Embeddings Layer
            with tf.variable_scope(params.scopes['emb_scope']):
                l2_norm = tf.nn.l2_normalize(dense, dim=1, name='l2norm')

                tf.summary.histogram("l2norm", l2_norm)

                embeddings = tf.layers.dense(inputs=l2_norm, kernel_initializer=tf.initializers.random_normal,
                                             kernel_regularizer=tf.contrib.layers.l2_regularizer,
                                             units=EMBEDDING_SIZE, name=params.scopes['emb_name'])

                tf.summary.histogram(params.scopes['emb_name'], embeddings)

                tf.logging.info('Embeddings Layer build successful..')

            """ ---------------------------------------------------------------------------------------------------- """

            # Logits Layer
            with tf.variable_scope('LogitsLayer'):
                logits = tf.layers.dense(inputs=embeddings, units=10)

                tf.summary.histogram('logits', logits)

                tf.logging.info('Logits Layer build successful..')

        return logits

    @staticmethod
    def get_estimator_spec(features, labels, mode, params):

        logits = Cifar10.architecture(features, params)

        # Metrics Layer
        with tf.variable_scope(params.scopes['metrics_scope']):
            # Generate predictions (for PREDICT and EVAL mode)
            predictions = {
                "classes": tf.argmax(input=logits, axis=1),
                # Add `softmax_tensor` to the graph. It is used for PREDICT.
                "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
            }

            tf.logging.info('Predictions build successful..')

            # Calculate Loss (for both TRAIN and EVAL modes)
            labels = tf.identity(labels, name=params.scopes['label_name'])
            one_hot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=10)
            loss = tf.losses.softmax_cross_entropy(onehot_labels=one_hot_labels, logits=logits)

            tf.summary.histogram('loss', loss)

            tf.logging.info('Losses build successful..')

            learning_rate = tf.train.exponential_decay(
                params.learning_rate,  # Base learning rate.
                tf.train.get_global_step(),  # Current index into the dataset.
                1000,  # Decay step.
                0.75,  # Decay rate.
                staircase=True,
                name='learning_rate'
            )

            tf.summary.histogram('learning_rate', learning_rate)

            tf.logging.info('Learning rate build successful..')

            optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
            # optimizer = tf.train.RMSPropOptimizer(learning_rate=learning_rate)
            train_op = optimizer.minimize(loss=loss, global_step=tf.train.get_global_step())

            # Add evaluation metrics (for EVAL mode)
            accuracy = tf.metrics.accuracy(labels=labels, predictions=predictions["classes"], name='accuracy')

            tf.summary.histogram('accuracy', accuracy)

            tf.logging.info('Accuracy metric build successful..')

            return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op,
                                              predictions=predictions,
                                              eval_metric_ops={"accuracy": accuracy},
                                              scaffold=tf.train.Scaffold(
                                                  summary_op=tf.summary.merge_all()
                                              ))


import copy
import datetime
import json
import logging.config
import os
import random
import re
import sys
import time
import uuid
from datetime import datetime as dt

import jctconv
import requests

LOG_CONF = "./logging.conf"
logging.config.fileConfig(LOG_CONF)

from bs4 import BeautifulSoup
from kivy.app import App
from kivy.clock import Clock
from kivy.config import Config
from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.core.window import Window
from kivy.resources import resource_add_path
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen
from kivy.uix.textinput import TextInput

if hasattr(sys, "_MEIPASS"):
    resource_add_path(sys._MEIPASS)

EMPTY = ""
JP = "jp"
JP_CAP = "JP"
NEW = "CATEGORY: NEW"
TOPS_SWEATERS = "TOPS/SWEATERS"
LEAVE_BLANK = "*leave blank*"
SIZE_S = "s"
SIZE_M = "m"
SIZE_L = "l"
SIZE_XL = "xl"
KEY_INDEX = "index"
KEY_ITEM_CODE = "itemCode"
KEY_NAME = "name"
KEY_LOCALE = "locale"
KEY_TITLE = "title"
KEY_MONITOR = "monitor"
KEY_SCHEDULE = "schedule"
KEY_COLOR = "color"
KEY_PAGE = "page"
KEY_CHECKOUT_DELAY_ENABLED = "checkout_delay_enabled"
KEY_CHECKOUT_DELAY_SECONDS = "checkout_delay_seconds"
KEY_PROXY_RATIO = "proxyratio"
KEY_TASK_RATIO = "taskratio"
KEY_TASKS = "tasks"
KEY_EMAIL = "email"
KEY_BILLING = "billing"
KEY_FIRST = "first"
KEY_LAST = "last"
KEY_ADDRESS1 = "address1"
KEY_POST_CODE = "postcode"
KEY_CITY = "city"
KEY_REGION = "region"
KEY_COUNTRY = "country"
KEY_PHONE = "phone"
KEY_CARD = "card"
KEY_TYPE = "type"
KEY_NUMBER = "number"
KEY_MONTH = "month"
KEY_YEAR = "year"
KEY_CODE = "code"
KEY_SIZES = "sizes"
KEY_CHECKOUT_PROFILE = "checkoutprofile"
INDEX_TWITTER = 21
INDEX_EMAIL = 9
INDEX_FIRST_NAME = 2
INDEX_LAST_NAME = 3
INDEX_ADDRESS = 7
INDEX_POST_CODE = 4
INDEX_CITY = 6
INDEX_REGION = 5
INDEX_PHONE = 8
INDEX_PAY_TYPE = 13
INDEX_CARD_NUMBER = 14
INDEX_CARD_LIMIT_MONTH = 15
INDEX_CARD_LIMIT_YEAR = 16
INDEX_CARD_CVV = 17
INDEX_ITEM_NO = 4
INDEX_ITEM_SIZE = 2
VAL_CHECKOUT_DELAY_ENABLED = False
VAL_CHECKOUT_DELAY_SECONDS = 5.0
VAL_PROXY_RATIO = 1
VAL_TASK_RATIO = 1
HEADER_KEY_LIST = [KEY_INDEX, KEY_ITEM_CODE, KEY_NAME, KEY_MONITOR]
HEADER_MONITOR_KEY_LIST = [KEY_PAGE, KEY_TITLE, KEY_COLOR]
SIZE_X_DICT = {
    KEY_INDEX: 0.7, KEY_NAME: 1, KEY_PAGE: 0.3, KEY_TITLE: 0.5, KEY_COLOR: 0.3
}

URL = "http://www.nikeslayer.com/news/category/supremeslayer-keywords/"
HEADERS = {
    "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0",
}

ID_ITEM_VIEW = "item_view_data"
ID_GET_SITE_INFO_BUTTON = "get_site_info_button"
ID_DUMP_CHECKOUTPROFILES_BUTTON = "dump_checkoutprofiles_button"
ID_DUMP_RELEASEPROFILES_BUTTON = "dump_releaseprofiles_button"
ID_MESSAGE = "message"
ID_MAX_DATA_NUM_PER_FILE = "max_data_num_per_file"

RELEASE_PROFILES_JSON = "releaseprofiles{}.json"
CHECKOUT_PROFILES_JSON = "checkoutprofiles.json"
UTF8 = "utf8"
SATURDAY_INDEX = 5
LOG_CONF = "./logging.conf"

CONFIG_DICT = {}
CONFIG_KEY_KEYWORD_URL = "KEYWORD_URL"

class JsonMakerScreen(Screen):
    def __init__(self, **kwargs):
        super(JsonMakerScreen, self).__init__(**kwargs)
        self.item_list = []
        self.task_list_dict = {}
        self.line_num = 0
        self._file = Window.bind(on_dropfile=self._on_file_drop)
        self.tmp_txt_path = None

    def _on_file_drop(self, window, file_path):
        self.disp_messg("{}を読み込みました".format(os.path.basename(file_path)))
        self.tmp_txt_path = file_path
        self.ids[ID_DUMP_CHECKOUTPROFILES_BUTTON].disabled = False

    def disp_drag_and_drop_msg(self):
        self.disp_messg("tmp.txtをツール画面上にドラッグ&ドロップしてください")

    @staticmethod
    def get_latest_url():
        r = requests.get(URL, headers=HEADERS)
        soup = BeautifulSoup(r.text, "lxml")
        for a in soup.find_all("a"):
            if a.text == "Read more":
                return a.get("href")

    def get_site_info(self):
        self.disp_messg("サイトから最新情報を取得中...")
        self.ids[ID_GET_SITE_INFO_BUTTON].disabled = True
        Clock.schedule_once(self.update_item_view)

    def update_item_view(self, dt):
        try:
            #url = self.get_latest_url()
            url = CONFIG_DICT[CONFIG_KEY_KEYWORD_URL]
            self.parse_site_info(url)
            scrollview = self.ids["container"]
            scrollview.clear_widgets()
            row_len = len(self.item_list)

            scrollview.height = row_len * 40
            for i in range(row_len):
                self.add_item_info_row(i, scrollview)

            self.disp_messg("サイトから最新情報を取得しました")
        except Exception as e:
            self.disp_messg_err("サイトから最新情報を取得するのに失敗しました。")
            logging.exception("Unknown Exception : %s.", e)
        finally:
            self.ids[ID_GET_SITE_INFO_BUTTON].disabled = False

    def add_item_info_row(self, i, scrollview):
        box = BoxLayout()
        item_dict = self.item_list[i]
        self.add_text_widget_on_grid(box, str(i + 1), size_hint_x=0.15)
        for key in HEADER_KEY_LIST:
            if key == KEY_MONITOR:
                mon_dict = item_dict[key]
                for mon_key in HEADER_MONITOR_KEY_LIST:
                    self.add_text_widget_on_grid(box, mon_dict.get(mon_key, ""), size_hint_x=SIZE_X_DICT[mon_key])
            elif key == KEY_ITEM_CODE:
                self.add_text_widget_on_grid(box, "", "itemCode-" + str(i), size_hint_x=0.3, disabled=False)
            else:
                self.add_text_widget_on_grid(box, item_dict[key], size_hint_x=SIZE_X_DICT[key])

        scrollview.add_widget(box)

    @staticmethod
    def add_text_widget_on_grid(box, text, id=None, size_hint_x=1, disabled=True):
        text = TextInput(text=text, size_hint_x=size_hint_x, multiline=False, write_tab=False)
        text.id = id
        text.disabled = disabled
        text.disabled_foreground_color = (0, 0, 0, 1)
        text.background_disabled_normal = text.background_normal
        box.add_widget(text)

    @staticmethod
    def get_page(th_list):
        page = th_list[0].text
        if NEW in page:
            page = "new"
        elif page == TOPS_SWEATERS:
            page = "tops_sweaters"
        return page.lower()

    def save_item_info(self, page, td_list):
        has_multi_color = False
        base_name = td_list[0].text
        title = td_list[1].text
        color_list = td_list[2].text.split(",")

        if len(color_list) > 1:
            has_multi_color = True

        for color in color_list:
            item_dict = {}
            item_dict[KEY_INDEX] = "rk_" + str(uuid.uuid4()).replace("-", "")
            monitor_dict = {}
            monitor_dict[KEY_PAGE] = page
            monitor_dict[KEY_TITLE] = title
            color = re.sub("^ ", EMPTY, color)

            if has_multi_color:
                item_dict[KEY_NAME] = "{} {}".format(base_name, color)
            else:
                item_dict[KEY_NAME] = base_name

            item_dict[KEY_LOCALE] = JP

            if color != LEAVE_BLANK:
                monitor_dict[KEY_COLOR] = color

            item_dict[KEY_MONITOR] = monitor_dict
            item_dict[KEY_SCHEDULE] = self.get_next_saturday_epoch()
            item_dict[KEY_CHECKOUT_DELAY_ENABLED] = VAL_CHECKOUT_DELAY_ENABLED
            item_dict[KEY_CHECKOUT_DELAY_SECONDS] = VAL_CHECKOUT_DELAY_SECONDS
            item_dict[KEY_PROXY_RATIO] = VAL_PROXY_RATIO
            item_dict[KEY_TASK_RATIO] = VAL_TASK_RATIO
            self.item_list.append(item_dict)

    def parse_site_info(self, url):
        self.item_list = []
        r = requests.get(url, headers=HEADERS)
        soup = BeautifulSoup(r.text, "lxml")
        for tab in soup.find_all("table"):
            page = None
            is_1st_td = True
            for tr in tab.find_all("tr"):
                td_list = tr.find_all("td")
                if len(td_list) > 0:
                    if is_1st_td:
                        page = self.get_page(td_list)
                        is_1st_td = False
                    else:
                        self.save_item_info(page, td_list)

    def dump_checkoutprofiles(self):
        global log
        try:
            self.dump_checkoutprofile_core()
        except Exception as e:
            self.disp_messg_err("checkoutprofiles.jsonを出力に失敗しました。")
            if self.line_num > 0:
                log.error("tmp.txtの{}行目処理時にエラーが発生しました。".format(self.line_num))
            log.exception("checkoutprofiles.jsonの出力に失敗しました。%s", e)

    def dump_checkoutprofile_core(self):
        address_list = []
        self.task_list_dict = {}
        self.line_num = 0

        for line in open(self.tmp_txt_path, "r", encoding="utf-8"):
            self.line_num += 1
            line = line[:-1]
            items = line.split("\t")
            if items[0] == "*S":
                address_dict = {}
                index = "ckk_" + str(uuid.uuid4()).replace("-", "")
                address_dict[KEY_INDEX] = index
                address_dict[KEY_NAME] = items[INDEX_TWITTER]
                address_dict[KEY_LOCALE] = JP
                address_dict[KEY_EMAIL] = items[INDEX_EMAIL]
                bill_dict = {}
                bill_dict[KEY_FIRST] = items[INDEX_FIRST_NAME]
                bill_dict[KEY_LAST] = items[INDEX_LAST_NAME]
                bill_dict[KEY_ADDRESS1] = items[INDEX_ADDRESS]
                bill_dict[KEY_POST_CODE] = items[INDEX_POST_CODE]
                bill_dict[KEY_CITY] = items[INDEX_CITY]
                bill_dict[KEY_REGION] = items[INDEX_REGION]
                bill_dict[KEY_COUNTRY] = JP_CAP
                bill_dict[KEY_PHONE] = items[INDEX_PHONE]
                address_dict[KEY_BILLING] = bill_dict
                card_dict = {}
                if items[INDEX_PAY_TYPE] == "代金引換":
                    card_dict[KEY_TYPE] = "cashondelivery"
                else:
                    card_dict[KEY_TYPE] = items[INDEX_PAY_TYPE].replace(" ", "").lower()
                    card_dict[KEY_NUMBER] = items[INDEX_CARD_NUMBER]
                    card_dict[KEY_MONTH] = int(items[INDEX_CARD_LIMIT_MONTH])
                    card_dict[KEY_YEAR] = int("20" + items[INDEX_CARD_LIMIT_YEAR])
                    card_dict[KEY_CODE] = items[INDEX_CARD_CVV]
                address_dict[KEY_CARD] = card_dict
            elif items[0] == "*I":
                item_no = items[INDEX_ITEM_NO]
                size = self.format_size(items[INDEX_ITEM_SIZE])

                if size is None:
                    continue

                task_list = self.task_list_dict.get(item_no)
                if task_list is None:
                    task_list = []
                    self.task_list_dict[item_no] = task_list

                task_dict = {}
                task_dict[KEY_SIZES] = [size]
                task_dict[KEY_CHECKOUT_PROFILE] = index
                task_list.append(task_dict)

                address_list.append(address_dict)

        with open(CHECKOUT_PROFILES_JSON, "w", encoding=UTF8) as f:
            f.write(json.dumps(address_list, indent=2, ensure_ascii=False))

        self.ids[ID_DUMP_RELEASEPROFILES_BUTTON].disabled = False
        self.disp_messg("checkoutprofiles.jsonを出力しました")

    def disp_messg(self, msg):
        self.ids[ID_MESSAGE].text = msg
        self.ids[ID_MESSAGE].color = (0, 0, 0, 1)

    def disp_messg_err(self, msg):
        self.ids[ID_MESSAGE].text = "{}詳細はログファイルを確認してください。".format(msg)
        self.ids[ID_MESSAGE].color = (1, 0, 0, 1)

    @staticmethod
    def format_size(size):
        global log
        size = jctconv.normalize(size.lower())
        if size == EMPTY:
            return "random_random"
        elif size == SIZE_S or size == SIZE_M or size == SIZE_L or size == SIZE_XL:
            return "shirtsother_{}".format(size)
        elif "/" in size:
            return None
        elif float(size) < 28:
            return "shoes_{}".format(size)
        else:
            return "pants_{}".format(size)

    @staticmethod
    def conv_0_to_empty(num):
        if num == 0:
            return ""
        else:
            return num

    def dump_releaseprofiles(self):
        global log
        try:
            self.dump_releaseprofiles_core()
        except Exception as e:
            self.disp_messg_err("releaseprofiles.jsonを出力に失敗しました。")
            log.exception("releaseprofiles.jsonの出力に失敗しました。%s", e)

    def dump_releaseprofiles_core(self):
        global log

        dump_item_list = []
        max_data_num_per_file = int(self.ids[ID_MAX_DATA_NUM_PER_FILE].text)
        order_num = 0
        dumped_num = 0

        for i in range(len(self.item_list)):
            item_dict = self.item_list[i]
            item_no = self.get_item_no(i)
            if item_no is None:
                continue

            task_list = self.task_list_dict.get(item_no)
            if task_list is None:
                continue

            if order_num + len(task_list) <= max_data_num_per_file:
                item_dict[KEY_TASKS] = task_list
                dump_item_list.append(item_dict)
                order_num += len(task_list)
                if max_data_num_per_file <= order_num:
                    self.write_release_profiles_json(dump_item_list, dumped_num)
                    dumped_num += 1
                    dump_item_list = []
                    order_num = 0
            else:
                item_dict_without_task = copy.deepcopy(item_dict)
                split_task_list = []
                for task in task_list:
                    split_task_list.append(task)
                    order_num += 1
                    if order_num >= max_data_num_per_file:
                        item_dict[KEY_TASKS] = split_task_list
                        dump_item_list.append(item_dict)
                        self.write_release_profiles_json(dump_item_list, dumped_num)
                        dumped_num += 1
                        order_num = 0
                        dump_item_list = []
                        split_task_list = []
                        item_dict = item_dict_without_task
                        item_dict_without_task = copy.deepcopy(item_dict)

                if 0 < len(split_task_list):
                    item_dict[KEY_TASKS] = split_task_list
                    dump_item_list.append(item_dict)

        if 0 < order_num:
            self.write_release_profiles_json(dump_item_list, dumped_num)
            dumped_num += 1

        self.disp_messg("releaseprofiles.jsonを{}ファイル出力しました".format(dumped_num))

    @staticmethod
    def get_next_saturday_epoch():
        today = dt.today()
        add_day = SATURDAY_INDEX - today.weekday()
        if add_day < 0:
            add_day = 6
        next_day = today + datetime.timedelta(days=add_day)

        sec = random.randint(20, 50)
        next_date_str = "{}-{}-{} 10:59:{}".format(next_day.year, next_day.month, next_day.day, sec)
        next_date = dt.strptime(next_date_str, '%Y-%m-%d %H:%M:%S')
        epoch = int(time.mktime(next_date.timetuple())) + (9 * 3600)
        return str(epoch)

    def write_release_profiles_json(self, dump_item_list, dumped_num):
        with open(RELEASE_PROFILES_JSON.format(self.conv_0_to_empty(dumped_num)), "w", encoding=UTF8) as f:
            f.write(json.dumps(dump_item_list, indent=2, ensure_ascii=False))

    def get_item_no(self, no):
        for widget in self.walk():
            if widget.id == "itemCode-{}".format(no):
                return widget.text

class JsonMakerApp(App):
    def build(self):
        return JsonMakerScreen()

def load_config():
    for line in open("./config.txt", "r"):
        items = line.replace("\n", "").split("=")

        if len(items) != 2:
            continue

        if items[0] == CONFIG_KEY_KEYWORD_URL:
            CONFIG_DICT[CONFIG_KEY_KEYWORD_URL] = items[1]

def setup_config():
    load_config()
    Config.set('modules', 'inspector', '')  # Inspectorを有効にする
    Config.set('graphics', 'width', 1280)  # Windowの幅を1280にする
    Config.set('graphics', 'maxfps', 20)  # フレームレートを最大で20にする
    Config.set('graphics', 'resizable', 0)  # Windowの大きさを変えられなくする
    Config.set('input', 'mouse', 'mouse,disable_multitouch')
    Config.write()

if __name__ == '__main__':
    log = logging.getLogger('my-log')
    setup_config()
    LabelBase.register(DEFAULT_FONT, "ipaexg.ttf")
    JsonMakerApp().run()


from config.dbconfig import pg_config
import psycopg2
class RequestDAO:
    global list
    list = set()
    def __init__(self):

        connection_url = "dbname=%s user=%s password=%s host=127.0.0.1" % (pg_config['dbname'],
                                                            pg_config['user'],
                                                            pg_config['passwd'])
        self.conn = psycopg2._connect(connection_url)

    def addrequest(self,date,quantity,adress):
        print(date,quantity,adress)
        list.add((date,quantity,adress))
        return list

    def searchrequested(self, name):
        cursor = self.conn.cursor()
        query = "SELECT  rname,rtype,quantity,rqaddress,rqdate FROM resources as r inner join requested as rq on r.rid=rq.rid inner join request as req on req.rqid=rq.rqid where rname like %s order by rname"
        cursor.execute(query, (name,))
        result = []
        for row in cursor:
            result.append(row)
        return result

    def getrequest(self):
        cursor = self.conn.cursor()
        query = "select rqaddress,quantity,rqdate from request"
        cursor.execute(query)
        result = []
        for row in cursor:
            result.append(row)
        return result

    def searchrequest(self, request):
        cursor = self.conn.cursor()
        query = "select rqaddress,quantity,rqdate from request where rqid= %s "
        cursor.execute(query, (request,))
        result = []
        for row in cursor:
            result.append(row)
        return result

    def getRequestbyCoid(self, request):
        cursor = self.conn.cursor()
        query = "SELECT  firstname,lastname,quantity,rqaddress,rqdate FROM consumer as c inner join makes as mk on c.coid=mk.coid inner join request as req on req.rqid=mk.rqid where c.coid=%s"
        cursor.execute(query, (request,))
        result = []
        for row in cursor:
            result.append(row)
        return result

    def insertrequest(self, rqaddress,quantity,rqdate):
        cursor = self.conn.cursor()
        query = "insert into request(rqaddress,quantity,rqdate) values (%s, %s, %s) returning rqid;"
        cursor.execute(query, (rqaddress,quantity,rqdate,))
        pid = cursor.fetchone()[0]
        self.conn.commit()
        return pid

    def insertmakes(self, pid,coid):
        cursor = self.conn.cursor()
        query = "insert into makes(rqid,coid) values (%s, %s) returning mkid;"
        cursor.execute(query, (pid,coid))
        pid = cursor.fetchone()[0]
        self.conn.commit()
        return pid

    def insertrequested(self, pid,rid,quantity):
        cursor = self.conn.cursor()
        query = "insert into requested(rid,rqid,quantity) values (%s, %s,%s) returning rqdid;"
        cursor.execute(query, (rid,pid,quantity))
        pid = cursor.fetchone()[0]
        self.conn.commit()
        return pid

    def dailyResourcesinNeed(self,date):
        cursor = self.conn.cursor()
        query = "SELECT resources.rname, sum(request.quantity), request.rqdate FROM public.request, public.requested,public.resources WHERE request.rqid = requested.rqid AND requested.rid = resources.rid and request.rqdate = %s group by resources.rname, request.rqdate;"
        cursor.execute(query, (date,))
        result = []
        for row in cursor:
            result.append(row)
        return result

    def weeklyResourcesinNeed(self, date):
        cursor = self.conn.cursor()
        date1 = date.split("-")
        year = int(date1[0])
        month = int(date1[1])
        day = int(date1[2])
        print(year + month + day)
        if month == 1 or month == 3  or month == 5  or month == 7 or month == 8  or month == 10  or month == 12:
            if day+7 > 31:
                if month+1 >12:
                    year = year+1
                    month = "01"
                else:
                    month = month+1
            else:
                day = int(date1[2]) + 7
        else:
            if month == 4 or month == 6 or month == 9 or month == 11:
                if day + 7 > 30:
                    if month + 1 > 12:
                        year = year + 1
                        month = "01"
                    else:
                        month = month + 1
                else:
                    day = int(date1[2]) + 7
            else:
                if month == 2:
                    if day + 7 > 28:
                        if month + 1 > 12:
                            year = year + 1
                            month = "01"
                        else:
                            month = month + 1
                    else:
                        day = int(date1[2]) + 7

            year = str(year)
            if month < 10:
                month = "0" + str(month)
            else:
                month = str(month)

            if day < 10:
                day = "0" + str(day)
            else:
                day = str(day)

        date2 = year + "-" + month + "-" + day
        print(year +"-" +month+"-" + day)

        query = "SELECT rqdate as Week1stDate, resources.rname, sum(request.quantity) FROM public.request, public.requested,public.resources WHERE request.rqid = requested.rqid AND requested.rid = resources.rid and request.rqdate between %s and %s group by  request.rqdate, resources.rname;"
        cursor.execute(query, (date,date2,))
        result = []
        for row in cursor:
            result.append(row)
        return result


from keras.models import Sequential
from keras.layers import Dense
from keras.models import model_from_json
from keras import optimizers
import numpy as np
import os
import pandas as pd
import sys, getopt
from optparse import OptionParser
from pathlib import Path

def train_model(train,truth):
    # Load dataset
    dataset_train = pd.read_csv(train)
    dataset_trainresults = pd.read_csv(truth)

    # Split into input (X) and output (Y) variables
    X_train = dataset_train.iloc[:, 1:21].values
    y_train = dataset_trainresults

    # Create slope model
    model_slope = Sequential()
    model_slope.add(Dense(12, input_dim=20, init='uniform', activation='linear'))
    model_slope.add(Dense(6, init='uniform', activation='linear'))
    model_slope.add(Dense(1, init='uniform', activation='linear'))
    # Compile slope model
    model_slope.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
    # Fit the slope model
    model_slope.fit(X_train, y_train['slope'], epochs=5, batch_size=10,  verbose=2)

    # Create intercept model
    model_intercept = Sequential()
    model_intercept.add(Dense(12, input_dim=20, init='uniform', activation='linear'))
    model_intercept.add(Dense(6, init='uniform', activation='linear'))
    model_intercept.add(Dense(1, init='uniform', activation='linear'))
    # Compile intercept model
    model_intercept.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
    # Fit the intercept model
    model_intercept.fit(X_train, y_train['intercept'], epochs=5, batch_size=10,  verbose=2)

    ## Just for test the predictions
    # Calculate predictions of slope
    #predictions = model_slope.predict(X_train)
    # round predictions
    #rounded_slope = [x[0] for x in predictions]
    #print(rounded)
    #np.savetxt("slope_predict_train.txt",rounded_slope)

    # calculate predictions of intercept
    #predictions2 = model_intercept.predict(X_train)
    # round predictions
    #rounded_intercept = [x[0] for x in predictions2]
    #print(rounded2)
    #np.savetxt("intercept_predict_train.txt",rounded_intercept)

    # serialize slope model to JSON
    model_slope_json = model_slope.to_json()
    with open("model_slope.json", "w") as json_file:
        json_file.write(model_slope_json)
    # serialize slope weights to HDF5
    model_slope.save_weights("model_slope.h5")

    # serialize intercept model to JSON
    model_intercept_json = model_intercept.to_json()
    with open("model_intercept.json", "w") as json_file:
        json_file.write(model_intercept_json)
    # serialize intercept weights to HDF5
    model_intercept.save_weights("model_intercept.h5")
    print("Saved model to disk")

def test_model(test):
    # Load json and create slope model
    json_file_slope = open('model_slope.json', 'r')
    loaded_model_json_slope = json_file_slope.read()
    json_file_slope.close()
    loaded_model_slope = model_from_json(loaded_model_json_slope)
    # Load slope weights into new model
    loaded_model_slope.load_weights("model_slope.h5")
    print("Loaded model slope from disk")

    # Load json and create intercept model
    json_file_intercept = open('model_intercept.json', 'r')
    loaded_model_json_intercept = json_file_intercept.read()
    json_file_intercept.close()
    loaded_model_intercept = model_from_json(loaded_model_json_intercept)
    # Load intercept weights into new model
    loaded_model_intercept.load_weights("model_intercept.h5")
    print("Loaded model intercept from disk")

    # Load dataset of test
    dataset_test = pd.read_csv(test)
    X_test = dataset_test.iloc[:, 1:21].values

    # Evaluate loaded model on test data
    loaded_model_slope.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
    slopes = loaded_model_slope.predict(X_test)
    # Saving the slope predict in file
    np.savetxt("slope_predict_test.txt",slopes)
    print("Slope of prediction save at: slope_predict_test.txt")

    # Evaluate loaded model on test data
    loaded_model_intercept.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
    intercept = loaded_model_intercept.predict(X_test)
    # Saving the intercept predict in file
    np.savetxt("intercept_predict_test.txt",intercept)
    print("Intercept of prediction save at: intercept_predict_test.txt")

def main(argv):

    traintruth = ''
    train = ''
    test = ''

    #Getting args (-t,-r,-n) and testing if is correctly
    try:
        opts, args = getopt.getopt(argv,"h:t:r:n:",["train","traintruth","test"])
    except getopt.GetoptError:
        print('deepersystem.py -t <train.csv> -r <traintruth.csv> || -n <test.csv>')
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            print('deepersystem.py -t <train.csv> -r <traintruth.csv> || -n <test.csv>')
            sys.exit()
        elif opt in ("-t", "--train"):
            train = arg
        elif opt in ("-r", "--traintruth"):
            traintruth = arg
        elif opt in ("-n", "--test"):
            test = arg

    # If all args is null, so exit
    if (test == "" and traintruth=="" and train==""):
        print('deepersystem.py -t <train.csv> -r <traintruth.csv> || -n <test.csv>')
        sys.exit(2)

    # If all args is present, so exit too
    if (test != "" and traintruth!="" and train!=""):
        print('deepersystem.py -t <train.csv> -r <traintruth.csv> || -n <test.csv>')
        print('just -t and -r OR -n')
        sys.exit(2)

    # Verify if train arg and traintruth arg is correctly. If exist model, so dont enter to train, just to test
    if (train != "" and traintruth!=""):
        if Path("model_slope.json").is_file() and Path("model_slope.h5").is_file() and Path("model_intercept.json").is_file() and Path("model_intercept.h5").is_file():
            print("Model already created, please use the test arg or delete the model_slope and model_intercept in both formats .h5 and .json")
        else:
            train_model(train,traintruth)
    elif (test != ""):
        if Path("model_slope.json").is_file() and Path("model_slope.h5").is_file() and Path("model_intercept.json").is_file() and Path("model_intercept.h5").is_file():
            test_model(test)
        else:
            print("Please, use the train to create a Model.")

if __name__ == "__main__":
    main(sys.argv[1:])