text: #!/usr/bin/env python
  # -*- coding: latin-1 -*-
  import curses, time
  
  
  import global_mod as g
  import getstr
  import footer
  import readhashmap
  import csv
  import os
  import inspect
  
  def draw_window(state, window, rpc_queue=None, do_clear = True):
  
  	if do_clear:
  		window.clear()
  		window.refresh()
  
  	win_header = curses.newwin(3, g.x, 0, 0)
  
  	unit = g.coin_unit
  	if 'testnet' in state:
  		if state['testnet']:
  			unit = g.coin_unit_test
  
  	if 'wallet' in state or 'walletinfo' in state:
  		if 'balance' in state:
  			balance_string = "Balance: " + "%0.8f" % state['balance'] + " " + unit
  			if 'unconfirmedbalance' in state:
  				if state['unconfirmedbalance'] != 0:
  					balance_string += " (+" + "%0.8f" % state['unconfirmedbalance'] + " unconf)"
  			if 'unconfirmed_balance' in state:
  				if state['unconfirmed_balance'] != 0:
  					balance_string += " (+" + "%0.8f" % state['unconfirmed_balance'] + " unconf)"
  			window.addstr(0, 1, balance_string, curses.A_BOLD)
  		
  		if 'walletinfo' in state:
  			if 'paytxfee' in state['walletinfo']:
  				fee_string = "Fee: " + "%0.8f" % state['walletinfo']['paytxfee'] + " " + unit + " per kB"
  				window.addstr(1, 1, fee_string, curses.A_BOLD)
  			fee_string = "Wallet status: "
  			if 'unlocked_until' in state['walletinfo']:
  				if state['walletinfo']['unlocked_until'] == 0:
  					fee_string += 'locked'
  					window.addstr(2, 1, fee_string, curses.A_BOLD)
  				else:
  					try:
  						fee_string += 'unlocked until ' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(state['walletinfo']['unlocked_until']))
  					except ValueError:
  						fee_string += 'unlocked!!! (' + str(state['walletinfo']['unlocked_until'])+ ')'
  					window.addstr(2, 1, fee_string, curses.A_BOLD + curses.A_REVERSE)
  			else:
  				fee_string += 'not encrypted!'
  				window.addstr(2, 1, fee_string, curses.A_BOLD + curses.A_REVERSE)
  
  		if state['wallet']['mode'] == 'tx':
  			g.addstr_rjust(window, 0, "(W: refresh, A: list addresses, R: new address)", curses.A_BOLD, 1)
  			g.addstr_rjust(window, 1, "(X: set tx fee, S: send " + unit + ")", curses.A_BOLD, 1)
  			g.addstr_rjust(window, 2, "(E: export all txs, L: export wallet.dat)", curses.A_BOLD, 1)
  			draw_transactions(state)
  		elif state['wallet']['mode'] == 'settxfee':
  			draw_fee_input_window(state, window, rpc_queue)
  		elif state['wallet']['mode'] == 'newaddress':
  			draw_new_address_window(state, window, rpc_queue)
  		elif state['wallet']['mode'] == 'sendtoaddress':
  			draw_send_coins_window(state, window, rpc_queue)
  		elif state['wallet']['mode'] == 'backupwallet':
  			draw_backup_wallet_window(state, window, rpc_queue)
  		elif state['wallet']['mode'] == 'exporttx':
  			draw_exporttx_window(state, window, rpc_queue)
  		else:
  			g.addstr_rjust(window, 0, "(W: refresh, A: list addresses, R: new address)", curses.A_BOLD, 1)
  			g.addstr_rjust(window, 1, "(X: set tx fee, S: send " + unit + ")", curses.A_BOLD, 1)
  			g.addstr_rjust(window, 2, "(E: export all txs, L: export wallet.dat)", curses.A_BOLD, 1)
  			draw_addresses(state)
  
  	else:
  		if rpc_queue.qsize() > 0:
  			g.addstr_cjust(win_header, 0, "...waiting for wallet information being processed...", curses.A_BOLD + curses.color_pair(3))
  		else:
  			win_header.addstr(0, 1, "no wallet information loaded.", curses.A_BOLD + curses.color_pair(3))
  			win_header.addstr(1, 1, "press 'W' to refresh", curses.A_BOLD)
  
  	win_header.refresh()
  	footer.draw_window(state, rpc_queue)
  
  def draw_transactions(state):
  	g.viewport_heigth = g.y - 5
  	win_transactions = curses.newwin(g.viewport_heigth, g.x, 4, 0)
  
  	win_transactions.addstr(0, 1, "{:,d}".format(len(state['wallet']['view_string'])/(5 if state['wallet']['verbose'] > 0 else 4)) + " transactions:", curses.A_BOLD + curses.color_pair(5))
  	caption = "(UP/DOWN: scroll, ENTER: view, V: less verbose)" if state['wallet']['verbose'] > 0 else "(UP/DOWN: scroll, ENTER: view, V: verbose, O: Output tx)"
  	g.addstr_rjust(win_transactions, 0, caption, curses.A_BOLD + curses.color_pair(5), 1)
  	
  	offset = state['wallet']['offset']
  
  	for index in xrange(offset, offset + g.viewport_heigth - 1):
  		if index < len(state['wallet']['view_string']):
  				condition = (index == offset + g.viewport_heigth - 2) and (index+1 < len(state['wallet']['view_string']))
  				condition = condition or ( (index == offset) and (index > 0) )
  
  				if condition:
  					win_transactions.addstr(index+1-offset, 1, "...")
  				else:
  					win_transactions.addstr(index+1-offset, 1, state['wallet']['view_string'][index], curses.color_pair(state['wallet']['view_colorpair'][index]))
  
  				if index == (state['wallet']['cursor']* (5 if state['wallet']['verbose'] > 0 else 4) + 1):
  					win_transactions.addstr(index+1-offset, 1, ">", curses.A_REVERSE + curses.A_BOLD)
  
  	win_transactions.refresh()
  
  def draw_addresses(state):
  	g.viewport_heigth = g.y - 5
  	win_addresses = curses.newwin(g.viewport_heigth, g.x, 4, 0)
  	offset = state['wallet']['offset']
  
  	if 'addresses_view_string' in state['wallet']:
  
  		win_addresses.addstr(0, 1, str(len(state['wallet']['addresses_view_string'])/4) + " addresses:", curses.A_BOLD + curses.color_pair(5))
  		g.addstr_rjust(win_addresses, 0, "(UP/DOWN: scroll)", curses.A_BOLD + curses.color_pair(5), 1)
  		
  		for index in xrange(offset, offset + g.viewport_heigth - 1):
  			if index < len(state['wallet']['addresses_view_string']):
  					condition = (index == offset + g.viewport_heigth - 2) and (index+1 < len(state['wallet']['addresses_view_string']))
  					condition = condition or ( (index == offset) and (index > 0) )
  
  					if condition:
  						win_addresses.addstr(index+1-offset, 1, "...")
  					else:
  						win_addresses.addstr(index+1-offset, 1, state['wallet']['addresses_view_string'][index], curses.color_pair(state['wallet']['addresses_view_colorpair'][index]))
  
  	else:
  		g.addstr_cjust(win_addresses, 0, "...waiting for address information being processed...", curses.A_BOLD + curses.color_pair(3))
  		# win_addresses.addstr(1, 1, "...waiting for address information being processed...", curses.A_BOLD + curses.color_pair(3))
  
  	win_addresses.refresh()
  
  def draw_fee_input_window(state, window, rpc_queue):
  	color = curses.color_pair(1)
  	unit = g.coin_unit
  	if g.testnet:
  		color = curses.color_pair(2)
  		unit = g.coin_unit_test
  
  	UI = getstr.UserInput(window, "fee input mode")
  	if 'walletinfo' in state:
  		if 'paytxfee' in state['walletinfo']:
  			fee_string = "Current transaction fee: " + "%0.8f" % state['walletinfo']['paytxfee'] + " " + unit + " per kB"
  			UI.addline(fee_string)
  
  	if 'estimatefee' in state and len(state['estimatefee']):
  		string = "Estimatefee: "
  		for item in state['estimatefee']:
  			if item['value'] >= 0:
  				string += "{:0.8f}".format(item['value']) + " " + unit + " per kB (" + str(item['blocks']) + (" blocks) " if int(item['blocks']) > 1 else " block) ")
  		UI.addline(string, curses.A_NORMAL)
  
  	UI.addline("Please enter new transaction fee in " + unit + " per kB:", curses.A_BOLD)
  	
  	try:
  		new_fee = float(UI.getstr(64))
  	except ValueError:
  		new_fee = -1
  	
  	if new_fee >= 0:
  		s = {'settxfee': "{:0.8f}".format(new_fee)}
  		UI.addmessageline("Setting transaction fee value to " + "{:0.8f}".format(new_fee) + " " + unit + " per kB...", color + curses.A_BOLD)
  		rpc_queue.put(s)
  	else:
  		UI.addmessageline("No valid fee amount entered. Aborting.", color + curses.A_BOLD)
  		UI.clear()
  		state['wallet']['mode'] = 'addresses'
  		rpc_queue.put('listsinceblock')
  
  def draw_new_address_window(state, window, rpc_queue):
  	color = curses.color_pair(1)
  	if g.testnet:
  		color = curses.color_pair(2)
  
  	UI = getstr.UserInput(window, "new receiving address mode")
  
  	abort = False
  	error_string = ""
  	UI.addline("Please enter an address label (optional):", curses.A_BOLD)
  	try:
  		new_account = str(UI.getstr(128)).strip()
  	except:
  		abort = True
  	
  	if not abort:
  		UI.addline("Do you want to add a [r]eceiving or a [w]atch-only address? [r/w]", curses.A_BOLD)
  		try:
  			new_type = str(UI.getstr(1))
  		except:
  			error_string = "Invalid address type entered. "
  			abort = True
  
  		if new_type == 'r':
  			state['wallet']['y'] = UI._y + 2
  			state['wallet']['newlabel'] = new_account
  			rpc_queue.put({'getnewaddress': new_account})
  			UI.addmessageline("Creating new receiving address" + (" for account " + "'{}'".format(new_account) if len(new_account) else "") + "...", 
  								color + curses.A_BOLD)
  		elif new_type == 'w':
  			UI.addline("Please enter watch-only address:", curses.A_BOLD)
  			new_address = ""
  			try:
  				new_address = UI.getstr(35).strip()
  			except:
  				abort = True
  			if not check_address(new_address):
  				error_string = "Invalid address entered. "
  				abort = True
  			if not abort:
  				UI.addline("Do you want to rescan the entire blockchain for matching transactions? [y/N]", curses.A_BOLD)
  				try:
  					new_rescan = str(UI.getstr(1))
  				except:
  					abort = True
  				if new_rescan in ['y', 'Y']:
  					new_rescan = True
  				elif new_rescan in ['n', 'N']:
  					new_rescan = False
  				else:
  					abort = True
  
  				if not abort:
  					state['wallet']['newlabel'] = new_account
  					state['wallet']['newaddress'] = new_address
  					s = {'importaddress': {'account': new_account, 'address': new_address, 'rescan': bool(new_rescan)}}
  					rpc_queue.put(s)
  					UI.addmessageline("Importing watch-only address" + (" for account " + "'{}'".format(new_account) if len(new_account) else "") + "...", 
  										color + curses.A_BOLD)
  		else:
  			abort = True
  
  	if abort:
  		UI.addmessageline(error_string + "Aborting.", color + curses.A_BOLD)
  		state['wallet']['mode'] = 'addresses'
  		rpc_queue.put('listreceivedbyaddress')
  		UI.clear()
  		footer.draw_window(state, rpc_queue, True)
  
  def draw_new_address_update(state, window):
  	color = curses.color_pair(1)
  	if g.testnet:
  		color = curses.color_pair(2)
  
  	if 'newaddress' in state['wallet'] and 'y' in state['wallet']:
  		y = int(state['wallet']['y'])
  		this_y, _ = window.getmaxyx()
  		if y >= this_y:
  			y -= 1
  		window.addstr(y, 1, "Address successfully added: " + state['wallet']['newaddress'], color + curses.A_BOLD)
  		window.refresh()
  		time.sleep(4)
  
  def draw_backup_wallet_window(state, window, rpc_queue):
  	color = curses.color_pair(1)
  	if g.testnet:
  		color = curses.color_pair(2)
  
  	UI = getstr.UserInput(window, "backup wallet.dat mode")
  
  	UI.addline("Please enter destination file or directory name:", curses.A_BOLD)
  	try:
  		backup = str(UI.getstr(254)).strip()
  	except ValueError:
  		backup = ""
  	
  	state['wallet']['y'] = UI._y + 1
  	if backup != "":
  		backup = backup.replace('~', os.path.expanduser('~'))
  		rpc_queue.put({'backupwallet': backup })
  		UI.addmessageline("Backing up wallet.dat to file '" + backup + "'...", color + curses.A_BOLD)
  	else:
  		UI.addmessageline("Invalid file or directory name. Aborting.", color + curses.A_BOLD)
  		state['wallet']['mode'] = 'tx'
  		rpc_queue.put('getwalletinfo')
  		rpc_queue.put('listsinceblock')
  		UI.clear()
  
  def draw_exporttx_window(state, window, rpc_queue):
  	color = curses.color_pair(1)
  	if g.testnet:
  		color = curses.color_pair(2)
  
  	UI = getstr.UserInput(window, "export transactions to csv file")
  
  	# check for csv data in state
  	if 'csv_data' in state['wallet']:
  		if len(state['wallet']['csv_data']) > 0:
  			UI.addline("Please enter destination file name (existing file will be overwritten):", curses.A_BOLD)
  			try:
  				backup = str(UI.getstr(254)).strip()
  			except ValueError:
  				backup = ""
  			if backup != '':
  				backup = backup.replace('~', os.path.expanduser('~'))
  				state['wallet']['y'] = UI._y + 1
  				UI.addmessageline("Saving " + str(len(state['wallet']['csv_data'])) + " tx...", color + curses.A_BOLD)
  				_csv = readhashmap.get(os.path.dirname(os.path.abspath(inspect.getframeinfo(inspect.currentframe()).filename)) + \
  					os.path.sep + 'csv_export_de.tpl')	# template hard coded here!!!
  				try:
  					with open(backup, 'w') as f:
  						csv.register_dialect('coindDialect', quoting=csv.QUOTE_ALL, skipinitialspace=True)
  						writer = csv.writer(f, dialect='coindDialect')
  						writer.writerow([_csv['Confirmed'], _csv['Date'], _csv['Type'], _csv['Label'], _csv['Address'], _csv['Amount'] + ' (' + g.coin_unit + ')', _csv['ID']])
  						for tx in state['wallet']['csv_data']:
  							writer.writerow([tx['Confirmed'].encode('utf-8'), tx['Date'].encode('utf-8'), _csv[tx['Type']], tx['Label'].encode('utf-8'), tx['Address'].encode('utf-8'), str(tx['Amount']).encode('utf-8'), tx['ID'].encode('utf-8')])
  					f.close()
  					UI.addmessageline("File '" + backup + "' sucessfully written.", color + curses.A_BOLD)
  				except:
  					UI.addmessageline("An error occured on saving the file...", color + curses.A_BOLD)
  			else:
  				UI.addmessageline("Invalid file or directory name. Aborting.", color + curses.A_BOLD)
  		else:
  			UI.addmessageline("There are no transactions to save...", color + curses.A_BOLD)
  	else:
  		UI.addmessageline("No wallet data loaded yet...", color + curses.A_BOLD)
  		
  	# return to tx view
  	state['wallet']['mode'] = 'tx'
  	rpc_queue.put('getwalletinfo')
  	rpc_queue.put('listsinceblock')
  	UI.clear()
  
  def draw_send_coins_window(state, window, rpc_queue):
  	color = curses.color_pair(1)
  	unit = g.coin_unit
  	if g.testnet:
  		color = curses.color_pair(2)
  		unit = g.coin_unit_test
  
  	UI = getstr.UserInput(window, "send " + unit + " mode")
  
  	if 'balance' in state and g.y >= 14:
  		display_string = "Current balance: " + "%0.8f" % state['balance'] + " " + unit
  		if 'unconfirmedbalance' in state:
  			if state['unconfirmedbalance'] != 0:
  				display_string += " (+" + "%0.8f" % state['unconfirmedbalance'] + " unconf)"
  		if 'unconfirmed_balance' in state:
  			if state['unconfirmed_balance'] != 0:
  				display_string += " (+" + "%0.8f" % state['unconfirmed_balance'] + " unconf)"
  		UI.addline(display_string)
  
  	if 'walletinfo' in state:
  		if 'paytxfee' in state['walletinfo'] and g.y >= 15:
  			display_string = "Current transaction fee: " + "%0.8f" % state['walletinfo']['paytxfee'] + " " + unit + " per kB"
  			UI.addline(display_string, curses.A_NORMAL)
  
  	if 'estimatefee' in state and g.y >= 17:
  		display_string = "Estimatefee: "
  		for item in state['estimatefee']:
  			if item['value'] > 0:
  				display_string += "{:0.8f}".format(item['value']) + " " + unit + " per kB (" + str(item['blocks']) + (" blocks) " if int(item['blocks']) > 1 else " block) ")
  		UI.addline(display_string, curses.A_NORMAL)
  
  	err_msg = ""
  	abort = False
  
  	UI.addline("Please enter amount of " + unit + " so send:", curses.A_BOLD)
  	try:
  		amount = float(UI.getstr(32))
  	except ValueError:
  		amount = -1
  	
  	if amount > 0:
  
  		state['newtransaction']['amount'] = "%0.8f" % amount
  
  		UI.addline("Please enter receiving address:", curses.A_BOLD)
  		try:
  			address = UI.getstr(54).strip()
  		except:
  			abort = True
  
  		if check_address(address) and not abort:
  
  			state['newtransaction']['address'] = address
  			
  			UI.addline("Please enter a comment on the transaction (optional):", curses.A_BOLD)
  			try:
  				comment = UI.getstr(128).strip()
  			except:
  				abort = True
  
  			if not abort:
  
  				state['newtransaction']['comment'] = comment
  				
  				UI.addline("Please enter a comment on the recipient (optional):", curses.A_BOLD)
  				try:
  					comment_to = UI.getstr(128).strip()
  				except:
  					abort = True
  
  				if not abort:
  
  					state['newtransaction']['comment_to'] = comment_to
  				
  					if g.y >= 19:
  						UI.addline()
  					if g.y >= 16:
  						UI.addline("You will send " + "{:0.8f}".format(amount) + " " + unit + " (+ fee) to the address '" + address + "'")
  					if g.y >= 18:
  						UI.addline()
  
  					encrypted = False
  					if 'walletinfo' in state:
  						if 'unlocked_until' in state['walletinfo']:
  							encrypted = True
  
  					if encrypted:
  						UI.addline("Please confirm this transaction by providing your wallet's passphrase:", curses.A_BOLD)
  						try:
  							password = getstr.getstr(128, UI._y, 1, "*")
  							pass
  						except:
  							abort = True
  					else:
  						abort = not UI.continue_yesno(False)
  						UI._y -= 1
  
  					if not abort:
  
  						if encrypted:
  							if g.y >= 18:
  								UI.addline()
  							s = {'walletpassphrase': password}
  							rpc_queue.put(s)
  							UI.addmessageline("Unlocking wallet and sending transaction...", color + curses.A_BOLD)
  						else:
  							if g.y >= 17:
  								UI.addline()
  							s = {'sendtoaddress': {'address': address, 'amount': str(amount), 'comment': comment, 'comment_to': comment_to}}
  							rpc_queue.put(s)
  							UI.addmessageline("Sending transaction...", color + curses.A_BOLD)
  						state['wallet']['y'] = UI._y
  
  		else:
  			err_msg = "Invalid receiving address."
  			abort = True
  
  	else:
  		err_msg = "Invalid amount."
  		abort = True
  
  	if abort:
  		UI.addmessageline(err_msg + " Aborting.", color + curses.A_BOLD)
  		UI.clear()
  		state['wallet']['mode'] = 'addresses'
  		rpc_queue.put('listsinceblock')
  
  def draw_transaction_update(state, window):
  	color = curses.color_pair(1)
  	if g.testnet:
  		color = curses.color_pair(2)
  
  	if 'newtransaction' in state:
  		if 'y' in state['wallet']:
  			y = int(state['wallet']['y'])
  			this_y, _ = window.getmaxyx()
  			if y >= this_y:
  				y -= 1
  			if 'result' in state['newtransaction']:
  				if len(state['newtransaction']['result']) < 26:
  					window.addstr(y, 1, "Sending error - transaction failed.".ljust(g.x - 2, " "), color + curses.A_BOLD)
  				else:
  					window.addstr(y, 1, ("Transaction successful. Tx id: " + state['newtransaction']['result']).ljust(g.x - 2, " "), color + curses.A_BOLD)
  				window.refresh()
  				time.sleep(4)
  
  def check_address(address):
  	if g.coinmode == 'LTC':
  		# Addresses for litecoin:
  		return bool(len(address) >= 26 and len(address) <= 35 and ((not g.testnet and (address.startswith('L') or address.startswith('3') or address.startswith('M'))) or (g.testnet and (address.startswith('m') or address.startswith('n') or address.startswith('2')))))
  	elif g.coinmode == 'BCH' or g.coinmode == 'BCHA':
  		# Addresses for bitcoin cash:
  		return bool(len(address) >= 26 and len(address) <= 54 and ((not g.testnet and (address.startswith('1') or address.startswith('3') or address.startswith('q') or address.startswith('bitcoincash:q'))) or (g.testnet and (address.startswith('m') or address.startswith('n') or address.startswith('2') or address.startswith('bchtest:')))))
  	elif g.coinmode == 'BSV':
  		# Addresses for bitcoin cash sv:
  		return bool(len(address) >= 26 and len(address) <= 54 and ((not g.testnet and (address.startswith('1') or address.startswith('3') or address.startswith('q') or address.startswith('bitcoincash:q'))) or (g.testnet and (address.startswith('m') or address.startswith('n') or address.startswith('2') or address.startswith('bchtest:')))))
  	elif g.coinmode == 'BTG':
  		# Addresses for bitcoin gold:
  		return bool(len(address) >= 26 and len(address) <= 35 and ((not g.testnet and (address.startswith('G'))) or (g.testnet and (address.startswith('m') or address.startswith('n') or address.startswith('2')))))
  	else:
  		# Addresses for bitcoin:
  		return bool(len(address) >= 26 and len(address) <= 35 and ((not g.testnet and (address.startswith('1') or address.startswith('3'))) or (g.testnet and (address.startswith('m') or address.startswith('n') or address.startswith('2')))))
  