#!/usr/bin/env python3

import sqlite3
from sqlite3 import Error
import tkinter as tk
from tkinter import ttk
from scapy.all import *
from datetime import datetime

import os
import threading

# NOTE: look into PCAP for pcap file
PCAP_DIRECTORY = "PCAP"

# NOTE: global variables for threading
files = []
pcap_files=[]
pcap_filename = ''

# NOTE: global variables for result
num_of_packet = 0
list_of_scanned_port = []
num_of_scanned_port = 0
pcap_process_status = 'start'

# NOTE: initial get all files in the directory
files = os.listdir(PCAP_DIRECTORY)

# NOTE: Filter files with '.pcap' extension
pcap_files = [file for file in files if file.endswith('.pcap')]

def handle_pcap_file_select_update(event):
    # NOTE: make analyse button when pcap file selected
    analysebtn.config(state=tk.ACTIVE)

def create_connection(db_file):
    conn = None
    try:
        conn = sqlite3.connect(db_file)
    except Error as e:
        print(e)
    return conn

def select_all_pcaprecords(conn):
    cur = conn.cursor()
    cur.execute("SELECT * FROM pcap_records")

    rows = cur.fetchall()
    return rows

def open_popup(text_display):
    top = tk.Toplevel(mainwindow)
    top.geometry("550x250")
    top.title("Analysis Results!")
    popup_text = tk.Text(top, height=10, width=65,font=('Consolas',10))
    popup_text.grid(row=0,column=0,padx=5,pady=5,sticky=tk.W)
    popup_text.insert(tk.END,text_display)

def callback(event):
    filepath = "./outputfiles/"
    # get the index of the mouse click
    index = event.widget.index("@%s,%s" % (event.x, event.y))

    # get the indices of all "adj" tags
    tag_indices = list(event.widget.tag_ranges('tag'))

    # iterate them pairwise (start and end index)
    for start, end in zip(tag_indices[0::2], tag_indices[1::2]):
        # check if the tag matches the mouse click index
        if event.widget.compare(start, '<=', index) and event.widget.compare(index, '<', end):
            # return string between tag start and end
            filename = filepath + event.widget.get(start, end)
            print(filename)
            file1 = open(filename,'r')
            lines = file1.readlines()
            d = ""
            for line in lines:
                d += line.strip() + "\n"

            open_popup(d)

def find_num_of_packet(pcap_filename):
    global PCAP_DIRECTORY,num_of_packet

    # Provide the path to your PCAP file
    pcap_file = f'{PCAP_DIRECTORY}/{pcap_filename}'

    # Read the PCAP file
    packets = rdpcap(pcap_file)

    # return 'num_packets'
    num_of_packet = len(packets)
    pass

def count_scanned_port(list_of_scanned_port):
    return len(list_of_scanned_port)

def find_scanned_port(pcap_filename):
    global list_of_scanned_port
    global num_of_scanned_port
    global PCAP_DIRECTORY

    pcap_file = f'{PCAP_DIRECTORY}/{pcap_filename}'

    # Read the PCAP file
    packets = rdpcap(pcap_file)

    # Create an empty set to store unique destination ports
    scanned_ports = set()

    for packet in packets:
        # Check if it's a TCP packet with destination port information
        if TCP in packet and packet[TCP].dport not in scanned_ports:
            scanned_ports.add(packet[TCP].dport)

    list_of_scanned_port = sorted(scanned_ports)
    num_of_scanned_port = count_scanned_port(scanned_ports)

    pass

def display_to_text(in_data):
    displaytext.tag_config("tag",foreground="blue")
    displaytext.tag_bind("tag","<Button-1>", callback)
    displaytext.insert(tk.END, 'ID' + "\t" + "PCAP Filename" + "              " + "Date" + "\t\t\t\t" + "Time" + "\t" + "Output File\n")
    displaytext.insert(tk.END, '==' + "\t" + "==========================" + "\t" + "========" + "\t" + "====" + "\t" + "===========\n")
    for row in in_data:
        displaytext.insert(tk.END, str(row[0]) + "\t" + row[1] + "   \t\t\t" + row[2] + "\t" + row[3] + " " + row[4] + "\t")
        displaytext.insert(tk.END,row[4],"tag")
        displaytext.insert(tk.END,"\n")


def clear_text():
    pcap_file_select_cb.set(DEFAULT_COMBOBOX_TEXT)
    analysetext.delete(1.0, tk.END)

    clearbtn.config(state=tk.DISABLED)
    analysebtn.config(state=tk.DISABLED)
    storebtn.config(state=tk.DISABLED)

def store_to_db(conn):
    global pcap_filename

    print(pcap_filename)

    try:
      current_date = get_current_date()
      current_time = get_current_time()
      output_filename = current_date+current_time+'.txt'

      cursor = conn.cursor()

      # cursor.execute("INSERT INTO pcap_records (pcafilename) VALUES (?)", (name))
      cursor.execute('INSERT INTO pcap_records (pcapfilename, date, time, outputfilename) VALUES (?, ?, ?, ?)', (pcap_filename,current_date, current_time, output_filename))

      # Commit the changes and close the connection
      conn.commit()
      print('save to db done')

    except:
      print('error found during saving to db')

# TODO: relocate me
thread1 = 0
thread2 = 0

def update_result():
    global pcap_filename
    global thread1,  thread2
    global num_of_scanned_port, list_of_scanned_port, num_of_packet

    thread1.join()
    thread2.join()

    clear_text()

    analysetext.insert(tk.END, f"-- ANALYSIS RESULT --\n")

    analysetext.insert(tk.END, f"File analyzed: {pcap_filename}\n")

    # # NOTES: count number of packets
    analysetext.insert(tk.END, f"The number of packets : {num_of_packet}\n")

    # # NOTES: find the ports scanned
    analysetext.insert(tk.END, f"Scanned port : {list_of_scanned_port}\n")

    # NOTES: find_num_of_port_scanned
    analysetext.insert(tk.END, f"Scanned port : {num_of_scanned_port}\n")

    analysetext.insert(tk.END, f"-- ANALYSIS END --\n")




def analyse_to_text():
    global num_of_packet
    global thread1, thread2
    global pcap_filename

    pcap_filename = pcap_file_select_cb.get()

    # NOTE: seperate thread for process analysis of scanned port and number of packet
    thread1 = threading.Thread(target=find_scanned_port, args=(pcap_filename,))
    thread2 = threading.Thread(target=find_num_of_packet, args=(pcap_filename,))

    # NOTE: start thread
    thread1.start()
    thread2.start()

    # NOTE: prepare textbox for output
    analysetext.tag_config("tag",foreground="blue")
    analysetext.tag_bind("tag","<Button-1>", callback)

    # NOTE: show processing file and wait for finish
    analysetext.insert(tk.END, f"processing file\n")

    update_result()

    clearbtn.config(state=tk.ACTIVE)
    storebtn.config(state=tk.ACTIVE)


def get_current_date():
    now = datetime.now()
    return now.strftime('%Y%m%d')

def get_current_time():
    now = datetime.now()
    return now.strftime('%H%M%S')


def analysispcap():
    pcapFile = getfiletextbox.get()
    pcap = rdpcap(pcapFile)
    numofpackets = len(pcap)
    resultstextbox.insert(tk.END,numofpackets)

def saveresult():
    pcapFile = getfiletextbox.get()
    analysis_date = get_current_date()
    analysis_time = get_current_time()
    analysis_output = resultstextbox.get("1.0","end-1c")
    output_filename = analysis_date + analysis_time + '.txt'
    print(pcapFile)
    print(analysis_date)
    print(analysis_time)
    print(analysis_output)
    print(output_filename)

def refresh_pcap_file_list(Noneevent):
    global files
    global pcap_files

    files = os.listdir(directory)
    pcap_files = [file for file in files if file.endswith('.pcap')]
# ====================== Main Start Here =====================================================

database = r"saspdemo.db"
conn = create_connection(database)
rows = select_all_pcaprecords(conn)
data = []

for row in rows:
    data.append([row[0], row[1], row[2], row[3], row[4]])

mainwindow = tk.Tk()
mainwindow.geometry("1620x600")
mainwindow.title("SASP Part B Assignment AY2223 - PCAP Analysis By Chan Tai Man")

tabControl = ttk.Notebook(mainwindow)

tab1 = ttk.Frame(tabControl)
tab2 = ttk.Frame(tabControl)

tabControl.add(tab1, text ='Network Traffic Analysis')
tabControl.add(tab2, text ='History')
tabControl.pack(expand = 1, fill ="both")

# # =================== tab 1 GUI Layout ========================================================

# # Options

# NOTE: this is combobox for pcap file list
DEFAULT_COMBOBOX_TEXT = 'Select a pcap file'
pcap_file_select_cb = ttk.Combobox(tab1, width=30, textvariable=tk.StringVar())
pcap_file_select_cb.set(DEFAULT_COMBOBOX_TEXT)
pcap_file_select_cb.grid(row=0,column=0, padx=5,pady=10,sticky=tk.W)
pcap_file_select_cb.bind('<<ComboboxSelected>>', handle_pcap_file_select_update)

pcap_file_select_cb['values'] = pcap_files
pcap_file_select_cb['state'] = 'readonly'

# NOTE: this is "REFRESH" button
refreshbtn = tk.Button(tab1, text="REFRESH", fg='blue', width=10, command=lambda:refresh_pcap_file_list(None))
refreshbtn.grid(row=0,column=0, padx=500,pady=10,sticky=tk.W)

# NOTE: this is "ANALYSE" button
analysebtn = tk.Button(tab1, text="ANALYSE", fg='blue', width=10, command=lambda:analyse_to_text())
analysebtn.grid(row=0,column=0, padx=700,pady=10,sticky=tk.W)
analysebtn.config(state=tk.DISABLED)

# NOTE: this is "CLEAR" button
clearbtn = tk.Button(tab1, text="CLEAR", fg='blue', width=10, command=lambda:clear_text())
clearbtn.grid(row=0,column=0, padx=900,pady=10,sticky=tk.W)
clearbtn.config(state=tk.DISABLED)

# NOTE: store to database
# NOTE: Store all the information
# NOTE: (e.g. date and time, PCAP filename, and the results of items)
# NOTE: related to analysing PCAP files in the SQLite database.
storebtn = tk.Button(tab1, text="STORE", fg='blue', width=10, command=lambda:store_to_db(conn))
storebtn.grid(row=0,column=0, padx=1100,pady=10,sticky=tk.W)
storebtn.config(state=tk.DISABLED)

# NOTE: result window
analysetext = tk.Text(tab1,height=10, width=100,font=('Consolas',10))
analysetext.grid(row=2,column=0,padx=5,pady=20,sticky=tk.W)

# # =================== tab 2 GUI Layout ========================================================

displaybtn = tk.Button(tab2, text="DISPLAY", fg='blue', width=20, command=lambda:display_to_text(data))
displaybtn.grid(row=0,column=0, padx=5,pady=10,sticky=tk.W)

displaytext = tk.Text(tab2,height=10, width=100,font=('Consolas',10))
displaytext.grid(row=2,column=0,padx=5,pady=5,sticky=tk.W)

# TODO: resume me
mainwindow.mainloop()

print('program ended')
