import tkinter as tk
from tkinter.scrolledtext import ScrolledText
from ..core import Switcher, InlineTableList

class View(tk.Frame):

	def __init__(self, parent, logger, library):
		tk.Frame.__init__(self, parent)
		self.logger = logger
		self.library = library

		self.page_switcher = Switcher(self)
		self.page_switcher.pack(fill=tk.BOTH, expand=True)
		self.page_switcher.on_page_opened = self.on_page_opened
		
		self.footer_frame = tk.Frame(self)
		self.back_label_var = tk.StringVar()
		self.next_label_var = tk.StringVar()
		self.back_btn = tk.Button(master=self.footer_frame, textvariable=self.back_label_var, command=self.prev_page)
		self.next_btn = tk.Button(master=self.footer_frame, textvariable=self.next_label_var, command=self.next_page)
		self.back_btn.pack(side=tk.LEFT, padx=5, pady=5)
		self.next_btn.pack(side=tk.LEFT, padx=5, pady=5)
		self.footer_frame.pack(fill=tk.X)

		self.page_switcher.open_page(InputPage(self.page_switcher, self.logger, self.library))
	
	def on_transition_from(self, page):
		pass

	def on_page_opened(self, page):
		if type(page) is InputPage:
			self.back_label_var.set('Cancel')
		else:
			self.back_label_var.set('Back')

		if type(page) is ParsedDataPage:
			self.next_label_var.set('Commit')
			if page.has_errors():
				self.next_btn.pack_forget()
			else:
				self.next_btn.pack(side=tk.LEFT, padx=5, pady=5)
		else:
			self.next_label_var.set('Next')

	def prev_page(self):
		self.page_switcher.return_to_previous()
		if self.page_switcher.current_page is None:
			self.master.return_to_previous()

	def next_page(self):
		if self.page_switcher.current_page is not None:
			self.page_switcher.current_page.next_page()

class InputPage(tk.Frame):

	def __init__(self, parent, logger, library):
		tk.Frame.__init__(self, parent)
		self.logger = logger
		self.library = library
		
		side_frame = tk.Frame(self)
		side_frame.pack(fill=tk.Y, side=tk.LEFT)

		self.has_header_row_var = tk.IntVar()
		self.has_header_row_var.set(1)
		tk.Checkbutton(side_frame, text='Has Header Row', variable=self.has_header_row_var).pack(fill=tk.X)

		self.model_list = InlineTableList(side_frame, logger)
		self.model_list.height_in_rows = 3
		self.model_list.item_list = self.valid_import_models()
		self.model_list.comparator = self.compare_model_names
		self.model_list.to_column_values = lambda item: item.__name__
		self.model_list.add_column('Model')
		self.model_list.init_treeview()
		self.model_list.select_item_by_index(0)
		self.model_list.pack(fill=tk.X)

		self.col_delimiter_list = InlineTableList(side_frame, logger)
		self.col_delimiter_list.height_in_rows = 2
		self.col_delimiter_list.item_list = ['Tab (\\t)', 'Comma (,)']
		self.col_delimiter_vals = ['\t', ',']
		self.col_delimiter_list.add_column('Col Delimeter')
		self.col_delimiter_list.init_treeview()
		self.col_delimiter_list.select_item_by_index(0)
		self.col_delimiter_list.pack()

		self.input_field = ScrolledText(self, undo=True)
		self.input_field.pack(fill=tk.BOTH, expand=True)

	def on_transition_from(self, prev):
		if type(prev) is ParsedDataPage:
			self.has_header_row_var.set(prev.has_header_row)
			self.model_list.select_item_by_index(self.valid_import_models().index(prev.model_class))
			self.input_field.insert('1.0', prev.input_content)
			self.col_delimiter_list.select_item_by_index(self.col_delimiter_vals.index(prev.dialect.delimiter))

	def next_page(self):
		self.master.open_page(ParsedDataPage(self.master, self.logger, self.library))

	def valid_import_models(self):
		from src.library.model import LicenseModel, TrackModel, PlaylistModel
		return [
			LicenseModel,
			TrackModel,
			PlaylistModel,
		]
	
	def compare_model_names(self, sorting_column, a, b):
		from src.utility import compare_strings
		return compare_strings(a.__name__, b.__name__)

	def get_model_class(self):
		return self.model_list.get_selected_item()
	
	def get_import_text(self):
		return self.input_field.get('1.0', 'end')
	
	def has_header_row(self):
		return bool(self.has_header_row_var.get())

	def get_dialect(self):
		import csv
		class Dialect(csv.Dialect):
			quoting = csv.QUOTE_MINIMAL
			delimiter = ','
			quotechar = '"'
			lineterminator = '\r\n'
		dialect = Dialect()
		dialect.delimiter = self.col_delimiter_vals[self.col_delimiter_list.get_selected_index()]
		return dialect

class ParsedDataPage(tk.Frame):

	def __init__(self, parent, logger, library):
		tk.Frame.__init__(self, parent)
		self.logger = logger
		self.library = library

		self.model_class = None
		self.has_header_row = False
		self.input_content = ''
		self.preview_template = None
		self.dialect = None
		self.entries = []
		self.errors = []

		self.parsed_data_table = InlineTableList(self, logger)
		self.parsed_data_table.comparator = self.compare_entries
		self.parsed_data_table.to_column_values = self.make_column_values

		self.error_pane = tk.Frame(self)
		tk.Label(self.error_pane, text='Errors').pack()
		self.error_text = ScrolledText(self.error_pane, height=5)
		self.error_text.pack(fill=tk.BOTH, expand=True)
	
	def on_transition_from(self, prev):
		if type(prev) is InputPage:
			self.model_class = prev.get_model_class()
			self.has_header_row = prev.has_header_row()
			self.input_content = prev.get_import_text()
			self.dialect = prev.get_dialect()
			self.preview_template = self.model_class.preview_template()
			self.entries, self.errors = self.parse_data()
			
			self.parsed_data_table.item_list = self.entries
			if self.preview_template is not None:
				for column_name in self.preview_template.preview_column_names:
					self.parsed_data_table.add_column(column_name, sortable=True)
			self.parsed_data_table.init_treeview()
			self.parsed_data_table.pack(fill=tk.BOTH, expand=True)

		if len(self.errors) > 0:
			for error_txt in self.errors:
				self.error_text.delete('1.0', tk.END)
				self.error_text.insert(tk.END, error_txt + '\n')
			self.error_pane.pack(fill=tk.BOTH, expand=True)
		else:
			self.error_pane.pack_forget()

	def next_page(self):
		self.commit_entries()

		switcher = self.master
		import_data_view = switcher.master
		view_switcher = import_data_view.master
		view_switcher.return_to_previous()

	def parse_data(self, add_to_session=False):
		from src.library.model import parse_model_data
		return parse_model_data(
			self.logger, self.library,
			self.preview_template, self.has_header_row,
			self.input_content, self.dialect,
			add_to_session=add_to_session
		)

	def compare_entries(self, sorting_column, a, b):
		if self.preview_template is None or sorting_column is None:
			return 0
		col_idx = self.preview_template.preview_column_names.index(sorting_column)
		sorting_column = self.preview_template.preview_column_properties[col_idx]
		a_var = getattr(a, sorting_column)
		b_var = getattr(b, sorting_column)
		if a_var is None and b_var is None:
			return 0
		elif a_var is None:
			return 1
		elif b_var is None:
			return -1
		if a_var < b_var:
			return -1
		elif a_var > b_var:
			return 1
		else:
			return 0
	
	def make_column_values(self, item):
		if self.preview_template is not None:
			columns = []
			for property_name in self.preview_template.preview_column_properties:
				value = item.get_property(property_name)
				columns.append('' if value is None else value)
			return (*columns,)
		return ('',)
	
	def has_errors(self):
		return len(self.errors) > 0
	
	def commit_entries(self):
		self.parse_data(add_to_session=True)
		self.library.session.commit()
import tkinter as tk
from tkinter.scrolledtext import ScrolledText
from ..core import Switcher, InlineTableList

class View(tk.Frame):

	def __init__(self, parent, logger, library):
		tk.Frame.__init__(self, parent)
		self.logger = logger
		self.library = library

		self.page_switcher = Switcher(self)
		self.page_switcher.pack(fill=tk.BOTH, expand=True)
		self.page_switcher.on_page_opened = self.on_page_opened
		
		self.footer_frame = tk.Frame(self)
		self.back_label_var = tk.StringVar()
		self.next_label_var = tk.StringVar()
		self.back_btn = tk.Button(master=self.footer_frame, textvariable=self.back_label_var, command=self.prev_page)
		self.next_btn = tk.Button(master=self.footer_frame, textvariable=self.next_label_var, command=self.next_page)
		self.back_btn.pack(side=tk.LEFT, padx=5, pady=5)
		self.next_btn.pack(side=tk.LEFT, padx=5, pady=5)
		self.footer_frame.pack(fill=tk.X)

		self.page_switcher.open_page(InputPage(self.page_switcher, self.logger, self.library))
	
	def on_transition_from(self, page):
		pass

	def on_page_opened(self, page):
		if type(page) is InputPage:
			self.back_label_var.set('Cancel')
		else:
			self.back_label_var.set('Back')

		if type(page) is ParsedDataPage:
			self.next_label_var.set('Commit')
			if page.has_errors():
				self.next_btn.pack_forget()
			else:
				self.next_btn.pack(side=tk.LEFT, padx=5, pady=5)
		else:
			self.next_label_var.set('Next')

	def prev_page(self):
		self.page_switcher.return_to_previous()
		if self.page_switcher.current_page is None:
			self.master.return_to_previous()

	def next_page(self):
		if self.page_switcher.current_page is not None:
			self.page_switcher.current_page.next_page()

class InputPage(tk.Frame):

	def __init__(self, parent, logger, library):
		tk.Frame.__init__(self, parent)
		self.logger = logger
		self.library = library
		
		side_frame = tk.Frame(self)
		side_frame.pack(fill=tk.Y, side=tk.LEFT)

		self.has_header_row_var = tk.IntVar()
		self.has_header_row_var.set(1)
		tk.Checkbutton(side_frame, text='Has Header Row', variable=self.has_header_row_var).pack(fill=tk.X)

		self.model_list = InlineTableList(side_frame, logger)
		self.model_list.height_in_rows = 3
		self.model_list.item_list = self.valid_import_models()
		self.model_list.comparator = self.compare_model_names
		self.model_list.to_column_values = lambda item: item.__name__
		self.model_list.add_column('Model')
		self.model_list.init_treeview()
		self.model_list.select_item_by_index(0)
		self.model_list.pack(fill=tk.X)

		self.col_delimiter_list = InlineTableList(side_frame, logger)
		self.col_delimiter_list.height_in_rows = 2
		self.col_delimiter_list.item_list = ['Tab (\\t)', 'Comma (,)']
		self.col_delimiter_vals = ['\t', ',']
		self.col_delimiter_list.add_column('Col Delimeter')
		self.col_delimiter_list.init_treeview()
		self.col_delimiter_list.select_item_by_index(0)
		self.col_delimiter_list.pack()

		self.input_field = ScrolledText(self, undo=True)
		self.input_field.pack(fill=tk.BOTH, expand=True)

	def on_transition_from(self, prev):
		if type(prev) is ParsedDataPage:
			self.has_header_row_var.set(prev.has_header_row)
			self.model_list.select_item_by_index(self.valid_import_models().index(prev.model_class))
			self.input_field.insert('1.0', prev.input_content)
			self.col_delimiter_list.select_item_by_index(self.col_delimiter_vals.index(prev.dialect.delimiter))

	def next_page(self):
		self.master.open_page(ParsedDataPage(self.master, self.logger, self.library))

	def valid_import_models(self):
		from src.library.model import LicenseModel, TrackModel, PlaylistModel
		return [
			LicenseModel,
			TrackModel,
			PlaylistModel,
		]
	
	def compare_model_names(self, sorting_column, a, b):
		from src.utility import compare_strings
		return compare_strings(a.__name__, b.__name__)

	def get_model_class(self):
		return self.model_list.get_selected_item()
	
	def get_import_text(self):
		return self.input_field.get('1.0', 'end')
	
	def has_header_row(self):
		return bool(self.has_header_row_var.get())

	def get_dialect(self):
		import csv
		class Dialect(csv.Dialect):
			quoting = csv.QUOTE_MINIMAL
			delimiter = ','
			quotechar = '"'
			lineterminator = '\r\n'
		dialect = Dialect()
		dialect.delimiter = self.col_delimiter_vals[self.col_delimiter_list.get_selected_index()]
		return dialect

class ParsedDataPage(tk.Frame):

	def __init__(self, parent, logger, library):
		tk.Frame.__init__(self, parent)
		self.logger = logger
		self.library = library

		self.model_class = None
		self.has_header_row = False
		self.input_content = ''
		self.preview_template = None
		self.dialect = None
		self.entries = []
		self.errors = []

		self.parsed_data_table = InlineTableList(self, logger)
		self.parsed_data_table.comparator = self.compare_entries
		self.parsed_data_table.to_column_values = self.make_column_values

		self.error_pane = tk.Frame(self)
		tk.Label(self.error_pane, text='Errors').pack()
		self.error_text = ScrolledText(self.error_pane, height=5)
		self.error_text.pack(fill=tk.BOTH, expand=True)
	
	def on_transition_from(self, prev):
		if type(prev) is InputPage:
			self.model_class = prev.get_model_class()
			self.has_header_row = prev.has_header_row()
			self.input_content = prev.get_import_text()
			self.dialect = prev.get_dialect()
			self.preview_template = self.model_class.preview_template()
			self.entries, self.errors = self.parse_data()
			
			self.parsed_data_table.item_list = self.entries
			if self.preview_template is not None:
				for column_name in self.preview_template.preview_column_names:
					self.parsed_data_table.add_column(column_name, sortable=True)
			self.parsed_data_table.init_treeview()
			self.parsed_data_table.pack(fill=tk.BOTH, expand=True)

		if len(self.errors) > 0:
			for error_txt in self.errors:
				self.error_text.delete('1.0', tk.END)
				self.error_text.insert(tk.END, error_txt + '\n')
			self.error_pane.pack(fill=tk.BOTH, expand=True)
		else:
			self.error_pane.pack_forget()

	def next_page(self):
		self.commit_entries()

		switcher = self.master
		import_data_view = switcher.master
		view_switcher = import_data_view.master
		view_switcher.return_to_previous()

	def parse_data(self, add_to_session=False):
		from src.library.model import parse_model_data
		return parse_model_data(
			self.logger, self.library,
			self.preview_template, self.has_header_row,
			self.input_content, self.dialect,
			add_to_session=add_to_session
		)

	def compare_entries(self, sorting_column, a, b):
		if self.preview_template is None or sorting_column is None:
			return 0
		col_idx = self.preview_template.preview_column_names.index(sorting_column)
		sorting_column = self.preview_template.preview_column_properties[col_idx]
		a_var = getattr(a, sorting_column)
		b_var = getattr(b, sorting_column)
		if a_var is None and b_var is None:
			return 0
		elif a_var is None:
			return 1
		elif b_var is None:
			return -1
		if a_var < b_var:
			return -1
		elif a_var > b_var:
			return 1
		else:
			return 0
	
	def make_column_values(self, item):
		if self.preview_template is not None:
			columns = []
			for property_name in self.preview_template.preview_column_properties:
				value = item.get_property(property_name)
				columns.append('' if value is None else value)
			return (*columns,)
		return ('',)
	
	def has_errors(self):
		return len(self.errors) > 0
	
	def commit_entries(self):
		self.parse_data(add_to_session=True)
		self.library.session.commit()