#!/usr/bin/env python3
import ast
import json
from tkinter import *
from tkinter import ttk
from tkinter import messagebox

from GestioneInformazione import search_engine


class UserInterface:
    # INITIALIZE ALL THE COMPONENTS FOR EVERY VIEW
    def __init__(self, window):
        self.window = window
        self.notebook = ttk.Notebook(self.window)
        self.tree_frame = Frame(self.notebook)
        self.json_frame = Frame(self.notebook)
        self.tree = ttk.Treeview(self.tree_frame)
        self.results_label = Label()
        self.scrollbar = Scrollbar(self.tree_frame, orient='vertical', command=self.tree.yview)
        self.json_text = Text(self.json_frame, height=44, width=194)
        self.back_button = Button(self.window, text="Back", font="none 14 bold", command=self.go_back_handler)
        self.phrase_entry = Entry(self.window, width=22)
        self.table_entry = Entry(self.window, width=22)
        self.year_entry = Entry(self.window, width=22)
        self.text_field_cbb = ttk.Combobox(self.window, values=['authors', 'year', 'title'])
        self.venue_entry = Entry(self.window, width=22)
        self.venue_field_cbb = ttk.Combobox(self.window, values=['title', 'publisher', 'journal'])
        self.number_scale = Scale(from_=0, to=200, resolution=10, orient=HORIZONTAL, length=200)
        self.ranking_cbb = ttk.Combobox(self.window, values=['boolean', 'bm25'])
        self.ranking_cbb.set('boolean')
        self.required_label = Label(self.window, text="Required Fields", font="none 18 bold")
        self.phrase_label = Label(self.window, text="Phrase")
        self.table_label = Label(self.window, text="Table")
        self.optional_label = Label(self.window, text="Optional Fields", font="none 18")
        self.year_table = Label(self.window, text="Year")
        self.text_field_label = Label(self.window, text="Text Field")
        self.venue_label = Label(self.window, text="Venue")
        self.venue_field_label = Label(self.window, text="Venue field")
        self.number_label = Label(self.window, text="Number of Records\n(Set 0 to see all records)", justify=LEFT)
        self.ranking_label = Label(self.window, text="Ranking Type")
        self.search_button = Button(self.window, text="SEARCH", font="none 14 bold", command=self.launch_query)

    # GO BACK HANDLER, REMOVE ALL THE COMPONENTS OF THE VIEW AND display_search
    def go_back_handler(self):
        self.notebook.grid_forget()
        self.tree_frame.grid_forget()
        self.json_frame.grid_forget()
        self.tree.grid_forget()
        self.results_label.grid_forget()
        self.scrollbar.grid_forget()
        self.json_text.grid_forget()
        self.back_button.grid_forget()

        self.display_search()

    # CALL THE SEARCH ENGINE PASSING THE PARAMETERS
    def launch_query(self):
        phrase = re.sub(' +', ' ', str(self.phrase_entry.get()))
        phrase = phrase.strip()
        table = re.sub(' +', ' ', str(self.table_entry.get()))
        table = table.strip()
        if not phrase or not table:
            messagebox.showerror(title="Error", message="Both \"Phrase\" and \"Table\" must be filled.")
            return

        if table not in ["articles", "book", "incollection", "inproceedings", "mastersthesis", "phdthesis",
                         "proceedings"]:
            messagebox.showerror(title="Error", message="Table not valid.")

        year = self.year_entry.get()
        if year:
            try:
                year = int(year)
            except ValueError:
                messagebox.showerror(title="Error", message="Year value must be int.")
                return
        else:
            year = None
        text_field = self.text_field_cbb.get()
        if text_field == "":
            text_field = None
        venue = re.sub(' +', ' ', str(self.venue_entry.get()))
        venue = venue.strip()
        if venue == "":
            venue = None
        venue_field = self.venue_field_cbb.get()
        if venue_field == "":
            venue_field = None
        ranking = self.ranking_cbb.get()
        if ranking == "":
            ranking = None
        # set 0 = all results
        number = self.number_scale.get()
        if number == 0:
            number = None

        string_label = "Phrase: " + phrase + "        Table: " + table

        SE = search_engine.searchEng(phrase,
                                     table,
                                     year=year,
                                     text_field=text_field,
                                     venue=venue,
                                     venue_field=venue_field,
                                     ranking=ranking,
                                     num=number)

        records = SE.interrogation()

        if records is not None:
            self.clear_all()
            self.print_view(records, string_label)

    # PRINT RESULTS FROM THE QUERY, TREEVIEW AND JSON
    def print_view(self, records, string_label):
        if self.tree.get_children():
            self.tree.destroy()
            self.tree = ttk.Treeview(self.tree_frame)
            self.json_text.destroy()
            self.json_text = Text(self.json_frame, height=44, width=194)

        self.notebook.add(self.tree_frame, text="TreeView")
        self.notebook.add(self.json_frame, text="JSON")
        self.tree.heading('#0', text='Title')
        self.tree.column('#0', stretch=YES, width=1350)
        self.tree.configure(yscrollcommand=self.scrollbar.set)
        if records == -1 or len(records) == 0:
            messagebox.showwarning(title="Warning", message="No records found.")
            self.go_back_handler()
            return
        num_results = string_label + "\nNumber of records: " + str(len(records))
        self.results_label = Label(self.window, text=num_results)

        i = 0
        for rec in records:
            try:
                if 'title' in rec.keys():
                    self.tree.insert('', 'end', iid=i, text=rec['title'])
                    if 'authors' in rec.keys():
                        self.tree.insert(i, 'end', text="Authors: " + rec['authors'])
                    if 'year' in rec.keys():
                        self.tree.insert(i, 'end', text="Year: " + rec['year'])
                    if 'url' in rec.keys():
                        self.tree.insert(i, 'end', text="URL: " + rec['url'])
                elif 'i_title' in rec.keys():
                    self.tree.insert('', 'end', iid=i, text=rec['i_title'])
                    if 'i_authors' in rec.keys():
                        self.tree.insert(i, 'end', text="Authors: " + rec['i_authors'])
                    if 'i_year' in rec.keys():
                        self.tree.insert(i, 'end', text="Year: " + rec['i_year'])
                    if 'i_url' in rec.keys():
                        self.tree.insert(i, 'end', text="URL: " + rec['i_url'])
                    if 'p_title' in rec.keys():
                        self.tree.insert(i, 'end', text="Proceeding Title: " + rec['p_title'])
                    if 'p_publisher' in rec.keys():
                        self.tree.insert(i, 'end', text="Proceeding Publisher: " + rec['p_publisher'])
                    if 'p_year' in rec.keys():
                        self.tree.insert(i, 'end', text="Proceeding Year: " + rec['p_year'])
                    if 'p_url' in rec.keys():
                        self.tree.insert(i, 'end', text="Proceeding URL: " + rec['p_url'])

                self.tree.item(i, open=True)

                i += 1
            except Exception:
                print("[Error printing following record]   " + str(rec))

        self.json_text.insert('end', json.dumps(ast.literal_eval(str(records)), indent=4))

        self.results_label.grid(row=0, column=0, sticky=W, padx=10, pady=5)
        self.back_button.grid(row=1, column=0, ipady=5, ipadx=5, pady=10)
        self.json_text.grid(row=2, column=0, sticky=NSEW)
        self.notebook.grid(row=2, column=0, sticky=NSEW)
        self.tree.config(height=28)
        self.tree.grid(row=2, column=0, sticky=NS)
        self.scrollbar.grid(row=2, column=1, sticky=NS)

    # CLEAR THE WHOLE WINDOW IN ORDER TO REUSE IT
    def clear_all(self):
        self.phrase_entry.grid_forget()
        self.table_entry.grid_forget()
        self.year_entry.grid_forget()
        self.text_field_cbb.grid_forget()
        self.venue_entry.grid_forget()
        self.venue_field_cbb.grid_forget()
        self.number_scale.grid_forget()
        self.ranking_cbb.grid_forget()
        self.required_label.grid_forget()
        self.phrase_label.grid_forget()
        self.table_label.grid_forget()
        self.optional_label.grid_forget()
        self.year_table.grid_forget()
        self.text_field_label.grid_forget()
        self.venue_label.grid_forget()
        self.venue_field_label.grid_forget()
        self.number_label.grid_forget()
        self.ranking_label.grid_forget()
        self.search_button.grid_forget()

    # DISPLAY ALL THE COMPONENTS INSIDE THE WINDOW
    def display_search(self):
        # REQUIRED
        self.required_label.grid(row=0, columnspan=2, pady=10)

        self.phrase_label.grid(row=1, sticky=W, padx=5)
        self.phrase_entry.grid(row=1, column=1, pady=5, padx=10)

        self.table_label.grid(row=2, sticky=W, padx=5)
        self.table_entry.grid(row=2, column=1, pady=5)

        # OPTIONAL
        self.optional_label.grid(row=3, columnspan=2, pady=10)

        self.year_table.grid(row=4, sticky=W, padx=5)
        self.year_entry.grid(row=4, column=1, pady=5)

        self.text_field_label.grid(row=5, sticky=W, padx=5)
        self.text_field_cbb.grid(row=5, column=1, pady=5)

        self.venue_label.grid(row=6, sticky=W, padx=5)
        self.venue_entry.grid(row=6, column=1, pady=5)

        self.venue_field_label.grid(row=7, sticky=W, padx=5)
        self.venue_field_cbb.grid(row=7, column=1, pady=5)

        self.number_label.grid(row=8, sticky=W, padx=5)
        self.number_scale.grid(row=8, column=1, ipady=5)

        self.ranking_label.grid(row=9, sticky=W, padx=5)
        self.ranking_cbb.grid(row=9, column=1)

        self.search_button.grid(row=10, column=0, columnspan=2, ipady=5, ipadx=5, pady=20)

        self.window.mainloop()


def main():
    window = Tk()
    window.title("GAvI Search Engine")
    UI = UserInterface(window)
    UI.display_search()


if __name__ == '__main__':
    main()
