import re
import os
import cmd
import sys
import common
from getpass import getpass
from kp import KeePassError, get_password 
from configmanager import  ConfigManager, ConfigManagerError

common.init()


class ParseArgsException(Exception):
	def __init__(self, msg):
		self.msg = msg

class ModuleCore(cmd.Cmd):
	def __init__(self, module = ''):
		cmd.Cmd.__init__(self)
		self.master = None

		if module == '#':
			self.prompt_sign = '#>'
		elif module != '':
			self.prompt_sign = '[' + module + ']>'
		else:
			self.prompt_sign = '->'

		#defaults
		self.ruler = '-'

		#Completions
		self.directories = []
		self.file_server_database = []
		self.file_server = []

		self.do_cd('.')

		configs = ConfigManager().get_config_list()
		for conf in configs:
			self.file_server_database.append(conf)
			self.file_server.append(conf)
			for srv in ConfigManager('config/' + conf + '.yaml').get_all():
				self.file_server_database.append(conf + '.' + srv)
				self.file_server.append(conf + '.' + srv)
				for db in ConfigManager('config/' + conf + '.yaml').get(srv)['databases']:
					self.file_server_database.append(conf + '.' + srv + '.' + db)

	def precmd(self, line):
		if not sys.stdin.isatty():
			print(line)
		return line
	
	def postcmd(self, stop, line):
		if not sys.stdin.isatty():
			print("")
		return stop

	def parse_args(self, string="", n=0, m=0):
		list = re.findall('"+.*"+|[a-zA-Z0-9!@#$%^&*()_+-,./<>?]+', string)
		arg_counter = len(list);
		if (arg_counter >= n and arg_counter <= m) or (arg_counter == n and m == 0) or n == 0:
			r_list = []
			for l in list:
				r_list.append(l.replace('"', ''))
			return (r_list, len(list))
		else:
			raise ParseArgsException("Incorrect number of arguments")

	# wykonuje daną funkcję (callback) na wszystkich bazach
	def exec_on_config(self, callback, args, values, view = ''): # link - file.server.base
		if values == '': # wykonaj na wszystkich plikach
			files = ConfigManager().get_config_list() # pobierz listę plików konfiguracyjnych

			# wyświetl na czym będziesz wykonywać
			print("Exec on:")
			for file in files:
				print('+-',file)

			ans = input("Are you sure? [NO/yes/info]: ")

			if ans == "yes": #wykonaj callback
				for file in files:
					if view == 'tree': print('+-', file)
					try:
						servers = ConfigManager("config/" + file + ".yaml").get_all()
						for srv in servers:
							if view == 'tree': print("|  +-", srv)
							databases = servers[srv]["databases"]
							for db in databases:
								if view == 'tree': print("|  |  +-", db)
								if view == 'list': print('[', file, '->', srv, '->', db, ']')
								callback(file, srv, db, *args)
					except ConfigManagerError as e:
						print(e)

			elif ans == "info": #podaj tylko informację na czym callback zostałby wykonany
				for file in files:
					print('+-', file)
					servers = ConfigManager("config/" + file + ".yaml").get_all()
					for srv in servers:
						print('|  +-', srv)
						databases = servers[srv]["databases"]
						for db in databases:
							print('|  |  +-', db)

			else: #jeżeli nie zdecydujemy się na wykonanie czegokolwiek
				print("aborted")

		else: # jeżeli specjalizujemy na czym chcemy wykonać

			val = values.split('.') #rozdzielamy nazwę_pliku.serwera.bazy
			params = len(val)

			if params == 1: # jeżeli podano nazwę tylko pliku to wykonaj na wszystkich serwerach, bazach które są w nim zapisane
				file = val[0]
				try:
					servers = ConfigManager("config/" + file + ".yaml").get_all()
					for srv in servers:
						if view == 'tree': print("+-", srv)
						databases = servers[srv]["databases"]
						for db in databases:
							if view == 'tree': print("|  +-", db)
							if view == 'list': print('[', srv, '->', db, ']')
							callback(file, srv, db, *args)
				except ConfigManagerError as e:
					print(e)
				except KeyError as e:
					print(e, "is not exist")

			elif params == 2: # jeżeli podano nazwę pliku i serwer to wykonaj na wszystkich bazach na serwerze
				file = val[0]
				try:
					servers = ConfigManager("config/" + file + ".yaml").get_all()
					srv = val[1]
					databases = servers[srv]["databases"]
					for db in databases:
						if view == 'tree': print("+-", db)
						if view == 'list': print('[', db, ']')
						callback(file, srv, db, *args)
				except ConfigManagerError as e:
					print(e)
				except KeyError as e:
					print(e, "is not exist")

			elif params == 3: # podano nazwę pliku, serwer i nazwę bazy - wykonaj polecenie dokładnie na niej
				try:
					callback(val[0], val[1], val[2], *args)
				except ConfigManagerError as e:
					print(e)
				except KeyError as e:
					print(e, "is not exist")

	# zwraca skróconą ścieżkę do aktualnego katalogu - funkcja pomocnicza
	def get_shortpath(self):
		path = common.get_cdir()
		separator = ''
		if '\\' in path:
			separator = '\\'
		else:
			separator = '/'
		start = path.find(separator)
		end = path.rfind(separator, 0, len(path)-1)
		if start < end:
			return (path[0:start+1] + '...' + path[end:])
		else:
			return (path)

	# autouzupełnienia dla cmd polecenia cd
	def complete_cd(self, text, line, begidx, endidx):
		if not text:
			completions = self.directories[:]
		else:
			completions = [f for f in self.directories if f.startswith(text)]
		return completions

	# polecenie cd - pozwala na przemieszczanie się po katalogach
	def do_cd(self, args):
		"Move to directory"
		if args == '':
			print(common.get_cdir())
		else:
			try:
				common.chdir(args)
				self.prompt = self.get_shortpath() + ' ' + self.prompt_sign

				self.directories = []
				for name in os.listdir(common.get_cdir()):
					if os.path.isdir(os.path.join(common.get_cdir(), name)):
						self.directories.append(name)
			except FileNotFoundError as e:
				print(e)

	# wyświetla wszystkie pliki w lokalizacji
	def do_ls(self, args):
		"List directory"
		for name in os.listdir(common.get_cdir()):
			print(name)

	# podaje pełną ścieżkę aktualnego katalogu
	def do_pwd(self, args):
		"Print path"
		print(common.get_cdir())

	# pozwala na decyzję czy chcemy wyświetlać warningi
	def do_warn(self, args):
		"""warn <on/off>"""
		try:
			(values, values_num) = self.parse_args(args, 0, 1)
			if values_num == 1:
				if values[0] == 'on':
					print('Warnings on')
					self.warn = True
				elif values[0] == 'off':
					print('Warnings off')
					self.warn = False
				else:
					print('Incorrect argument.')
			else:
				if self.warn == True:
					print('Status: on')
				else:
					print('Status: off')

		except ParseArgsException as e:
			print(e)

	# ustawia masterpassword dla keepasa
	def do_setMaster(self,args):
		"Set master password"
		if sys.stdin.isatty(): # jezeli jako shell
			p = getpass('Enter Master Password: ')
		else:
			p = sys.stdin.readline().rstrip()
		self.master = p
		
	def do_exit(self, *args):
		return True

	def do_EOF(self, line):
		return True

	def emptyline(self):
		return False
	
	# Musimy wyłapać wszystko co możliwe, nie ma pliku, zly master itp. i zwrocic 1 wyjątek
	def get_password(self, alias):
		keepass_path = common.keepass_path
		if self.master == None:
			raise KeePassError("Master Password Not Set")
		try:
			return get_password(keepass_path, self.master, alias)
		except KeePassError as e:
			raise e

	def connect_command_builder(self,connection, perm):
		try:
			command = connection["adress"] + "_" + connection["user"]+ "_" + \
					self.get_password(connection["keepass"]) + "_" + str(connection["sshport"])  + "_" + str(connection["remoteport"]) + "_" + perm
		except (KeyError, KeePassError) as e1:
			try:
				command = connection["adress"] + "_" + connection["user"]+ "_" + \
					connection["passwd"] + "_" + str(connection["sshport"])  + "_" + str(connection["remoteport"]) + "_" + perm
				return command
			except KeyError as e2:
				if isinstance(e1,KeePassError):
					raise KeePassError("Unable to use Keepass(" + e1.value + ") or Password")
				else:
					raise KeePassError("Invalid connection in yaml file")
			raise KeePassError(e1)
		return command
[((10, 0, 10, 13), 'common.init', 'common.init', ({}, {}), '()', False, 'import common\n'), ((19, 2, 19, 24), 'cmd.Cmd.__init__', 'cmd.Cmd.__init__', ({(19, 19, 19, 23): 'self'}, {}), '(self)', False, 'import cmd\n'), ((60, 9, 60, 69), 're.findall', 're.findall', ({(60, 20, 60, 60): '""""+.*"+|[a-zA-Z0-9!@#$%^&*()_+-,./<>?]+"""', (60, 62, 60, 68): 'string'}, {}), '(\'"+.*"+|[a-zA-Z0-9!@#$%^&*()_+-,./<>?]+\', string)', False, 'import re\n'), ((156, 9, 156, 26), 'common.get_cdir', 'common.get_cdir', ({}, {}), '()', False, 'import common\n'), ((231, 5, 231, 23), 'sys.stdin.isatty', 'sys.stdin.isatty', ({}, {}), '()', False, 'import sys\n'), ((50, 9, 50, 27), 'sys.stdin.isatty', 'sys.stdin.isatty', ({}, {}), '()', False, 'import sys\n'), ((55, 9, 55, 27), 'sys.stdin.isatty', 'sys.stdin.isatty', ({}, {}), '()', False, 'import sys\n'), ((197, 25, 197, 42), 'common.get_cdir', 'common.get_cdir', ({}, {}), '()', False, 'import common\n'), ((203, 8, 203, 25), 'common.get_cdir', 'common.get_cdir', ({}, {}), '()', False, 'import common\n'), ((232, 7, 232, 41), 'getpass.getpass', 'getpass', ({(232, 15, 232, 40): '"""Enter Master Password: """'}, {}), "('Enter Master Password: ')", False, 'from getpass import getpass\n'), ((250, 9, 250, 48), 'kp.KeePassError', 'KeePassError', ({(250, 22, 250, 47): '"""Master Password Not Set"""'}, {}), "('Master Password Not Set')", False, 'from kp import KeePassError, get_password\n'), ((252, 10, 252, 56), 'kp.get_password', 'get_password', ({(252, 23, 252, 35): 'keepass_path', (252, 37, 252, 48): 'self.master', (252, 50, 252, 55): 'alias'}, {}), '(keepass_path, self.master, alias)', False, 'from kp import KeePassError, get_password\n'), ((39, 12, 39, 27), 'configmanager.ConfigManager', 'ConfigManager', ({}, {}), '()', False, 'from configmanager import ConfigManager, ConfigManagerError\n'), ((181, 9, 181, 26), 'common.get_cdir', 'common.get_cdir', ({}, {}), '()', False, 'import common\n'), ((184, 4, 184, 22), 'common.chdir', 'common.chdir', ({(184, 17, 184, 21): 'args'}, {}), '(args)', False, 'import common\n'), ((270, 9, 270, 25), 'kp.KeePassError', 'KeePassError', ({(270, 22, 270, 24): 'e1'}, {}), '(e1)', False, 'from kp import KeePassError, get_password\n'), ((43, 14, 43, 55), 'configmanager.ConfigManager', 'ConfigManager', ({(43, 28, 43, 54): "('config/' + conf + '.yaml')"}, {}), "('config/' + conf + '.yaml')", False, 'from configmanager import ConfigManager, ConfigManagerError\n'), ((73, 11, 73, 26), 'configmanager.ConfigManager', 'ConfigManager', ({}, {}), '()', False, 'from configmanager import ConfigManager, ConfigManagerError\n'), ((188, 27, 188, 44), 'common.get_cdir', 'common.get_cdir', ({}, {}), '()', False, 'import common\n'), ((234, 7, 234, 27), 'sys.stdin.readline', 'sys.stdin.readline', ({}, {}), '()', False, 'import sys\n'), ((46, 14, 46, 55), 'configmanager.ConfigManager', 'ConfigManager', ({(46, 28, 46, 54): "('config/' + conf + '.yaml')"}, {}), "('config/' + conf + '.yaml')", False, 'from configmanager import ConfigManager, ConfigManagerError\n'), ((118, 15, 118, 56), 'configmanager.ConfigManager', 'ConfigManager', ({(118, 29, 118, 55): "'config/' + file + '.yaml'"}, {}), "('config/' + file + '.yaml')", False, 'from configmanager import ConfigManager, ConfigManagerError\n'), ((189, 35, 189, 52), 'common.get_cdir', 'common.get_cdir', ({}, {}), '()', False, 'import common\n'), ((267, 11, 267, 78), 'kp.KeePassError', 'KeePassError', ({(267, 24, 267, 77): "('Unable to use Keepass(' + e1.value + ') or Password')"}, {}), "('Unable to use Keepass(' + e1.value + ') or Password')", False, 'from kp import KeePassError, get_password\n'), ((269, 11, 269, 58), 'kp.KeePassError', 'KeePassError', ({(269, 24, 269, 57): '"""Invalid connection in yaml file"""'}, {}), "('Invalid connection in yaml file')", False, 'from kp import KeePassError, get_password\n'), ((86, 16, 86, 57), 'configmanager.ConfigManager', 'ConfigManager', ({(86, 30, 86, 56): "'config/' + file + '.yaml'"}, {}), "('config/' + file + '.yaml')", False, 'from configmanager import ConfigManager, ConfigManagerError\n'), ((100, 15, 100, 56), 'configmanager.ConfigManager', 'ConfigManager', ({(100, 29, 100, 55): "'config/' + file + '.yaml'"}, {}), "('config/' + file + '.yaml')", False, 'from configmanager import ConfigManager, ConfigManagerError\n'), ((134, 15, 134, 56), 'configmanager.ConfigManager', 'ConfigManager', ({(134, 29, 134, 55): "'config/' + file + '.yaml'"}, {}), "('config/' + file + '.yaml')", False, 'from configmanager import ConfigManager, ConfigManagerError\n')]