# Author: Rubinigg Michael
# Contributor: Rubinigg Michael
# Abstract: Unpivots (melt) a CSV file
# Version 1.0
# Release date: 2024-10-25
# Place: Graz, Austria, EU
# Company: dr Mag. rer. nat. Michael Rubinigg
# Programming Language: Python 3.11
# Rights:  Creative Commons Attribution 4.0 (CC-BY)

import tkinter as tk
from tkinter import filedialog, simpledialog, ttk
import pandas as pd
import os

def melt_file(selected_file, output_directory, output_filename, column_id_var, decimal_input, separator_input):

    output_path = os.path.join(output_directory, output_filename + '.csv')

    # create output directory if it doesn't exist
    if not os.path.exists(output_directory):
        os.makedirs(output_directory)

    input_file = pd.read_csv(selected_file, sep=separator_input, decimal=decimal_input)

    id_var = input_file.columns[:column_id_var]

    output_file = input_file.melt(id_vars=id_var, var_name='variable', value_name='value')

    # Set the first column as the index (to keep it separate)
    output_file.sort_values(by=input_file.columns[0], ascending=True, inplace=True)

    output_file.fillna('NULL', inplace=True)

    output_file.to_csv(output_path, sep=separator_input, na_rep='NULL', index=False, decimal='.')

def select_file(title_text):
    file_path = filedialog.askopenfilename(
        title = title_text,
        filetypes= [('CSV files', '*.csv')],
    )
    return file_path

def select_directory(title_text):
    output_directory = filedialog.askdirectory(
        title = title_text
    )
    return output_directory

def get_text(title_text, prompt_text):
    output_text = simpledialog.askstring(
        title = title_text,
        prompt = prompt_text
    )
    return output_text

def get_integer(title_text, prompt_text):
    output_integer = simpledialog.askinteger(
        title = title_text,
        prompt = prompt_text
    )
    return output_integer

def get_output_filename(title_text, prompt_text):
    output_filename = simpledialog.askstring(
        title = title_text,
        prompt = prompt_text
    )
    return output_filename

def get_listvalue(options, title_text):

    # Create a main window
    root = tk.Tk()
    root.attributes('-topmost', True)
    root.eval('tk::PlaceWindow . center')

    # create label
    label = ttk.Label(text=title_text)
    label.pack(padx=5, pady=5)

    # Create a StringVar to hold the selected value
    selected_value = tk.StringVar()

    # Create a combobox
    combobox = ttk.Combobox(root, textvariable=selected_value)
    combobox['values'] = options
    combobox.current(0)  # Set the default selection to the first item
    combobox.pack(padx=10, pady=10)

    # Function to handle the button click
    def on_submit():
        root.destroy()  # Close the window

    # Create a submit button
    submit_button = tk.Button(root, text="Submit", command=on_submit)
    submit_button.pack(padx=10, pady=10)

    # Run the application
    root.mainloop()

    # Return the selected value
    return selected_value.get()


def main ():

    # select source file
    selected_file = select_file('Select a source file for the data')

    # select output directory
    selected_output_directory = select_directory('Select Output Directory')

    # Get user-defined output filename
    output_filename = get_text('Name of the output file', "Enter the output filename (excluding extension):")

    # Get number of identifier variables to be maintained
    column_id_var = get_integer('Number of columns', "Enter the number of columns to be used as identifier variables:")

    # get the format of the decimal point
    decimal_input = get_listvalue([',', '.'], 'Select the decimal in the input file')

    # get the column delimiter character
    separator_input = get_listvalue([',', ';'], 'Select the column separator in the input file')

    #melt file
    melt_file(selected_file, selected_output_directory, output_filename, column_id_var,decimal_input, separator_input)

if __name__ == '__main__':
    main()
