# ============== modules and libraries =========================================================
from tkinter import *
from tkcalendar import *
import tkinter.messagebox
import datetime
import sqlite3
# =============== root window and its configuration ============================================
root = Tk()
root.title('UDYOG')
screenwidth = root.winfo_screenwidth()
screenheight = root.winfo_screenheight()
root.geometry("%dx%d%+d%+d" % (screenwidth, screenheight, 0, 0))
root.minsize(900, 800)
root.resizable(width=FALSE, height=TRUE)
bgcolor = '#EEECEB'
root.configure(bg=bgcolor)
udyog = Label(root, text='UDYOG', bg=bgcolor, fg='grey', font=('poppins', 310))
# ================= frames  =====================================================================
loginframe = Frame(root, height=screenheight, width=screenwidth, bg='white')
signup_frame = Frame(root, height=150, width=250, bg=bgcolor)
sellerframe = Frame(root, height=screenheight, width=screenwidth*20/100, bg='skyblue')
productframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg='#A1A1A1')
stocksframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg=bgcolor)
saleframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg='white')
dailyframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg='white')
monthlyframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg='white')
aboutframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg='white')
buyerframe = Frame(root, height=screenheight, width=screenwidth*20/100, bg='skyblue')
shopframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg=bgcolor)
wishlistframe = Frame(root, height=screenheight, width=screenwidth*80/100, bg=bgcolor,)

# ================images===========================================================================
iconimg = PhotoImage(file='resources/appicon.png')
loginbuttonimg = PhotoImage(file='resources/loginbutton.png')
signupbuttonimg = PhotoImage(file='resources/sigupbuttonimg.png')
existingimg = PhotoImage(file='resources/existingimg.png')
productbutton = PhotoImage(file='resources/addproduct.png')
stocksbutton = PhotoImage(file='resources/getstocks.png')
addtocartbutton = PhotoImage(file='resources/addtocart.png')
clearselectbutton = PhotoImage(file='resources/clearselection.png')
gettotalbutton = PhotoImage(file='resources/gettotal.png')
# ============== global variables ==================================================================
userid = ''
data = ''
# ================ variables for login and signup ================
userName = StringVar()
userPass = StringVar()
name = StringVar()
usertype = StringVar()
saleyear = StringVar()
salemonth = StringVar()
# =======variables for products additon==========
productname = StringVar()
productqty = IntVar()
productrate = DoubleVar()
units = StringVar()
# ==========app icon =============================
root.iconphoto(FALSE, iconimg)
# ========variables for wishlist =================
x = datetime.datetime.now()
responce = list()
slistitems = []
slstitemsqty = []
slstvar = []
itemrate = list()
itemunit = ''
selections = tuple()

# ======================================================================================================
flist = [sellerframe, productframe, stocksframe, buyerframe, shopframe,
                    wishlistframe, saleframe, dailyframe, monthlyframe]
framelist = [productframe, stocksframe, saleframe, dailyframe, monthlyframe]
framelist1 = [shopframe, wishlistframe]
scrollbar = Scrollbar(stocksframe)
scrollbar1 = Scrollbar(shopframe)
scrollbar2 = Scrollbar(wishlistframe)
stocklist = Listbox(stocksframe, yscrollcommand=scrollbar.set, font=('poppins', 20))
shoplist = Listbox(shopframe, yscrollcommand=scrollbar.set, font=('poppins', 20), selectmode=MULTIPLE)

# ======================================== Flags =============================================================

logincount = False
signupcount = False
sellercount = False
productcount = False
stockscount = False
salecount = False
dailycount = False
monthlycount =False
buyercount = False
shopcount = False
wishlistcount = False
# ================= functions and widget packings==========================================================

def validatelogin():
    global userid
    userid = userName.get()
    user = userName.get()
    pas = userPass.get()

    if len(user) == 0:
        tkinter.messagebox.showerror('Error', 'Blank UserID, try again')

    elif len(user) == 0 or len(pas) == 0:
        tkinter.messagebox.showerror('Error', 'Please fill the required information')

    elif len(user) <= 5 or len(user) >= 15:
        tkinter.messagebox.showerror('Error', 'Username must be between 5 to 15 characters')

    elif user.isalnum() != 1:
        tkinter.messagebox.showerror('Error', 'Special character or blank space in username is invalid')

    elif user.isalnum() and len(pas) > 7:
        try:
            login = FALSE
            connection = sqlite3.connect('udyog.db')
            cursor = connection.cursor()
            cursor.execute("""SELECT Username, Pass, Type FROM Users""")
            records = cursor.fetchall()
            for row in records:
                if row[0] == user and row[1] == pas:
                    login = True
                    if row[2] == 'SELLER':
                        tkinter.messagebox.showinfo('User Type', 'You are ' + row[2])
                        onseller()
                    elif row[2] == 'CONSUMER':
                        tkinter.messagebox.showinfo('User Type', 'You are ' + row[2])
                        onbuyer()
                userPass.set('')

            cursor.close()
            if not login:
                tkinter.messagebox.showerror('Error', 'Credentials Mismatch !!!')
        except sqlite3.Error as error:
            tkinter.messagebox.showerror('Error', error)

def validatesignup():
    user = userName.get()
    pword = userPass.get()
    typeofuser = usertype.get()
    nameofuser = name.get()
    nameofuser = nameofuser.upper()

    if len(user) == 0:
        tkinter.messagebox.showerror('Error', 'UserID can not be blank')

    elif nameofuser == '':
        tkinter.messagebox.showerror('Error', 'Full name can not be null')

    elif len(user) <= 5 or len(user) >= 15:
        tkinter.messagebox.showerror('Error', 'Username must be between 5 to 15 characters')

    elif user.isalnum() != 1:
        tkinter.messagebox.showerror('Error', 'Special character or blank space in username is invalid')

    elif pword == '':
        tkinter.messagebox.showerror('Error', 'Password can not be null')

    elif user.isalnum() and len(pword) > 7:
        try:
            conn = sqlite3.connect('udyog.db')
            cur = conn.cursor()

            cur.execute('''CREATE TABLE IF NOT EXISTS Users (
                            Username VARCHAR,
                            Name CHAR(30),
                            Pass VARCHAR,
                            Type CHAR
                            );''')

            cur.execute('SELECT Username FROM Users')
            query = cur.fetchall()
            if (user,) in query:
                tkinter.messagebox.showerror('Error', 'Username is already taken')
            else:
                cur.execute('''INSERT INTO Users (Username, Name, Pass, Type)
                            VALUES (?,?,?,?);''', (user, nameofuser, pword, typeofuser))
                conn.commit()
                cur.close()
                tkinter.messagebox.showinfo('Info', 'Account successfully created')
            cur.close()
            userName.set('')
            userPass.set('')

        except sqlite3.Error as error:
            tkinter.messagebox.showerror('Error', error)

def addproduct():
    product_name = productname.get()
    product_unit = units.get()
    product_qty = productqty.get()
    product_rate = productrate.get()

    if len(product_name) == 0 or product_qty == 0 or product_rate == 0:
        tkinter.messagebox.showerror('Empty Fields', 'Fields not filled properly')
    else:
        product_qty = int(product_qty)
        product_rate = float(product_rate)
        try:
            # x = datetime.datetime.now()
            conn = sqlite3.connect('udyog.db')
            cur = conn.cursor()

            cur.execute('''CREATE TABLE IF NOT EXISTS Inventory (
                            ItemName VARCHAR,
                            Unit CHAR(50),
                            Qty INT,
                            Rate FLOAT,
                            TotalCost FLOAT,
                            Date DATE
                            );''')
            cur.execute('''INSERT INTO Inventory (ItemName, Unit, Qty, Rate, TotalCost, Date)
                            VALUES (?,?,?,?,?,?);''', (product_name, product_unit, product_qty, product_rate, product_rate*product_qty, x.date()))
            conn.commit()
            cur.close()
            tkinter.messagebox.showinfo('Info', 'Product added to inventory')
            productname.set('')
            productqty.set('0')
            productrate.set('0.0')

        except sqlite3.Error as error:
            tkinter.messagebox.showerror('Error', error)

def getstocks():
    stocklist.delete(0, 'end')
    stocklist.insert(END, 'ItemName' + ' '*42 + 'Unit' + ' '*46 + 'Qty' + ' '*47 + 'Rate' + ' '*46)
    try:
        conn = sqlite3.connect('udyog.db')
        cur = conn.cursor()
        cur.execute('''SELECT ItemName, Unit, Qty, Rate FROM Inventory''')
        records = cur.fetchall()
        for i in range(len(records)):
            itemname = str(records[i][0])
            units = str(records[i][1])
            quantity = str(records[i][2])
            rate = str(records[i][3])
            if len(itemname) != 50:
                itemname = itemname + ' '*(50 - len(itemname))
            if len(units) != 50:
                units = units + ' '*(50 - len(units))
            if len(quantity) != 50:
                quantity = quantity + ' '*(50 - len(quantity))
            if len(rate) != 50:
                rate = rate + ' '*(50 - len(rate))
            stocklist.insert(END, '  ' + itemname + units + quantity + rate)
        cur.close()
    except sqlite3.Error as error:
        tkinter.messagebox.showerror('Error', error)

def addtocart():
    global selections
    selections = shoplist.curselection()
    if len(selections) != 0:
        wishlist()
        swappanebuyer(wishlistframe)
    else:
        tkinter.messagebox.showerror('Error', 'You have 0 products selected, please select products first')

def getqty():
    global itemrate, itemunit, slstvar, slistitems, slstitemsqty, selections
    try:
        conn = sqlite3.connect('udyog.db')
        cur = conn.cursor()
        cur.execute('''CREATE TABLE IF NOT EXISTS Wishlist (
                        ItemName VARCHAR,
                        Unit VARCHAR,
                        Rate FLOAT,
                        Qty INT,
                        TotalCost FLOAT,
                        Date DATE
                        );''')

        cur.execute('''CREATE TABLE IF NOT EXISTS Sale (
                                            UserId VARCHAR,
                                            ItemName VARCHAR,
                                            Unit VARCHAR,
                                            Rate FLOAT,
                                            Qty INT,
                                            TotalCost FLOAT,
                                            Date DATE
                                            );''')

        for each in responce:
                alldata = each.split('-')
                itemname = str(alldata[0])
                itemunit = alldata[1]
                itemrate.append(float(alldata[2]))
                cur.execute('''INSERT INTO Wishlist (ItemName, Unit, Date)
                        VALUES (?,?,?);''', (itemname, itemunit, x.date()))
                conn.commit()

        for i in range(len(slistitems)):
            qty = slstitemsqty[i].get()
            cur.execute('''UPDATE Wishlist SET Qty = (?), TotalCost = (?), Rate = (?)
                         WHERE ItemName = (?);''', (int(qty), qty*itemrate[i], itemrate[i], slistitems[i]))
            conn.commit()
            cur.execute('''INSERT INTO Sale (UserId, ItemName, Unit, Rate, Qty, TotalCost, Date)
                        VALUES (?,?,?,?,?,?,?);''', (userid, slistitems[i], itemunit, itemrate[i], int(qty), qty*itemrate[i], x.date(),))
            conn.commit()

        for i in range(len(slistitems)):
            qty = slstitemsqty[i].get()
            cur.execute('''SELECT Qty FROM Inventory WHERE ItemName=(?);''', (slistitems[i],))
            qtyfrominventory = cur.fetchone()
            cur.execute('''UPDATE Inventory SET Qty = (?) WHERE ItemName=(?);''', (qtyfrominventory[0]-qty, slistitems[i]))
            cur.execute('''UPDATE Inventory SET TotalCost = (?) WHERE ItemName=(?);''', ((qtyfrominventory[0]-qty)*itemrate[i], slistitems[i]))
            conn.commit()

        cur.execute('''SELECT SUM(TotalCost) FROM Wishlist;''')
        records = cur.fetchone()
        tkinter.messagebox.showinfo('Grand Total', 'Your cart value is - ' + str(records[0]))
        cur.execute('''DROP TABLE Wishlist;''')
        conn.commit()
        cur.close()
        responce.clear()
        slistitems.clear()
        slstitemsqty.clear()
        slstvar.clear()
        itemrate.clear()
        itemunit = ''
        selections = tuple()

    except sqlite3.Error as error:
        tkinter.messagebox.showerror('Error', error)

def signup():
    global signupcount
    if signupcount:
        signup_frame.pack()
    else:
        greet_label = Label(signup_frame, text='Create An Account For UDYOG', bg=bgcolor, fg='#00A3F9', font=('poppins', 50))
        greet_label.pack(side=TOP, anchor='n')

        # rules
        rules = Label(signup_frame, text='''
        1. Username must be between 5 to 15 characters.
        2. must have letter and numbers.
        3. should not contain any special characters (for example: %, #, @).
        5. password must be greater than 7 characters.''', justify=LEFT, bg=bgcolor, fg='grey', font=('helvetica', 20))
        rules.pack()

        signcontainer = Frame(signup_frame, bg=bgcolor)
        signcontainer.pack()

        # Full name of user
        nameLabel = Label(signcontainer, text='Full Name', bg=bgcolor, fg='black', font=('poppins', 18))
        nameLabel.grid(row=1, column=1)
        nameEntry = Entry(signcontainer, textvariable=name, bg=bgcolor, borderwidth=2, font=('poppins', 18))
        nameEntry.grid(row=1, column=2, pady=5)

        # username
        userNameLabel = Label(signcontainer, text='User ID', bg=bgcolor, fg='black', font=('poppins', 18))
        userNameLabel.grid(row=2, column=1)
        userNameEntry = Entry(signcontainer, textvariable=userName,bg=bgcolor, font=('poppins', 18), borderwidth=2)
        userNameEntry.grid(row=2, column=2, pady=5)

        # pass
        userPassLabel = Label(signcontainer, text='Password', bg=bgcolor, fg='black', font=('poppins', 18))
        userPassLabel.grid(row=3, column=1)
        userPassEntry = Entry(signcontainer, textvariable=userPass, show='*', bg=bgcolor, font=('poppins', 18))
        userPassEntry.grid(row=3, column=2, pady=5)

        # user type
        OPTIONS = ["CONSUMER", "SELLER"]
        usertype.set(OPTIONS[0])
        usertypelabel = Label(signcontainer, text='You are - ', bg=bgcolor, fg='black', font=('poppins', 18))
        usertypelabel.grid(row=4, column=1)
        w = OptionMenu(signcontainer, usertype, *OPTIONS)
        w.grid(row=4, column=2, pady=5)

        # buttons
        signupbutton = Button(signcontainer, image=signupbuttonimg, command=validatesignup)
        signupbutton.grid(row=5, column=2, pady=8)
        backtologin = Button(signcontainer, image=existingimg, command=reloginwindow)
        backtologin.grid(row=6, column=2, pady=8)
        signup_frame.pack()
        signupcount = True

def loginWindow():
    global logincount
    if logincount:
        loginframe.pack(expand=TRUE, fill='both')
    else:
        greeting = Label(loginframe, text='''Welcome To UDYOG''', bg='white', fg='#7229F7', font=('poppins', 130))
        greeting.pack(side=TOP, anchor=N)

        logo = Label(loginframe, image=iconimg)
        logo.pack(pady=10)

        container = Frame(loginframe)
        container.pack()

        # username label and entry box
        userNameLabel = Label(container, text='User ID', bg='white', fg='black', font=('poppins', 18))
        userNameLabel.grid(row=1, column=1)
        userNameEntry = Entry(container, textvariable=userName, fg='black',
                              font=('poppins', 18), highlightbackground='lightgrey')
        userNameEntry.grid(row=1, column=2, padx=50, pady=15)

        # password label and entry box
        userPassLabel = Label(container, text='Password', bg='white', fg='black', font=('poppins', 18))
        userPassLabel.grid(row=2, column=1)
        userPassEntry = Entry(container, textvariable=userPass, fg='black', show="*",
                              font=('poppins', 18), highlightbackground='lightgrey')
        userPassEntry.bind("<Return>", (lambda event: validatelogin()))
        userPassEntry.grid(row=2, column=2)

        # Login &  button
        loginbutton = Button(container, image=loginbuttonimg, command=validatelogin)
        loginbutton.grid(row=3, column=2, pady=30)
        signupbutton = Button(container, image=signupbuttonimg, command=signupwindow)
        signupbutton.grid(row=4, column=2)
        loginframe.pack(expand=TRUE, fill='both')
        logincount = True

def seller():
    global sellercount
    if sellercount:
        sellerframe.pack(side='left', fill='both')
        sellerframe.propagate(0)
    else:
        inventory = Button(sellerframe, text='PRODUCTS', font=('poppins', 18), command=lambda: swappaneseller(productframe))
        inventory.pack(fill=BOTH, expand=1)

        stocks = Button(sellerframe, text='STOCKS', font=('poppins', 18), command=lambda: swappaneseller(stocksframe))
        stocks.pack(fill=BOTH, expand=1)

        sale = Button(sellerframe, text='SALE', font=('poppins', 18), command=lambda: swappaneseller(saleframe))
        sale.pack(fill=BOTH, expand=1)

        dailysheet = Button(sellerframe, text='DAILY SHEET', font=('poppins', 18), command=lambda: swappaneseller(dailyframe))
        dailysheet.pack(fill=BOTH, expand=1)

        monthlysheet = Button(sellerframe, text='MONTHLY SHEET', font=('poppins', 18), command=lambda: swappaneseller(monthlyframe))
        monthlysheet.pack(fill=BOTH, expand=1)

        sout = Button(sellerframe, text='SIGNOUT', font=('poppins', 18), command=signout)
        sout.pack(fill=BOTH, expand=1)

        # aboutlabel = Button(sellerframe, text='ABOUT VDYOG', font=('poppins', 18), command=lambda: swappaneseller(aboutframe))
        # aboutlabel.pack(fill=BOTH, expand=1)

        shut = Button(sellerframe, text='EXIT', font=('poppins', 18), command=shutdown)
        shut.pack(fill=BOTH, expand=1)

        sellerframe.pack(side='left', fill='both')
        sellerframe.propagate(0)
        sellercount = True

def products():
    global productcount
    if productcount:
        productframe.pack(side='right', fill='both')
        productframe.propagate(0)
    else:
        addproductlable = Label(productframe, text='Add Product In Inventory', bg='#A1A1A1', fg='white', font=('poppins', 40, 'normal'))
        addproductlable.pack(anchor=N, pady=30)

        productnamelabel = Label(productframe, text='Product Name', bg='#A1A1A1', fg='white', font=('poppins', 18))
        productnamelabel.place(x=290, y=180)
        productnameentry = Entry(productframe, textvariable=productname, bg='#A1A1A1', fg='white', font=('poppins', 18))
        productnameentry.place(x=550, y=180)

        unit = ['Kilogram', 'Litre', 'Bags', 'Bottles', 'Box', 'Dozens', 'Packs', 'Pieces', 'Tablets', 'Grams']
        productunitlabel = Label(productframe, text='Unit', bg='#A1A1A1', fg='white', font=('poppins', 18))
        productunitlabel.place(x=290, y=280)
        w = OptionMenu(productframe, units, *unit)
        units.set(unit[0])
        w.place(x=550, y=280)

        productqtylabel = Label(productframe, text='Quantity', bg='#A1A1A1', fg='white', font=('poppins', 18))
        productqtylabel.place(x=290, y=380)
        productqtyentry = Entry(productframe, textvariable=productqty, bg='#A1A1A1', fg='white', font=('poppins', 18))
        productqtyentry.place(x=550, y=380)

        productratelabel = Label(productframe, text='Rate Per Unit', bg='#A1A1A1', fg='white', font=('poppins', 18))
        productratelabel.place(x=290, y=480)
        productrateentry = Entry(productframe, textvariable=productrate, bg='#A1A1A1', fg='white', font=('poppins', 18))
        productrateentry.place(x=550, y=480)

        addproductbutton = Button(productframe, image=productbutton, bg='#A1A1A1', border=0, activebackground='#A1A1A1', command=addproduct)
        addproductbutton.place(x=550, y=580)

        productframe.pack(side='right', fill='both')
        productframe.propagate(0)
        productcount = True

def stocks():
    global stockscount
    if stockscount:
        stocksframe.pack(side='right', fill='both')
        stocksframe.propagate(0)
    else:
        stockslabel = Label(stocksframe, text='STOCKS', bg=bgcolor, fg='grey', font=('poppins', 40, 'normal'))
        stockslabel.pack(anchor=N, pady=30)
        getstocksbutton = Button(stocksframe, image=stocksbutton, bg=bgcolor, border=0, activebackground=bgcolor, command=getstocks)
        getstocksbutton.pack()
        stocklist.insert(END, 'ItemName' + ' '*42 + 'Unit' + ' '*46 + 'Qty' + ' '*47 + 'Rate' + ' '*46)
        stocklist.pack(side=LEFT, fill=BOTH, expand=TRUE)
        scrollbar.pack(side=RIGHT, fill=Y)
        scrollbar.config(command=stocklist.yview)

        stocksframe.pack(side='right', fill='both')
        stocksframe.propagate(0)
        stockscount = True

def sale():
    global salecount
    def grabsale():
        conn = sqlite3.connect('udyog.db')
        cur = conn.cursor()
        cur.execute('''SELECT SUM(TotalCost) FROM Sale WHERE Date=(?);''', [x.date()])
        record = cur.fetchone()
        salenumlabel.configure(text='₹ ' + str(record[0]))
        cur.close()

    if salecount:
        saleframe.pack(side='right', fill='both')
        saleframe.propagate(0)
    else:
        salelabel = Label(saleframe, text='''TODAY'S SALE''', bg='white', font=('Helvetica Neue', 80))
        salelabel.pack(anchor=N, pady=30)

        refreshlabel = Button(saleframe, text='REFRESH SALE', command=grabsale)
        refreshlabel.pack()

        salenumlabel = Label(saleframe, text='', bg='white', fg='#8900FF', font=('arial unicode ms', 200, 'bold'))
        salenumlabel.pack(anchor=N, pady=60)

        saleframe.pack(side='right', fill='both')
        saleframe.propagate(0)
        salecount = True

def daily():
    global dailycount, data

    def getdate():
        global data
        data = cal.get_date()
        conn = sqlite3.connect('udyog.db')
        cur = conn.cursor()
        cur.execute('''SELECT SUM(TotalCost) FROM Sale WHERE Date=(?);''', [data])
        record = cur.fetchone()
        salelabel.configure(text='₹ ' + str(record[0]))
        cur.close()

    if dailycount:
        dailyframe.pack(side='right', fill='both')
        dailyframe.propagate(0)
    else:
        cal = Calendar(dailyframe, seLectmode="month", year=x.year, month=x.month, day=x.day, date_pattern='y-mm-dd', font=('poppins', 20), selectforeground='red')
        cal.pack(fill=BOTH, expand=FALSE, pady=20)

        dailylabel = Label(dailyframe, text='''Select Day For Sale Records''', bg='white', font=('poppins', 20))
        dailylabel.pack(anchor=N)

        getdatebutton = Button(dailyframe, text='Get Sale', command=getdate)
        getdatebutton.pack(pady=5)

        salelabel = Label(dailyframe, text='', bg='white', fg='red', font=('arial unicode ms', 200, 'bold'))
        salelabel.pack(anchor=N, pady=5)

        dailyframe.pack(side='right', fill='both')
        dailyframe.propagate(0)
        dailycount = True

def monthly():
    global monthlycount, salemonth, saleyear

    def grabmonthsale():
        global salemonth, saleyear
        getmonth = salemonth.get()
        m = getmonth.split('-')
        mm = m[1]
        yyyy = saleyear.get()
        startdate = yyyy + '-' + mm + '-' + '01'
        enddate = yyyy + '-' + mm + '-' + '31'

        conn = sqlite3.connect('udyog.db')
        cur = conn.cursor()
        cur.execute('''SELECT SUM(TotalCost) FROM Sale WHERE Date >= (?) AND Date <= (?);''', (startdate, enddate))
        record = cur.fetchone()
        salenumlabel.configure(text='₹ ' + str(record[0]))
        cur.close()

    if monthlycount:
        monthlyframe.pack(side='right', fill='both')
        monthlyframe.propagate(0)
    else:
        salelabel = Label(monthlyframe, text='''MONTHLY SALE''', bg='white', font=('poppins', 50))
        salelabel.pack(anchor=N, pady=30)

        YEAR = ['2015', '2016', '2017', '2018', '2019', '2020', '2021']
        saleyear.set(YEAR[6])
        year = OptionMenu(monthlyframe, saleyear, *YEAR)
        year.pack(pady=10)

        MONTH = ['January-01', 'February-02', 'March-03', 'April-04', 'May-05', 'June-06', 'July-07', 'August-08',
                 'September-09', 'October-10', 'November-11', 'December-12']
        salemonth.set(MONTH[0])
        month = OptionMenu(monthlyframe, salemonth, *MONTH)
        month.pack(pady=10)

        getmonthbutton = Button(monthlyframe, text='Get Sale', command=grabmonthsale)
        getmonthbutton.pack(pady=10)

        salenumlabel = Label(monthlyframe, text='', bg='white', fg='#96CC39', font=('arial unicode ms', 200, 'bold'))
        salenumlabel.pack(anchor=N, pady=60)

        monthlyframe.pack(side='right', fill='both')
        monthlyframe.propagate(0)
        monthlycount = True

def buyer():
    global buyercount
    if buyercount:
        buyerframe.pack(side='left', fill='both')
        buyerframe.propagate(0)
    else:
        inventory = Button(buyerframe, text='SHOP PRODUCTS', font=('poppins', 18), command=lambda: swappanebuyer(shopframe))
        inventory.pack(fill=BOTH, expand=1)

        stocks = Button(buyerframe, text='', font=('poppins', 18))

        stocks.pack(fill=BOTH, expand=1)

        sign = Button(buyerframe, text='SIGNOUT', font=('poppins', 18), command=signout)
        sign.pack(fill=BOTH, expand=1)

        sale = Button(buyerframe, text='', font=('poppins', 18))
        sale.pack(fill=BOTH, expand=1)

        shut = Button(buyerframe, text='EXIT', font=('poppins', 18), command=shutdown)
        shut.pack(fill=BOTH, expand=1)

        buyerframe.pack(side='left', fill='both')
        buyerframe.propagate(0)
        buyercount = True

def shop():
    global shopcount

    def clearselect():
        shoplist.selection_clear(0, END)

    if shopcount:
        try:
            shoplist.delete(0, END)
            conn = sqlite3.connect('udyog.db')
            cur = conn.cursor()
            cur.execute('''SELECT ItemName, Unit, Rate FROM Inventory''')
            records = cur.fetchall()
            for i in range(len(records)):
                itemname = str(records[i][0])
                units = str(records[i][1])
                rate = str(records[i][2])
                shoplist.insert(END, itemname + '-' + units + '-' + rate)
            cur.close()
        except sqlite3.Error as error:
            tkinter.messagebox.showerror('Error', error)
        shopframe.pack(side='right', fill='both')
        shopframe.propagate(0)
    else:
        shopheadlabel = Label(shopframe, text='Select Products for shopping', bg=bgcolor, fg='grey', font=('poppins', 40))
        shopheadlabel.pack(anchor=N, pady=30)
        getshoplistbutton = Button(shopframe, image=addtocartbutton, bg=bgcolor, bd=5, anchor=CENTER, command=addtocart)
        getshoplistbutton.pack()
        clearselection = Button(shopframe, image=clearselectbutton, bg=bgcolor, bd=5, anchor=CENTER, command=clearselect)
        clearselection.pack()
        formatlabel = Label(shopframe, text='''List is displayed in following format (Itemname)-(Unit)-(Rate per unit)''', bg=bgcolor, fg='grey', font=('poppins', 20))
        formatlabel.pack()
        shoplist.delete(0, END)
        try:
            conn = sqlite3.connect('udyog.db')
            cur = conn.cursor()
            cur.execute('''SELECT ItemName, Unit, Rate FROM Inventory''')
            records = cur.fetchall()
            for i in range(len(records)):
                itemname = str(records[i][0])
                units = str(records[i][1])
                rate = str(records[i][2])
                shoplist.insert(END, itemname + '-' + units + '-' + rate)
            cur.close()
        except sqlite3.Error as error:
            tkinter.messagebox.showerror('Error', error)

        shoplist.pack(side=LEFT, fill=BOTH, expand=TRUE)
        scrollbar1.pack(side=RIGHT, fill=Y)
        scrollbar1.config(command=shoplist.yview)

        shopframe.pack(side=RIGHT, fill='both')
        shopframe.propagate(0)
        shopcount = True

def wishlist():
    global wishlistcount, selections, slstitems, slstitemsqty, slstvar
    selections = shoplist.curselection()

    if wishlistcount:
        wishlistframe.pack(side='left', fill='both')
        wishlistframe.propagate(0)
    else:
        for i in selections:
            entries = shoplist.get(i)
            responce.append(entries)
        for each in responce:
            alldata = each.split('-')
            slstitemsqty.append(alldata[0])
            slistitems.append(alldata[0])
            slstvar.append(alldata[0])

        for i in range(len(slstitemsqty)):
            slstitemsqty[i] = IntVar()

        selectquantitylabel = Label(wishlistframe, text='Select Quantity Of Each Products', bg=bgcolor, font=('poppins', 30))
        selectquantitylabel.pack(anchor=N, pady=30)

        for i in range(len(slistitems)):
            l1 = Label(wishlistframe, text=slistitems[i], bg=bgcolor, font=('poppins', 18))
            l1.pack()
            s1 = Scale(wishlistframe, variable=slstitemsqty[i], from_=1, to=50, orient=HORIZONTAL, bg=bgcolor, font=('poppins', 18), length=200)
            s1.pack()

        getqtybutton = Button(wishlistframe, image=gettotalbutton, bg=bgcolor, border=0, command=getqty)
        getqtybutton.pack(pady=50)
        scrollbar2.pack(side=RIGHT, fill=Y)
        scrollbar2.config(command=shoplist.yview)
        # wishlistframe.configure(yscrollcommand=scrollbar2.set)
        wishlistframe.pack(side='right', fill='both')
        wishlistframe.propagate(0)
        wishlistcount = True

def signout():
    res = tkinter.messagebox.askquestion('Sign Out', 'Do you really want to sign out ?')
    if res == 'yes':
        for x in flist:
            x.pack_forget()
        udyog.pack_forget()
        loginframe.pack(expand=TRUE, fill='both')
    else:
        pass

def shutdown():
    res = tkinter.messagebox.askquestion('Exit Application', 'Do you really want to exit')
    if res == 'yes':
        root.destroy()
    else: pass

def swappaneseller(frame):
    for x in framelist:
        x.pack_forget()
    udyog.pack_forget()
    if frame == saleframe:
        frame.update()
        frame.pack()
    else:
        frame.pack()

def swappanebuyer(frame):
    for x in framelist1:
        x.pack_forget()
    udyog.pack_forget()
    if frame == wishlistframe:
        frame.update()
        frame.pack()
    else:
        frame.pack()

def onseller():
    loginframe.pack_forget()
    seller()
    stocks()
    products()
    sale()
    daily()
    monthly()
    stocksframe.pack_forget()
    productframe.pack_forget()
    saleframe.pack_forget()
    dailyframe.pack_forget()
    monthlyframe.pack_forget()
    udyog.pack(side=RIGHT, anchor=CENTER)

def onbuyer():
    loginframe.pack_forget()
    buyer()
    shop()
    shopframe.pack_forget()
    udyog.pack(side=RIGHT, anchor=CENTER)

def signupwindow():
    loginframe.pack_forget()
    signup()

def reloginwindow():
    signup_frame.pack_forget()
    loginWindow()

loginWindow()
root.mainloop()


from collections import OrderedDict

from django.contrib.gis.geos import Point
from django.utils import timezone

from rest_framework import serializers

class DateTimeFieldWithTZ(serializers.DateTimeField):

    def enforce_timezone(self, value):
        """
        If `self.default_timezone` is `None`, always return naive datetimes.
        If `self.default_timezone` is not `None`, return aware datetimes.
        """
        try:
            tz = timezone._active.value
            if (self.default_timezone is not None) \
                    and not timezone.is_aware(value):
                return timezone.make_aware(value, tz)
            return value
        except AttributeError:
            return super().enforce_timezone(value)

    def to_representation(self, value):
        value = timezone.localtime(value)
        return super().to_representation(value)

class CustomLocationField(serializers.Serializer):
    """Location field for representing points with 2 coordinates.

    django.contrib.gis.geos.Point represented using dict:
    {
        "longitude": 12,
        "latitude": 12
    }
    """

    longitude = serializers.FloatField(
        max_value=180,
        min_value=-180,
        required=True
    )
    latitude = serializers.FloatField(
        max_value=90,
        min_value=-90,
        required=True
    )

    def to_internal_value(self, value: dict) -> Point:
        """Convert ``dict`` to ``Point``

        Args:
            value (dict): Value to convert

        Returns:
            Point: Point with ``x=value['longitude']`` and
                ``y=value['latitude']``

        Raises:
            ValidationError: when value is not dict and latitude and longitude
                values not in according ranges
        """
        value = super().to_internal_value(value)
        return Point(value['longitude'], value['latitude'])

    def to_representation(self, obj: Point) -> OrderedDict:
        """Convert from ``Point`` to ``OrderedDict``.

        Args:
            obj (Point): Point to represent

        Returns:
            OrderedDict: Ordered dict with ``longitude`` and ``latitude`` keys
                and float values
        """
        return OrderedDict([
            ('longitude', obj.x),
            ('latitude', obj.y),
        ])


import pandas as pd
import boto3
import numpy as np
import pickle

import subprocess
import sys
import os

from keras.models import Sequential
from keras.layers import Dense, LSTM, Embedding, Flatten, Dropout, MaxPooling1D, Flatten
from keras.utils import to_categorical

import argparse

'''
FUNCTION:       install
PURPOSE:        calls pip to install a given python module
INPUT:          package       (string - desired python module)
OUTPUT:         no explicit return
'''

def install(package):
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

install('gensim')

from gensim.models import Word2Vec, KeyedVectors

#DEFINE MAIN FUNCTION FOR SAGEMAKER TRAINER

if __name__ == '__main__':

    #DEFINE PARSER AND ARGUMENTS FOR CALL WITH SAGEMAKER

    parser = argparse.ArgumentParser()

    parser.add_argument('--epochs', type = int, default = 1)
    parser.add_argument('--batch_size', type = int, default = 1024)
    parser.add_argument('--learning_rate', type = float, default = 0.01)

    parser.add_argument('--model', type=str)
    parser.add_argument('--train', type=str, default=os.environ.get('SM_CHANNEL_TRAIN'))
    parser.add_argument('--test', type=str, default=os.environ.get('SM_CHANNEL_EVAL'))

    args, _ = parser.parse_known_args()

    epochs = args.epochs
    learning_rate = args.learning_rate
    batch_size = args.batch_size

    model_dir = args.model
    training_dir = args.train
    test_dir = args.test

    #DEFINE S3 RESOURCE, BUCKET AND KEY

    s3_client = boto3.client('s3')
    s3_resource = boto3.resource('s3')

    bucket = 'mh-upload-bucket'
    key = 'data/Reddit/'

    #DEFINE MAXIMUM SEQUENCE LENGTH OF TEXTS AND MAXIMUM EMBEDDING LENGTH

    seq_len = 25
    embed_len = 300

    #LOAD TRAINING AND TEST DATA FROM S3 BUCKET AND FIT SHAPE PROPERLY

    df_train_obj = s3_client.get_object(Bucket = bucket, Key = key + 'train_df.json')
    df_test_obj = s3_client.get_object(Bucket = bucket, Key = key + 'test_df.json')

    df_train = pd.read_json(df_train_obj['Body'], orient = 'records', lines = True)
    df_test = pd.read_json(df_test_obj['Body'], orient = 'records', lines = True)

    X_train = np.concatenate(df_train['num_tokenized_title']).ravel().reshape(-1, seq_len)
    X_test = np.concatenate(df_test['num_tokenized_title']).ravel().reshape(-1, seq_len)

    #1-HOT-ENCODE CATEGORIES FOR TRAIN AND TEST DATA

    y_train = to_categorical(np.asarray(df_train['6_way_label']), num_classes = 6)
    y_test = to_categorical(np.asarray(df_test['6_way_label']), num_classes = 6)

    #LOAD TOKENIZER FROM PICKLE FILE AND SPECIFY VOCAB AND VOCAB_SIZE FOR EMBEDDING MATRIX

    tkz = pickle.loads(s3_resource.Object(bucket, key + 'tokenizer_reddit.pkl').get()['Body'].read())
    vocab_size = len(tkz.word_index) + 1
    vocab = tkz.word_index

    #LOAD PRE-TRAINED WORD2VEC MODEL (GOOGLE NEWS) AND SPECIFY EMBEDDING MATRIX

    wv = KeyedVectors.load_word2vec_format('s3://mh-upload-bucket/data/Reddit/GoogleNews-vectors-negative300.bin.gz', binary = True)
    embed_mat = np.random.normal(loc = 0., scale = 1.0, size = (vocab_size, embed_len))

    for entry, i in vocab.items():

        if entry in wv.vocab:

            embed_mat[i, :] = wv[entry]

    #DEFINE KERAS SEQUENTIAL MODEL

    model = Sequential()
    model.add(Embedding(vocab_size, embed_len, weights = [embed_mat], input_shape = (seq_len,)))
    model.add(Dropout(0.05))
    model.add(LSTM(128, dropout = 0.1, recurrent_dropout = 0.15, return_sequences = True))
    model.add(LSTM(64, dropout = 0.1, recurrent_dropout = 0.15, return_sequences = True))
    model.add(Dropout(0.10))
    model.add(LSTM(32, dropout = 0.15, recurrent_dropout = 0.2, return_sequences = True))
    model.add(MaxPooling1D(pool_size = 2))

    model.add(Flatten())

    model.add(Dense(6, activation = 'softmax'))

    #COMPILE KERAS MODEL

    model.compile(optimizer = 'RMSprop', loss = 'binary_crossentropy', metrics = ['accuracy'])

    #FIT KERAS MODEL

    model.fit(X_train, y_train, batch_size = batch_size, epochs = epochs, validation_data = (X_test, y_test))

    #SAVE KERAS MODEL TO S3 BUCKET

    model.save('reddit_classifier.h5')
    s3_client.upload_file(Filename = 'reddit_classifier.h5', Bucket = bucket, Key = key + 'reddit_classifier.h5')


import requests
import json

with open("config.json") as configFile:
    jsonObject = json.load(configFile)
    configFile.close()

    apiKey = jsonObject['keys']['api_key']

def requestAPIResp(_url):
    resp = requests.get(_url)
    return resp

def saveToJSON(_apiResponse):
    global fileName
    if isCityAPI:
        fileName = "currentcity.json"
    if not isCityAPI:
        fileName = "suntimerfile.json"

    file = open(fileName, "w")
    json.dump(res.json(), file, indent=6)
    file.close()

#####################################################

limit = 1

cityName = input("Please enter the city name: ")
countryCode = input("Please enter the country code: ")

urlCity = f"http://api.openweathermap.org/geo/1.0/direct?q={cityName},{countryCode}&limit={limit}&appid={apiKey}"
isCityAPI = True

res = requestAPIResp(urlCity)

if res.status_code == 200:

    saveToJSON(res)
    isCityAPI = False

    with open("currentcity.json", "r") as jsonCityFile:
        obj = json.load(jsonCityFile)
        jsonCityFile.close()

        lat = obj[0]['lat']
        lng = obj[0]['lon']

    urlSun = f"https://api.sunrise-sunset.org/json?lat=,{lat},&lng=,{lng},&date=today"  # https://sunrise-sunset.org/api
    print(urlSun)
    res = requestAPIResp(urlSun)
    print(res.status_code)

    if res.status_code == 200:
        saveToJSON(res)

        with open("suntimerfile.json") as jsonFile:
            jsonObject = json.load(jsonFile)
            jsonFile.close()

            sunrise = jsonObject['results']['sunrise']
            sunset = jsonObject['results']['sunset']
            solarNoon = jsonObject['results']['solar_noon']
            dayLength = jsonObject['results']['day_length']

            print("Sunrise: " + sunrise, "Sunset: " + sunset, "Solar Noon: " + solarNoon, "Day Length: " + dayLength,
                  sep=" , ")
            print("Times are in UTC")
    else:
        print("No valid Sun Response")

else:
    print("No valid City response")


import numpy as np
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
from tqdm import tqdm
from scipy import signal
import matplotlib.pyplot as plt

class Net(nn.Module):
    def __init__(self, H, Dx, Dy, D):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(Dx, H)
        self.fc2 = nn.Linear(Dy, H)
        self.fc3 = nn.Linear(H,H)
        self.fc4 = nn.Linear(H, D)

    def forward(self, x, y):
        h1 = F.relu(self.fc1(x)+self.fc2(y))
        h2 = F.relu(self.fc3(h1))
        h3 = self.fc4(h2)
        return h3

def Jasmine(x,y,n_epoch = 500, H = 100, data_proportion = 0.2, window_size=0.1, Plotting = True):
    Dx = x.shape[1]
    Dy = y.shape[1]
    data_size = int(data_proportion*x.shape[0])
    sx = normalize(x)
    sy = normalize(y)
    xy = np.concatenate((sx,sy), axis=1)
    model = Net(H, Dx, Dy, D)
    optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
    plot_loss = []
    for epoch in tqdm(range(n_epoch)):
        xy = xy[np.random.permutation(xy.shape[0]), :]
        x_sample=xy[:data_size,:x.shape[1]]
        y_sample=xy[:data_size,x.shape[1]:]
        y_shuffle = np.random.permutation(y_sample)

        x_sample = Variable(torch.from_numpy(x_sample).type(torch.FloatTensor), requires_grad = True)
        y_sample = Variable(torch.from_numpy(y_sample).type(torch.FloatTensor), requires_grad = True)
        y_shuffle = Variable(torch.from_numpy(y_shuffle).type(torch.FloatTensor), requires_grad = True)

        pred_xy = model(x_sample, y_sample)
        pred_x_y = model(x_sample, y_shuffle)

        ret = torch.mean(pred_xy) - torch.log(torch.mean(torch.exp(pred_x_y)))
        loss = - ret
        plot_loss.append(loss.data.numpy())
        model.zero_grad()
        loss.backward()
        optimizer.step()
    pl = -np.array(plot_loss)
    res = signal.savgol_filter(pl, int(data_size*window_size) + 1, 3)
    if Plotting == True:
        plt.plot(np.arange(n_epoch)+1, res)
        plt.xlabel("epoch, n")
        plt.ylabel("Mutual information, nat")
        plt.grid(True)
        plt.show()
    print("\n Mutual information is ", res[-1])
    return res[-1]

def normalize(z):
    sz = np.zeros(z.shape)
    for i in range(z.shape[1]):
        sz[:,i] = (z[:,i] - np.mean(z[:,i]))/np.std(z[:,i])
    return sz


#!/usr/bin/python3

import os
import ssl
import json
import socket
import select
import argparse
from time import sleep
from string import digits
from tap import Tap

SLEEP_TIME_SEC = 0.005
THUB_CLIENT_SOCKET_READ_WRITE = b'TCSRW'
CONTROL_SOCKET_UPDATE_MAC_ADDRESS = b'CSUMA'

def read_packet(client_socket):
    expected_packet_size = client_socket.recv(5)
    if expected_packet_size != b"":
        next_byte = 0
        while ((chr(expected_packet_size[0]) not in digits) and (next_byte != b"")):
            next_byte = client_socket.recv(1)
            expected_packet_size = expected_packet_size[1:] + next_byte
        if b'\x00' in expected_packet_size:
            expected_packet_size = int(expected_packet_size[:expected_packet_size.index(b'\x00')].decode())
        else:
            expected_packet_size = int(expected_packet_size.decode())
        return read_full_packet(client_socket, expected_packet_size)
    else:
        raise ConnectionResetError("The socket was closed while reading")

def read_full_packet(client_socket, expected_packet_size):
    full_packet = b""
    while len(full_packet) < expected_packet_size:
        packet = client_socket.recv(expected_packet_size - len(full_packet))
        if packet == b"":
            ConnectionResetError("The socket was closed while reading")
        full_packet += packet
    return full_packet

def prepare_packet(packet_data):
    packetlen = str(len(packet_data))
    packetlen = packetlen.encode() + (b'\x00' * (5 - len(packetlen)))
    return packetlen + packet_data

def send_packet(client_socket, packet):
    client_socket.sendall(prepare_packet(packet))

def inform_server_about_new_mac_address(client, new_mac):
    client.send(CONTROL_SOCKET_UPDATE_MAC_ADDRESS + new_mac)

def validate_send_mac_address(sender_address, device, client):
    if sender_address != device.mac_address:
        if device._check_if_mac_has_changed():
            inform_server_about_new_mac_address(client, device.mac_address)
        else:
            print("\n".join(["[!] Warning! Sending a packet with a mac address that differs from the device's address.",
                             "This can cause unexpected behaviour!"]))

def communication_loop(device, client_socket):
    while True:
        should_sleep = True
        ready_socket, _, _ = select.select([client_socket], [], [], 0)
        # Read from server socket and write to tap
        if ready_socket:
            packet = read_packet(client_socket)
            device.send_packet(packet)
            should_sleep = False
        # Read from tap and write to server socket
        if device.is_ready_to_read():
            packet, sender = device.read_packet()
            validate_send_mac_address(sender, device, client_socket)
            send_packet(client_socket, packet)
            should_sleep = False
        # Sleep to avoid busy loops if no packets were sent
        if should_sleep:
            sleep(SLEEP_TIME_SEC)

def print_new_device_info(device):
    print(f"[*] Created device: {device}", end='\n\t')
    parsed_mac_address = ":".join([hex(i)[2:] if len(hex(i)) == 4 else '0'+hex(i)[2:] for i in device.mac_address])
    print('\n\t'.join([f"MAC Address:\t{parsed_mac_address}",
                       f"IP Address:\t{device.ip}",
                       f"Netmask:\t{device.netmask}"]))
    print(f"[*] You can start using {device.tap_name.decode()} now")

def init_client_socket(client, mac_address):
    client.send(THUB_CLIENT_SOCKET_READ_WRITE)
    inform_server_about_new_mac_address(client, mac_address)

def main_loop(server_ip, server_port, tap_name, mac_address, ip_address, netmask):
    if tap_name is None:
        tap_name = b'\x00'
    print(f"[*] Connecting to server:{server_ip}:{server_port}")
    client = socket.socket()
    client.connect((server_ip, server_port))
    ssl_socket = ssl.wrap_socket(client)
    try:
        with Tap(tap_name, ip_address, netmask, mac_address) as device:
            print_new_device_info(device)
            init_client_socket(ssl_socket, device.mac_address)
            try:
                communication_loop(device, ssl_socket)
            finally:
                print(f"\n[*] Closing tap device: {device}")
    finally:
        print("[*] Closing server connection!")
        ssl_socket.close()
        client.close()

def parse_argumets():
    parser = argparse.ArgumentParser(description='THUB client')
    parser.add_argument('--config', '-c', help="Path to the config file", type=str, required=True)
    return parser.parse_args()

def main():
    args = parse_argumets()
    if not os.path.isfile(args.config):
        print(f"Could not open the configuration file {args.config}")
        return
    with open(args.config) as args.config:
        config = json.load(args.config)
    main_loop(
        server_ip=config['server']['host'], server_port=config['server']['port'],
        tap_name=config['client']['tap_name'], mac_address=config['client']['mac_address'],
        ip_address=config['client']['ip_address'], netmask=config['client']['ip_netmask'])

if __name__ == '__main__':
    main()


import sqlite3
import datetime

connection = sqlite3.connect('db/stocktrade.db')
cursor = connection.cursor()

def register(username,password):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()
    try:
        cursor.execute("""
INSERT INTO users(name, password, balance)
VALUES ('{}','{}',100000);
    """.format(username,password))
        connection.commit()
        return True
    except:
        connection.commit()
        return False

def login(username,password):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()
    try:
        cursor.execute("""
    SELECT name, balance
    FROM users
    WHERE name = '{}' AND password = '{}';
        """.format(username, password))
        fetch = cursor.fetchall()
        try:
            connection.commit()
            return True, fetch[0][0], fetch[0][1]
        except:
            connection.commit()
            return False, False, False
    except:
        connection.commit()
        return False, False, False

def get_balance(username):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()
    try:
        cursor.execute("""
        SELECT balance
        FROM users
        WHERE name = '{}'
        ;
            """.format(username))
        fetch = cursor.fetchone()
        connection.commit()
        return fetch[0]
    except:
        connection.commit()
        return False

def buy_stocks_users_table(username,cost, cash_balance):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()

    # update the balance in the USERS table to show that he bought shares
    difference = float(cash_balance) - float(cost)

    try:
        cursor.execute("""
            UPDATE users SET balance = '{}' WHERE name = '{}'
            ;
                """.format(difference, username))
        connection.commit()
        return True
    except:
        connection.commit()
        return False

def buy_stocks_transactions_table(quantity,ticker,price,username):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()

    # get primary key from users first
    cursor.execute("""
        SELECT pk FROM users WHERE name = '{}'
                    ;
                        """.format(username))
    id = cursor.fetchone()
    now = datetime.datetime.now()

    # update the TRANSACTIONS table to show that he bought shares
    try:
        cursor.execute("""
                INSERT INTO transactions(userID, symbol, unixtime, lastprice, quantity, buysell)
                VALUES ('{}','{}','{}','{}','{}','{}')
                ;
                    """.format(id[0],ticker,now,price, quantity,'b' ))
        connection.commit()
        return True
    except:
        connection.commit()
        return False

def buy_stocks_positions_table(quantity,ticker,price,username):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()

    # get primary key from users first
    cursor.execute("""
            SELECT pk FROM users WHERE name = '{}'
                        ;
                            """.format(username))
    id = cursor.fetchone()

    # check if anything in positions exists. If so create VWAP and then UPDATE. Else add to positions.
    cursor.execute("""
            SELECT VWAP, quantity
            FROM positions
            WHERE userID = '{}' AND symbol = '{}';
                        """.format(id[0], ticker))
    VWAP_query = cursor.fetchall()

    # if VWAP doesn't exist in positions list then add to positions
    if len(VWAP_query) == 0:
        # check if initial commit of symbol to position - if so we can add to position'
        cursor.execute("""
                INSERT INTO positions(userID, symbol, quantity, VWAP)
                VALUES('{}','{}','{}','{}')
                ;""".format(id[0], str(ticker), quantity, float(price)))
        connection.commit()
    else:
        # stock already in position - time to adjust the position
        VWAP_price = VWAP_query[0][0]
        VWAP_quantity = VWAP_query[0][1]
        newVWAPtop = (float(price) * float(quantity)) + (float(VWAP_price) * float(VWAP_quantity))
        newVWAPbottom = (float(VWAP_quantity) + float(quantity))
        VWAP_price = float(newVWAPtop) / float(newVWAPbottom)
        VWAPfinalprice = VWAP_price
        VWAPfinalquantity = newVWAPbottom

        # update quantity
        cursor.execute("""
        UPDATE positions
        SET quantity = '{}'
        WHERE userID = '{}' AND symbol = '{}'
        ;""".format(int(VWAPfinalquantity), id[0], ticker))

        connection.commit()

        # update VWAPprice
        cursor.execute("""
                UPDATE positions
                SET VWAP = '{}'
                WHERE userID = '{}' AND symbol = '{}'
                ;""".format(VWAPfinalprice, id[0], ticker))

        connection.commit()

        VWAP_query = cursor.fetchall()

        connection.commit()

def sell_get_list_of_positions(username):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()

    # get primary key from users first
    cursor.execute("""
                SELECT pk FROM users WHERE name = '{}'
                            ;
                                """.format(username))
    id = cursor.fetchone()

    cursor.execute("""
                SELECT symbol, VWAP, quantity
                FROM positions
                WHERE userID = '{}';
                            """.format(id[0]))
    positions_query = cursor.fetchall()
    if len(positions_query) == 0:
        return False
    else:
        # [ (ticker, price, quantity ) ]
        final_query_list = []
        for tups in positions_query:
            l = []
            for items in tups:
                l.append(items)
            final_query_list.append(l)
        return final_query_list

def sell_stocks_user_table(username, income):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()

    # get primary key from users first
    cursor.execute("""
                SELECT pk FROM users WHERE name = '{}'
                            ;
                                """.format(username))
    id = cursor.fetchone()

    # get current balance
    cursor.execute("""
    SELECT balance FROM users WHERE pk = '{}'
                    ;
                        """.format(id[0]))
    balance = cursor.fetchone()[0]
    new_balance = balance + income

    # update the balance in the USERS table to show that he bought shares
    try:
        cursor.execute("""
                UPDATE users SET balance = '{}' WHERE pk = '{}'
                ;
                    """.format(new_balance, id[0]))
        connection.commit()
        return True, new_balance, income
    except:
        connection.commit()
        return False

def sell_stocks_transactions_table(username, ticker_sell_symbol, ticker_sell_quantity,current_price):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()

    # get primary key from users first
    cursor.execute("""
                    SELECT pk FROM users WHERE name = '{}'
                                ;
                                    """.format(username))
    id = cursor.fetchone()
    now = datetime.datetime.now()

    # update the TRANSACTIONS table to show that we sold shares
    try:
        cursor.execute("""
                    INSERT INTO transactions(userID, symbol, unixtime, lastprice, quantity, buysell)
                    VALUES ('{}','{}','{}','{}','{}','{}')
                    ;
                        """.format(id[0], ticker_sell_symbol, now, current_price, ticker_sell_quantity, 's'))
        connection.commit()
        return True
    except:
        connection.commit()
        return False

def sell_stocks_positions_table(username, ticker_sell_symbol, ticker_sell_quantity,current_price):
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()

    # get primary key from users first
    cursor.execute("""
                SELECT pk FROM users WHERE name = '{}'
                            ;
                                """.format(username))
    id = cursor.fetchone()

    # check if anything in positions exists. If so create VWAP and then UPDATE. Else add to positions.
    cursor.execute("""
                SELECT quantity
                FROM positions
                WHERE userID = '{}' AND symbol = '{}';
                            """.format(id[0], ticker_sell_symbol))
    VWAP_query = cursor.fetchone()
    position_quantity = VWAP_query[0]
    new_position_quantity = position_quantity - ticker_sell_quantity

    # time to subtract the quantity in the position

    cursor.execute("""
        UPDATE positions
        SET quantity = '{}'
        WHERE userID = '{}' AND symbol = '{}'
        ;""".format(new_position_quantity, id[0],ticker_sell_symbol))

    connection.commit()
    return True

def get_all_users():
    connection = sqlite3.connect('db/stocktrade.db')
    cursor = connection.cursor()
    try:
        cursor.execute("""
            SELECT name
            FROM users
            ;
                """)
        fetch = cursor.fetchall()
        f2 = []
        for tups in fetch:
            f2.append(list(tups))
        connection.commit()
        return f2
    except:
        connection.commit()
        return False


from django.shortcuts import render,redirect
from Registration_Login.models import *

def admin_dashboard(request):
    if 'admin_id' in request.session:
        if request.session.has_key('admin_id'):
            admin_id = request.session['admin_id']

        else:
            return redirect('/')

        Admin_dash = LogRegister_Details.objects.get(id=admin_id)
        dash_details = BusinessRegister_Details.objects.get(log_id=Admin_dash)

        content = {'Admin_dash':Admin_dash,'dash_details':dash_details}

        return render(request,'AD_dashboard.html',content)

    else:
            return redirect('/')

# Department ---------------------

def admin_department(request):
    if 'admin_id' in request.session:
        if request.session.has_key('admin_id'):
            admin_id = request.session['admin_id']

        else:
            return redirect('/')

        Admin_dash = LogRegister_Details.objects.get(id=admin_id)
        dash_details = BusinessRegister_Details.objects.get(log_id=Admin_dash)
        departments = DepartmentRegister_details.objects.filter(brd_id=dash_details)

        if request.POST:

            depart_obj = DepartmentRegister_details()
            depart_obj.dept_name = request.POST['department_name']
            depart_obj.dept_content = request.POST['department_discription']
            depart_obj.dept_active_status = 1
            depart_obj.brd_id = dash_details
            depart_obj.save()

            success = True
            success_text = 'New department created successfully '

            departments = DepartmentRegister_details.objects.filter(brd_id=dash_details)

            content = {'Admin_dash':Admin_dash,
                   'dash_details':dash_details,
                   'success':success,
                   'success_text':success_text,
                   'departments':departments}
        else:

            content = {'Admin_dash':Admin_dash,
                   'dash_details':dash_details,
                    'departments':departments}

        return render(request,'AD_department.html',content)

    else:
            return redirect('/')

# Designation ----------------------------

def admin_designation(request):
    if 'admin_id' in request.session:
        if request.session.has_key('admin_id'):
            admin_id = request.session['admin_id']

        else:
            return redirect('/')

        Admin_dash = LogRegister_Details.objects.get(id=admin_id)
        dash_details = BusinessRegister_Details.objects.get(log_id=Admin_dash)

        departments = DepartmentRegister_details.objects.filter(brd_id=dash_details,dept_active_status=1)
        designations = DesignationRegister_details.objects.filter(dept_id__in=departments)

        if request.POST:

            desidnation_obj = DesignationRegister_details()

            desidnation_obj.desig_name = request.POST['designation_name']
            desidnation_obj.desig_content = request.POST['designation_discription']
            desidnation_obj.desig_brd_id = dash_details
            desidnation_obj.dept_id =  DepartmentRegister_details.objects.get(id=int(request.POST['deparmentId']))
            desidnation_obj.desig_active_status = 1
            desidnation_obj.dashboard_id = request.POST['dashboardId']
            desidnation_obj.save()

            success = True
            success_text = 'New designation add successfully '
            designations = DesignationRegister_details.objects.filter(dept_id__in=departments)

            content = {'Admin_dash':Admin_dash,
                   'dash_details':dash_details,
                   'departments':departments,
                   'designations':designations,
                   'success':success,
                   'success_text':success_text
                   }

        else:

            content = {'Admin_dash':Admin_dash,
                   'dash_details':dash_details,
                   'departments':departments,
                   'designations':designations
                   }

        return render(request,'AD_designation.html',content)

    else:
            return redirect('/')

def admin_logout(request):
    request.session.pop('admin_id', None)
    return redirect('login_page')


# Librerias a importar
import streamlit as st
import pandas as pd
import lasio
import altair as alt
import matplotlib.pyplot as plt
from PIL import Image
from io import StringIO
#Nombre de la aplicaci贸n
st.title("Registro de pozos")
# Archivos a importar
archivo_las = lasio.read("LGAE-040.las")
df = archivo_las.df()
inicio = Image.open("Inicio.jpg")
# Men煤 de la aplicaci贸n
menu = st.sidebar.radio("Seleccione una opcion del aplicativo", ("馃彔 Inicio","馃搱 An谩lisis r谩pido", "馃搳 Evaluacion de zonas de pago"))
#Opciones de menu
if menu == "馃彔 Inicio":
    st.image(inicio)
    st.write("""
        # Descripci贸n del aplicativo
        El objetivo de este aplicativo es realizar un analisis breve de la informaci贸n del registro de pozo
        y poder visualizar la data y graficarla, ademas incluir un **algoritmo para el an谩lisis de zonas de pago**
        en base a las teorias y f贸rmulas bibliogr谩ficas

        Previamente se debe tener conocimientos generales para interpretar registros de pozos
        - La experiencia en campo
        - Conocimientos de programacion

        Dos aspectos que permitiran mejorar continuamente este aplicativo, pero el objetivo es dar  herramienta en este primer modulo

        """)

    st.write("""

        instrucciones

        1-

        2-

        3

        """)
if menu == "馃搱 An谩lisis r谩pido":
    cargar_data = st.selectbox("Escoja un m茅todo",("Data demo","Cargar archivo LAS"), index = 1)
    if cargar_data == "Data demo":
        st.header("Data Frame")
        st.write(df)
        st.header("Lectura del registro")
        profundidad_min = df.index.values[0]
        profundidad_max = df.index.values[-1]
        st.write("Este registro fue medido desde una profundidad de :", profundidad_min , "[ft]")
        st.write("Este registro fue medido hasta una profundidad de :", profundidad_max , "[ft]" )
        st.title("Limpieza y selecci贸n de datos ")
        selected_columns = ['NPHI','RHOB','GR']
        df_shorter = df[selected_columns]
        df_clean = df_shorter.dropna(subset=['NPHI','RHOB','GR'],axis=0, how='any')
        st.header("DataFrame sin valores nulos")
        st.write(df_clean)
        st.header("Grafico Data Frame Clean")
        f, ax = plt.subplots(nrows=1, ncols=3, figsize=(12,8) )
        logs = ['NPHI','RHOB','GR']
        colors = ['green','blue','red']
        for i,log,color in zip(range(3),logs,colors):
            ax[i].plot(df_clean[log], df_clean.index, color=color)
            ax[i].invert_yaxis()
        for i,log,color in zip(range(3),logs,colors):
            ax[i].set_xlabel(log)
            ax[0].set_ylabel("Depth(ft)")
            ax[i].grid()
        st.pyplot(f)

    if cargar_data == "Cargar archivo LAS":
        archivo_cargado = st.file_uploader("Cargar archivo LAS" , key=None)

        if archivo_cargado is None:
            st.write("Suba un archivo con extencion .las")

        if archivo_cargado is not None:
            bytes_data = archivo_cargado.read()
            str_io = StringIO(bytes_data.decode('Windows-1252'))
            las_file = lasio.read(str_io)
            df_upload = las_file.df()
            df_upload['DEPTH'] = df_upload.index
            st.header("Data Frame")
            st.write(df_upload)
            st.header("Lectura del registro")
            profundidad_min = df_upload.index.values[0]
            profundidad_max = df_upload.index.values[-1]
            st.write("Este registro fue medido desde una profundidad de :", profundidad_min , "[ft]")
            st.write("Este registro fue medido hasta una profundidad de :", profundidad_max , "[ft]" )
            st.header("Limpieza y selecci贸n de datos ")
            selected_columns = ['NPHI','RHOB','GR']
            df_shorter = df_upload[selected_columns]
            df_clean = df_shorter.dropna(subset=['NPHI','RHOB','GR'],axis=0, how='any')
            st.header("DataFrame sin valores nulos")
            st.write(df_clean)
            f, ax = plt.subplots(nrows=1, ncols=3, figsize=(12,8) )
            logs = ['NPHI','RHOB','GR']
            colors = ['green','blue','red']
            for i,log,color in zip(range(3),logs,colors):
                ax[i].plot(df_clean[log], df_clean.index, color=color)
                ax[i].invert_yaxis()
            for i,log,color in zip(range(3),logs,colors):
                ax[i].set_xlabel(log)
                ax[0].set_ylabel("Depth(ft)")
                ax[i].grid()
            st.pyplot(f)

if menu == "馃搳 Evaluacion de zonas de pago":
    st.header("Lectura del registro")
    profundidad_min = df.index.values[0]
    profundidad_max = df.index.values[-1]
    st.write("Este registro fue medido desde una profundidad de :", profundidad_min , "[ft]")
    st.write("Este registro fue medido hasta una profundidad de :", profundidad_max , "[ft]" )
    st.header("Limpieza y selecci贸n de datos ")
    selected_columns = ['NPHI','RHOB','GR']
    df_shorter = df[selected_columns]
    df_clean = df_shorter.dropna(subset=['NPHI','RHOB','GR'],axis=0, how='any')
    df_clean

    f, ax = plt.subplots(nrows=1, ncols=2, figsize=(12,8) )
    logs = ['NPHI','RHOB']
    colors = ['green','blue']
    for i,log,color in zip(range(2),logs,colors):
        ax[i].plot(df_clean[log], df_clean.index, color=color)
        ax[i].invert_yaxis()
    for i,log,color in zip(range(3),logs,colors):
        ax[i].set_xlabel(log)
        ax[0].set_ylabel("Depth(ft)")
        ax[i].grid()
    st.pyplot(f)

    st.title("Evaluaci贸n del Registro")

    limite_superior = st.slider("Seleccione el limte superior de la formacion a analizar", int(profundidad_min) , int(profundidad_max) )
    limite_inferior = st.slider("Seleccione el limte inferior de la formacion a analizar", int(profundidad_min) , int(profundidad_max)  )
    df_limites=df[limite_superior:limite_inferior]

    st.header("Data Frame de la zona a evaluar")

    st.write(df_limites)
    seleccionar_columnas = ['NPHI','DT','RHOB','GR','SP','RT']
    st.header("Registros necesarios para la evaluaci贸n")
    df_filtrado = df_limites[seleccionar_columnas ]
    st.write(df_filtrado)

    f_filtrado, ax = plt.subplots(nrows=1, ncols=6, figsize=(16,10))
    logs = ['NPHI','DT','RHOB','GR','SP','RT']
    colors = ['green','orange','blue','red','black','brown']
    for i,log,color in zip(range(6),logs,colors):
        ax[i].plot(df_filtrado[log], df_filtrado.index, color=color)
        ax[i].invert_yaxis()

    for i,log,color in zip(range(6),logs,colors):
        ax[i].set_xlabel(log)
        ax[0].set_ylabel("Depth(ft)")
        ax[i].grid()
    st.pyplot(f_filtrado)

    st.header("Parametros para evaluacion")
    st.header("Analisis del GR")
    valor_minimo = df_filtrado["GR"].min()
    valor_maximo = df_filtrado["GR"].max()
    st.write("El valor minimo del GR:",valor_minimo)
    st.write("El valor maximo del GR:",valor_maximo)

    #Calculos Indice de Gamma Ray
    df_filtrado["IGR"]=(df_filtrado.GR-valor_minimo)/(valor_maximo-valor_minimo)
    #Calculo Vsh
    df_filtrado["Vsh"]=0.33*(2**(2*df_filtrado.IGR)-1)
    #Calculo Sonico

    delta_matriz=55.5
    delta_fluido=189
    st.write("螖matriz:",delta_matriz)
    st.write("螖fluido:",delta_fluido)

    df_filtrado["PSonico"]=(df_filtrado.DT-delta_matriz)/(delta_fluido-delta_matriz)

    #Calculo densidad
    densidad_matriz=2.65
    densidad_fluido=1
    st.write("Densidad de la matriz:", densidad_matriz)
    st.write("Densidad del fluido:", densidad_fluido)

    df_filtrado["Pdensidad"]=(densidad_matriz-df_filtrado.RHOB)/(densidad_matriz-densidad_fluido)

    #Calculo porosidad total
    df_filtrado["PT"]=((df_filtrado.NPHI+df_filtrado.Pdensidad)/2)

    #Calculo de gradiente de temperatura
    Tf=200
    Pm=10370
    Ts=60
    st.write("Temperatura de la formacion:",Tf)
    st.write("Temperatura de superficie:",Tf)
    st.write("Presion del lodo:",Pm)

    df_filtrado["Gt"]=(Tf-Ts)*100/Pm

    #Calculo de temperatura de formacion
    df_filtrado["TF"]=(Ts+df_filtrado.Gt*(df_filtrado.index/100))

    #Calculo de la resistividad de lodo en formacion
    Rms=1.17
    Tm=60
    st.write("Resistividad del lodo de formacion:",Rms)
    st.write("Temperatura del lodo:",Pm)

    df_filtrado["Rmf"]=1.17*((Tm+6.77)/(df_filtrado.TF+6.77))

    #Calculos SP
    valor_minimosp = df_filtrado["SP"].min()
    st.write("El valor minimo del SP:",valor_minimosp)

    #Calculo de resistividad de agua equivalente
    df_filtrado["k"]=61.3+0.133*df_filtrado.TF

    df_filtrado["Rwe"]=df_filtrado.Rmf/(10**(valor_minimosp/-df_filtrado.k))

    #Calculo Rw
    Rw=0.11 #60 潞F
    st.write("Resistividad del agua:",Rw)
    df_filtrado['Rwf']=Rw*((Ts+6.77)/(df_filtrado.TF+6.77))

    st.title("Tabla para determinar conductividad")
    imagen1= Image.open("Conductividad.jpg")
    st.image(imagen1)

    #Calculo del factor de formacion
    df_filtrado['F']=1.13/(df_filtrado.PT**1.73)

    #Calculo de Ro #(Resitividad de formacion)
    df_filtrado['Ro']=df_filtrado.F*df_filtrado.Rwf

    #Calculo de Sw
    df_filtrado['Sw']=(df_filtrado.Ro/df_filtrado.RT)**0.5

    #Calculo de So
    df_filtrado['So']=1-df_filtrado.Sw

    #Calculo de Rwa
    df_filtrado['Rwa']=df_filtrado.RT/df_filtrado.F

    #Calculo de Rwa/Rwf
    df_filtrado['Rwa/Rwf']=df_filtrado.Rwa/df_filtrado.Rwf

    bins = (0.0, 3.0, 1000.0)
    grupos_nombres = ['No pago','Pago']
    df_filtrado['Zonas de pago'] = pd.cut(df_filtrado['Rwa/Rwf'], bins=bins, labels = grupos_nombres)
    df_filtrado['Zonas de pago'].unique()

    st.header("Data Frame Resultante")
    st.write(df_filtrado.astype('object'))

    #Grafico_Zonas de pago
    Grafico=alt.Chart(df_filtrado.astype('object')).mark_bar().encode(
        x="Zonas de pago",
        y="count()",
        tooltip=['Zonas de pago',"count()"]).interactive().properties(width=400, height = 300)
    st.altair_chart(Grafico)

    df_filtrado.reset_index(level=0 , inplace =True)

    st.write(df_filtrado.astype('object'))
    df_clean = df_filtrado.dropna(subset=['Rwa/Rwf'],axis=0, how='any')
    st.write(df_clean.astype('object'))
    Grafico2 = alt.Chart(df_clean.astype('object')).mark_line().encode(
        y="Rwa/Rwf",
        x= "DEPTH"

        ).properties(width=400, height = 300)

    st.altair_chart(Grafico2)


import traceback

from aiogram.types import Message, CallbackQuery
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher import FSMContext

from bot.create_bot import dp, bot
from databases.database import VisuallyDB, FileDb
from keyboard_stop_fsm import keyboard_stop_fsm
from image_handlers.fsm import FSMUniversalizer
from replacement_exif import replacement_exif_for_photo
from video_uniqueization import replacement_exif_for_video
from log.log import logger

# @dp.message_handler(Text(equals=['🌄 Уникализатор файлов']), commands=['unique'])
async def start_universalizer(message: Message):
    """Начало уникализации. Пользователю предоставляется выбор фото или видео"""
    if message.chat.type == 'private':
        visuall_db = VisuallyDB()
        message_bot = await message.answer('Отправьте фото без сжатия (файлом) или же видео (файлом)\n\n'
                                           '⚠ Обратите внимание на то, что в Telegram есть ограничение на размер файла'
                                           ' Файл не должен превышать более 20 МБ⚠\n\n'
                                           'Если хотите остановить операцию, то воспользуйтесь кнопкой ниже',
                                           reply_markup=keyboard_stop_fsm)
        await FSMUniversalizer.file.set()
        visuall_db.add_message_id(user_id=message.from_user.id, message_id=message_bot.message_id)

# @dp.message_handler(state=FSMUniversalizer.file, content_types=['any'])
async def universalizer_file(message: Message, state: FSMContext):
    print(message)
    if message.video:
        await state.finish()
        visual_db = VisuallyDB()
        file_db = FileDb()
        file_info = await bot.get_file(message.video.file_id)
        try:
            # delete message
            message_id = visual_db.get_message_id(user_id=message.from_user.id)
            await bot.delete_message(message.chat.id, message_id=message_id)
            visual_db.delete_all_by_user_id(message.from_user.id)

            message_universalizer = await message.answer('Начинаю уникализацию...\n\n'
                                                         '🟩◻◻◻◻◻◻◻◻◻')

            await message.video.download()
            file_path = file_info.file_path
            new_path = await replacement_exif_for_video(file_path, message_id=message_universalizer.message_id,
                                                        chat_id=message_universalizer.chat.id,
                                                        user_id=message.from_user.id)
            with open(new_path, 'rb') as file_obj:
                await bot.send_video(chat_id=message.chat.id, video=file_obj)

            await message_universalizer.edit_text('Готово!')
        except Exception:
            await message.answer('Возникла неизвестная ошибка. Попробуйте повторить уникализацию')
            traceback.print_exc()
            logger.warning(f'Во время выполнения отправки фото возникла ошибка \n{traceback.print_exc()}')
        finally:
            await state.finish()
            if file_db.file_exists(user_id=message.from_user.id):
                file_db.delete_all_by_user_id(user_id=message.from_user.id)

    elif message.document:
        # Уникализация фото файла
        if message.document.mime_type[:5] == 'image':
            visual_db = VisuallyDB()
            file_info = await bot.get_file(message.document.file_id)
            try:
                # delete message
                message_id = visual_db.get_message_id(user_id=message.from_user.id)
                await bot.delete_message(message.chat.id, message_id=message_id)
                visual_db.delete_all_by_user_id(message.from_user.id)

                message_universalizer = await message.answer('Начинаю уникализацию...\n\n'
                                                             '🟩◻◻◻◻◻◻◻◻◻')

                await message.document.download()
                file_path = file_info.file_path
                new_path = await replacement_exif_for_photo(file_path, message_id=message_universalizer.message_id,
                                                            chat_id=message_universalizer.chat.id)
                with open(new_path, 'rb') as file_obj:
                    await bot.send_document(chat_id=message.chat.id, document=file_obj)

                await message_universalizer.edit_text('Готово!')
            except Exception:
                await message.answer('Возникла неизвестная ошибка. Попробуйте повторить уникализацию')
                traceback.print_exc()
                logger.warning(f'Во время выполнения отправки фото возникла ошибка \n{traceback.print_exc()}')
            finally:
                await state.finish()

        # Уникализация видео файла
        elif message.document.mime_type[:5] == 'video':
            await state.finish()
            visual_db = VisuallyDB()
            file_db = FileDb()
            file_info = await bot.get_file(message.document.file_id)
            try:
                # delete message
                message_id = visual_db.get_message_id(user_id=message.from_user.id)
                await bot.delete_message(message.chat.id, message_id=message_id)
                visual_db.delete_all_by_user_id(message.from_user.id)

                message_universalizer = await message.answer('Начинаю уникализацию...\n\n'
                                                             '🟩◻◻◻◻◻◻◻◻◻')

                await message.document.download()
                file_path = file_info.file_path
                new_path = await replacement_exif_for_video(file_path, message_id=message_universalizer.message_id,
                                                            chat_id=message_universalizer.chat.id,
                                                            user_id=message.from_user.id)
                with open(new_path, 'rb') as file_obj:
                    await bot.send_video(chat_id=message.chat.id, video=file_obj)

                await message_universalizer.edit_text('Готово!')
            except Exception:
                await message.answer('Возникла неизвестная ошибка. Попробуйте повторить уникализацию')
                traceback.print_exc()
                logger.warning(f'Во время выполнения отправки фото возникла ошибка \n{traceback.print_exc()}')
            finally:
                await state.finish()
                if file_db.file_exists(user_id=message.from_user.id):
                    file_db.delete_all_by_user_id(user_id=message.from_user.id)
        else:
            await message.answer('Необходимо отправлять файл - фотографию или же видео')
    else:
        await message.answer('Ожидалось фото(файл) или же видео (файл)'
                             ' Попробуйте еще раз или приостановите операцию при помощи команды '
                             '"/stop"')

def register_image_handlers(dp: dp):
    dp.register_message_handler(start_universalizer, Text(equals=['🌄 Уникализатор файлов 📷', 'Уникализировать']))
    dp.register_message_handler(start_universalizer, commands=['universalizer', 'us'])
    dp.register_message_handler(universalizer_file, state=FSMUniversalizer.file, content_types=['any'])


import paths
import numpy as np
import emcee as em
import ccdproc as ccdp
import photutils.centroids as cen
import photutils.profiles as prof

from astropy.stats import SigmaClip
from scipy.optimize import minimize
from photutils.background import Background2D, MedianBackground, SExtractorBackground

image_path = paths.data / "processed_photometry" / "science" / "observations"
position_path = (
    paths.data / "processed_photometry" / "numbers" / "science_source_detection"
)
save_path = (
    paths.data / "processed_photometry" / "numbers" / "standard_star_calibration"
)

init_fwhm = 3.0

flat_type = "sky"
filter_names = ["B", "V", "R"]

def generate_profiles(image, init_centroid, delta, max_radii):
    x0, y0 = init_centroid
    x0, y0 = int(x0), int(y0)
    xmax, xmin = x0 + delta, x0 - delta
    ymax, ymin = y0 + delta, y0 - delta

    if xmax > image.shape[1]:
        print(f"Warning: xmax ({xmax}) > image.shape[1] ({image.shape[1]})")
        xmax = image.shape[1]
    if xmin < 0:
        print(f"Warning: xmin ({xmin}) < 0")
        xmin = 0
    if ymax > image.shape[0]:
        print(f"Warning: ymax ({ymax}) > image.shape[0] ({image.shape[0]})")
        ymax = image.shape[0]
    if ymin < 0:
        print(f"Warning: ymin ({ymin}) < 0")
        ymin = 0

    edge_radii = np.arange(max_radii)

    trimmed_image = ccdp.trim_image(
        image.copy()[ymin:ymax, xmin:xmax],
    )
    data = trimmed_image.data
    uncertainty = trimmed_image.uncertainty.array

    xc, yc = cen.centroid_2dg(data, uncertainty)
    profile = prof.RadialProfile(
        data, (xc, yc), edge_radii, error=uncertainty, mask=None, method="subpixel"
    )

    counts = profile.profile
    mirrored_counts = np.concatenate((counts[::-1], counts))

    uncertainty = profile.profile_error
    mirrored_uncertainty = np.concatenate((uncertainty[::-1], uncertainty))

    profile_radii = profile.radius
    mirrored_radii = np.concatenate((-profile_radii[::-1], profile_radii))

    return mirrored_radii, mirrored_counts, mirrored_uncertainty

def log_prior_gauss_fwhm(fwhm, fwhm_min=1.0, fwhm_max=10.0):
    if fwhm < fwhm_min or fwhm > fwhm_max:
        return -np.inf
    else:
        return 0.0

def llh_gauss(fwhm, radii, counts, uncertainties):
    std = fwhm / 2.355
    model_log_pdf = np.log(2 * np.pi) + 2 * np.log(std) + (radii**2 / (2 * std**2))
    model_counts = np.exp(-model_log_pdf)

    return -0.5 * np.sum(((counts - model_counts) / uncertainties) ** 2)

def log_likelihood_gauss_fwhm(fwhm, radii, counts, uncertainties):
    log_likelihood = 0
    for i in range(len(counts)):
        log_likelihood += llh_gauss(
            fwhm, radii, counts[i] / np.sum(counts[i]), uncertainties[i]
        )
    return log_likelihood

def log_posterior_fwhm(fwhm, radii, counts, uncertainties):
    log_prior = log_prior_gauss_fwhm(fwhm)
    if not np.isfinite(log_prior):
        return log_prior

    log_likelihood = log_likelihood_gauss_fwhm(fwhm, radii, counts, uncertainties)

    return log_prior + log_likelihood

for filter in filter_names:
    radii = []
    counts = []
    uncertainties = []

    image = ccdp.CCDData.read(image_path / (filter + "_" + flat_type + "_image.fits"))
    pos = np.load(position_path / (filter + "_pos.npy"))

    for i, (x, y) in enumerate(pos):
        mirrored_radii, mirrored_counts, mirrored_uncertainty = generate_profiles(
            image, (x, y), int(3 * init_fwhm) + 1, 3 * init_fwhm
        )

        radii.append(mirrored_radii)
        counts.append(mirrored_counts)
        uncertainties.append(mirrored_uncertainty)

    radii = np.array(radii)
    counts = np.array(counts)
    uncertainties = np.array(uncertainties)

    norm = np.sum(counts, axis=1)
    counts = counts / norm[:, None]
    uncertainties = uncertainties / norm[:, None]

    np.save(
        save_path / (filter + "_radii.npy"),
        radii,
    )
    np.save(
        save_path / (filter + "_counts.npy"),
        counts,
    )
    np.save(
        save_path / (filter + "_uncertainties.npy"),
        uncertainties,
    )

    nll = lambda *args: -log_likelihood_gauss_fwhm(*args)
    soln = minimize(nll, init_fwhm, args=(radii[0], counts, uncertainties))

    ndim = 1
    nwalkers = 32
    nsteps = 10000

    pos = soln.x + 1e-4 * np.random.randn(nwalkers, ndim)

    hdf5_path = save_path / f"{filter}_chains.h5"
    backend = em.backends.HDFBackend(hdf5_path)
    backend.reset(nwalkers, ndim)

    sampler = em.EnsembleSampler(
        nwalkers,
        ndim,
        log_posterior_fwhm,
        args=(radii[0], counts, uncertainties),
        backend=backend,
    )
    sampler.run_mcmc(pos, nsteps, progress=True)


from __future__ import absolute_import, division, print_function
from gltbx import wx_viewer
from gltbx.gl import *
from gltbx.glu import *
import gltbx.util
from scitbx.math import minimum_covering_sphere
from scitbx.array_family import flex
from math import log
import wx
from six.moves import range

def glbox(xyz1, xyz2):
  x1 = min(xyz1[0], xyz2[0])
  x2 = max(xyz1[0], xyz2[0])
  y1 = min(xyz1[1], xyz2[1])
  y2 = max(xyz1[1], xyz2[1])
  z1 = min(xyz1[2], xyz2[2])
  z2 = max(xyz1[2], xyz2[2])
  # top face (red)
  glBegin(GL_QUADS)
  glNormal3f(0, 0, 1)
  glVertex3f(x1, y1, z2)
  glVertex3f(x2, y1, z2)
  glVertex3f(x2, y2, z2)
  glVertex3f(x1, y2, z2)
  glEnd()
  # bottom face (blue)
  glBegin(GL_QUADS)
  glNormal3f(0, 0, -1)
  glVertex3f(x1, y1, z1)
  glVertex3f(x1, y2, z1)
  glVertex3f(x2, y2, z1)
  glVertex3f(x2, y1, z1)
  glEnd()
  # top side (y = y)
  glBegin(GL_QUADS)
  glNormal3f(0, -1, 0)
  glVertex3f(x1, y1, z1)
  glVertex3f(x2, y1, z1)
  glVertex3f(x2, y1, z2)
  glVertex3f(x1, y1, z2)
  glEnd()
  # bottom side (y = y + 1)
  glBegin(GL_QUADS)
  glNormal3f(0, 1, 0)
  glVertex3f(x1, y2, z2)
  glVertex3f(x2, y2, z2)
  glVertex3f(x2, y2, z1)
  glVertex3f(x1, y2, z1)
  glEnd()
  # left side (x' = x)
  glBegin(GL_QUADS)
  glNormal3f(-1, 0, 0)
  glVertex3f(x1, y2, z2)
  glVertex3f(x1, y2, z1)
  glVertex3f(x1, y1, z1)
  glVertex3f(x1, y1, z2)
  glEnd()
  # right side (x' = x+1)
  glBegin(GL_QUADS)
  glNormal3f(1, 0, 0)
  glVertex3f(x2, y1, z1)
  glVertex3f(x2, y2, z1)
  glVertex3f(x2, y2, z2)
  glVertex3f(x2, y1, z2)
  glEnd()

class pixel_viewer_3d(wx_viewer.wxGLWindow):
  def __init__(self, *args, **kwds):
    wx_viewer.wxGLWindow.__init__(self, *args, **kwds)
    self.SetSize((400,400))
    self.SetMinSize((400,400))
    self.flag_draw_boxes = False
    self.flag_log_scale = False
    self._img = None
    self.x_center = None
    self.y_center = None
    self.buffer_factor = 2.0
    self.scale_factor = 100
    self.rotation_center = (20,-20,0)
    self.minimum_covering_sphere = minimum_covering_sphere(
      flex.vec3_double([[0,0,0],[40,-40,40],[40,0,0],[0,-40,40]]))
    self.zoom_level = 16

  def InitGL(self):
    gltbx.util.handle_error()
    b = self.background_rgb
    glClearColor(b[0], b[1], b[2], 0.0)
    glDisable(GL_LIGHT0)
    glDisable(GL_LIGHTING)
    glDisable(GL_BLEND)
    glEnable(GL_LINE_SMOOTH)
    glEnable(GL_CULL_FACE)
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_POLYGON_SMOOTH)
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
    glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST)
    self.initialize_modelview()
    gltbx.util.handle_error()

  def process_pick_points(self):
    pass

  def set_image(self, img):
    self._img = img

  def recenter(self, x, y):
    self.x_center = x
    self.y_center = y
    self.Refresh()

  def DrawGL(self):
    if (None in [self._img, self.x_center, self.y_center]) : return
    if self.flag_draw_boxes :
      r, g, b = self._img.get_opengl_background()
      glClearColor(r, g, b, 0.)
      self._draw_boxes()
    else :
      glClearColor(0, 0, 0, 0.)
      self._draw_lines()

  def _draw_lines(self):
    values = self._img.get_intensities_in_box(
      x=self.x_center,
      y=self.y_center,
      boxsize=40,
      mag=1)#self.zoom_level)
    scale_factor = self.scale_factor
    glColor3f(1, 1, 1)
    w_range = [0.0,0.0]
    glGetFloatv(GL_LINE_WIDTH_RANGE, w_range)
    line_width = 0.1
    if (w_range[0] > 0.1):
      line_width = w_range[0]
    glLineWidth(line_width)
    for i, row in enumerate(values):
      y = -i
      glBegin(GL_LINES)
      for j, value in enumerate(row):
        if (j > 0):
          x = j
          val1 = row[j-1] / scale_factor
          val2 = value / scale_factor
          if (self.flag_log_scale):
            val1 = log(val1)
            val2 = log(val2)
          glVertex3f(x-1, y, val1)
          glVertex3f(x, y, val2)
      glEnd()
    for i in range(40):
      x = i
      glBegin(GL_LINES)
      for j, row in enumerate(values):
        if (j > 0):
          y = -j
          val1 = values[j-1][i] / scale_factor
          val2 = row[i] / scale_factor
          if (self.flag_log_scale):
            val1 = log(val1)
            val2 = log(val2)
          glVertex3f(x, y+1, val1)
          glVertex3f(x, y, val2)
      glEnd()

  def _draw_boxes(self):
    values = self._img.get_intensities_in_box(
      x=self.x_center,
      y=self.y_center,
      boxsize=40,
      mag=1)#self.zoom_level)
    wx_image = self._img.get_zoomed_bitmap(
      x=self.x_center,
      y=self.y_center,
      boxsize=40,
      mag=1)
    if (wx_image is None) : return
    glPolygonMode(GL_FRONT, GL_FILL)
    scale_factor = self.scale_factor
    for y_, row in enumerate(values):
      y = -y_
      for x, value in enumerate(row):
        z = value / scale_factor
        if (self.flag_log_scale):
          z = log(z)
        R = wx_image.GetRed(x,y_)
        G = wx_image.GetGreen(x,y_)
        B = wx_image.GetBlue(x,y_)
        glColor3f(R/255., G/255., B/255.)
        glbox((x,y,0),(x+1,y+1,z))

class pixel_viewer_3d_frame(wx.MiniFrame):
  def __init__(self, *args, **kwds):
    wx.MiniFrame.__init__(self, *args, **kwds)
    szr = wx.BoxSizer(wx.VERTICAL)
    self.SetSizer(szr)
    ctrls = wx.Panel(self, style=wx.RAISED_BORDER)
    szr.Add(ctrls, 0, wx.EXPAND)
    szr2 = wx.BoxSizer(wx.HORIZONTAL)
    ctrls.SetSizer(szr2)
    box1 = wx.CheckBox(ctrls, label="Wireframe rendering")
    box1.SetValue(True)
    self.Bind(wx.EVT_CHECKBOX, self.OnChangeRenderStyle, box1)
    szr2.Add(box1, 0, wx.ALL, 5)
    box2 = wx.CheckBox(ctrls, label="Log scaling")
    self.Bind(wx.EVT_CHECKBOX, self.OnChangeScale, box2)
    szr2.Add(box2, 0, wx.ALL, 5)
    szr2.Add(wx.StaticText(ctrls, label="Scale:"), 0, wx.ALL, 5)
    slider = wx.Slider(ctrls, size=(120,-1), style=wx.SL_AUTOTICKS)
    slider.SetMin(10)
    slider.SetMax(100)
    slider.SetValue(100)
    slider.SetTickFreq(10,1)
    self.Bind(wx.EVT_SLIDER, self.OnSetScale, slider)
    szr2.Add(slider, 0, wx.ALL, 5)
    szr2.Fit(ctrls)
    self._viewer = pixel_viewer_3d(parent=self)
    szr.Add(self._viewer, 1, wx.EXPAND)
    szr.Fit(self._viewer)
    self.Fit()

  def __getattr__(self, name):
    return getattr(self._viewer, name)

  def OnChangeRenderStyle(self, event):
    wires = event.GetEventObject().GetValue()
    self._viewer.flag_draw_boxes = not wires
    self._viewer.Refresh()

  def OnChangeScale(self, event):
    scale = event.GetEventObject().GetValue()
    self._viewer.flag_log_scale = scale
    self._viewer.Refresh()

  def OnSetScale(self, event):
    scale = event.GetEventObject().GetValue()
    self._viewer.scale_factor = scale
    self._viewer.Refresh()


import sys
sys.path.append('../')
import numpy as np
import pandas as pd
from data_source.data_source_split import testMaskFetch
import torch.nn.functional as F
from tqdm import tqdm
from utils.eval_method import iou
import argparse
parser = argparse.ArgumentParser(description='')
parser.add_argument('--model_name', default='', type=str, help='Model version')
args = parser.parse_args()

def iou_batch(y_true_in, y_pred_in):
    batch_size = y_true_in.shape[0]
    metric = []
    for batch in range(batch_size):
        value = iou(y_true_in[batch], y_pred_in[batch])
        metric.append(value)
    return metric

if __name__ == '__main__':
    save_predict = "predict/"
    model_name = "danet"
    c_p = {i:[] for i in range(1, 11)}
    c_t = {i:[] for i in range(1, 11)}
    c_ids = {i: [] for i in range(1, 11)}
    all_predicts = []
    all_truths = []
    for i in range(5):
        test_df = pd.read_csv('../dataset/data_split/test' + str(i) + '.csv')
        truths = testMaskFetch(test_df["id"].values)
        predicts = np.load(save_predict + model_name + str(i) + ".npy")
        all_predicts.append(predicts)
        all_truths.append(truths)
        for index, row in tqdm(test_df.iterrows()):
            c = row["coverage_class"]
            if (c == 0 or c == 1):
                c_p[1].append(predicts[index].reshape(1, 101, 101))
                c_t[1].append(truths[index].reshape(1, 101, 101))
                c_ids[1].append(row["id"])
            for i in range(2,11):
                if (c == i):
                    c_p[i].append(predicts[index].reshape(1, 101, 101))
                    c_t[i].append(truths[index].reshape(1, 101, 101))
                    c_ids[i].append(row["id"])
    for i in range(1, 11):
        p = np.concatenate(c_p[i])
        t = np.concatenate(c_t[i])

        np.save(model_name + str(i), iou_batch(t, np.int32(p > 0.5)))
        # np.save("class_" + str(i),c_ids[i])