from getpass import getpass

class Server_Node:
	def __init__(self, addr, node_id=0):
		self.node_id 	= node_id 			# Server node ID, defaults to '0'
		self.addr 		= addr 				# Ip address that the node resides on
		self.childNodes	= []				# List of child nodes that belong to this node

	def view_node(self):
		print('Node ID:   ' + str(self.node_id))
		print('IP addr:   ' + self.addr)

class Node:
	def __init__(self, node_id, parent_node, addr, username='', passwd=''):
		self.node_id 		= node_id
		parent_node.childNodes.append(self)		# Append this node to another node's childNodes list
		self.parent_node 	= parent_node 		# Store parent node
		self.addr 			= addr
		self.username 		= username 			# Default username from creds{}
		self.passwd 		= passwd 			# Corresponding default password from creds{}
		self.childNodes		= []
		self.creds 			= {username:passwd}

	# View node attributes
	def view_node(self):
		print('╭─────────────────╮')
		print('│ n' + str(self.node_id).ljust(15) + '│')
		print('│' + self.addr.center(17) + '│')
		print('╰───┬─────────────╯')
		print('    │ Attributes:')
		print('    ╰─┬─Node ID:         ' + str(self.node_id))
		print('      ├─Parent ID:       ' + str(self.parent_node.node_id))
		print('      ├─IP address:      ' + self.addr)
		print('      ├─Default UN:      ' + self.username)
		print('      ├─Child nodes:     ')
		for child in self.childNodes:
			if len(self.childNodes) == 0:
				print('      │    ╰─n/a')
				break
			if child == self.childNodes[-1]:
				print('      │    ╰─n' + str(child.node_id) + ' - [' + child.addr + ']')
			else:
				print('      │    ├─n' + str(child.node_id) + ' - [' + child.addr + ']')

		print('      ╰─List of creds:')
		for un, pw in self.creds.items():
			if un == list(self.creds.keys())[-1]:
				print('           ╰─' + un)
			else:
				print('           ├─' + un)

	# Modify values of node
	def edit_node(self, pnodes):

		# Print a 'banner' for the node we're working on
		print('╭─────────────────╮')
		print('│ n' + str(self.node_id).ljust(15) + '│')
		print('│' + self.addr.center(17) + '│')
		print('╰───┬─────────────╯')

		while True:
			print('    │ Edit:')
			print('    ╰─┬─(a)ddress')
			print('      ├─(c)redentials')
			print('      ╰─(e)xit')
			print('')
			choice = input("Selection: ")
			match choice:

				# Modify the node's IP address (may make self.addr a list eventually to differentiate multi-homed hosts)
				case 'a' | 'A':
					self.addr = input("New node address: ")

				# Enter our credential-editing cases
				case 'c' | 'C':
					while True:

						# If we don't have credentials, run self.get_creds() to add new ones
						if len(self.creds) == 0:
							print('No credentials listed for this node.')
							self.get_creds()
							break
						count = 1
						name_to_edit = ''
						print('    │ Credentials (\'*\' = default):')

						# Iterate through node credentials and display them
						for username, passwd in self.creds.items():
							if username == self.username:
								display_name = '*' + username
							else:
								display_name = username
							if count == 1:
								print('    ╰─┬─(' + str(count) + ') ' + display_name)
							else:
								print('      ├─(' + str(count) + ') ' + display_name)
							count += 1
						print('      ├─(a)dd')
						print('      ╰─(b)ack')
						print('')

						# Get credentials to edit
						choice = input('Selection: ')

						# Check our 'char' inputs first
						if choice == 'a' or choice == 'A':
							self.get_creds()
							break
						if choice == 'b' or choice == 'B':
							break
						count = 1

						# Iterate through node credentials again to match user choice to credentials picked
						for username, passwd in self.creds.items():
							if int(choice) == count:
								name_to_edit = username
								pw_to_edit = passwd
								break
							count += 1

						# Give modification options for credentials
						print('    │')
						print('    │ Modification:')
						print('    ╰─┬─(m)ake default')
						print('      ├─(e)dit')
						print('      ├─(d)elete')
						print('      ╰─(b)ack')
						print('')

						choice = input('Selection: ')
						match choice:

							# Reassign our username and passwd default values
							case 'm' | 'M':
								self.username = name_to_edit
								self.passwd = pw_to_edit
								break

							# Get new UN/PW, create the new key, delete the old key, and apply new password to new key
							case 'e' | 'E':
								new_username = input('New username: ')
								new_passwd = getpass('New password: ')
								self.creds[new_username] = self.creds[name_to_edit]
								del self.creds[name_to_edit]
								self.creds[new_username] = new_passwd
								break

							# Delete the set of credentials entirely
							case 'd' | 'D':
								del self.creds[name_to_edit]
								break
							case 'b' | 'B':
								break

				case 'e' | 'E':
					break
				case _:
					print('Invalid choice')
					continue
		print('[+] Node n' + str(self.node_id) + ' successfully modified.')

	# Store new credentials for a node
	def get_creds(self):
		print('Adding credentials to n' + str(self.node_id) + ' - ' + str(self.addr) + ':')
		new_username = input("New username: ")
		new_passwd = getpass("New password: ")
		self.creds[new_username] = new_passwd

		# Give option to make these credentials the default for this node
		default = input('Make this the default login for this node? (Y/n): ')
		if (default == 'y' or default == 'Y'):
			self.username = new_username
			self.passwd = new_passwd
			print('Setting to default')
		else:
			print('Default credentials remain unchanged')


	# Return selected credentials to use for a node
	def use_creds(self):

		# No need to list anything or request input if only one set of credentials exists. Simply return the un/pw
		if len(self.creds.items()) == 1:
			username = list(self.creds.keys())[0]
			passwd = list(self.creds.values())[0]
			return username, passwd

		# If we have multiple login credentials, have user choose which set to use and return the un/pw
		while True:
			count = 1
			print('Credentials for n' + str(self.node_id) + ' - ' + str(self.addr) + ':')
			for username, passwd in self.creds.items():
				print(str(count) + ') ' + username)
				count += 1
			choice = int(input('Number to use: '))
			if choice < 1 or choice > count:
				print('Invalid input')
				continue
			count = 1
			for username, passwd in self.creds.items():
				if choice == count:
					return username, passwd
				count += 1

	# Return True if we have credentials for the object addr and False otherwise
	def node_owned(self):
		if len(self.creds.keys()) > 0:
			for username, passwd in self.creds.items():
				if len(username) > 0:
					if len(passwd) > 0:
						return True
		return False