package gui

// toolsGui.go implements pages to use Seekia tools
// Tools are various utilities to perform tasks such as generating identity hashes, verifying memos, and more

import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/data/binding"
import "fyne.io/fyne/v2/dialog"
import "fyne.io/fyne/v2/layout"
import "fyne.io/fyne/v2/theme"
import "fyne.io/fyne/v2/widget"

import "seekia/internal/cryptocurrency/cardanoAddress"
import "seekia/internal/cryptocurrency/ethereumAddress"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/memos/createMemos"
import "seekia/internal/memos/readMemos"
import "seekia/internal/myIdentity"
import "seekia/internal/mySettings"
import "seekia/internal/seedPhrase"

import "errors"

func setToolsPage(window fyne.Window, previousPage func()){

	currentPage := func(){setToolsPage(window, previousPage)}

	title := getPageTitleCentered("Tools")

	backButton := getBackButtonCentered(previousPage)

	moderateButton := widget.NewButton("Moderate", func(){
			setModeratePage(window, true, currentPage)
		})

	hostButton := widget.NewButton(translate("Host"), func(){
			setHostPage(window, true, currentPage)
		})

	networkStatisticsButton := widget.NewButton(translate("Network Statistics"), func(){
			setNetworkStatisticsPage(window, currentPage)
		})

	generateCustomIdentityHashButton := widget.NewButton("Generate Custom Identity Hash", func(){
			setChooseIdentityTypeForNewIdentityHashPage(window, currentPage)
		})

	deriveIdentityScoreAddressButton := widget.NewButton("Derive Identity Score Addresses", func(){
			setDeriveIdentityScoreAddressesPage(window, currentPage)
		})

	createMemoButton := widget.NewButton("Create Memo", func(){
			setCreateMemoPage(window, false, "", currentPage)
		})
	verifyMemoButton := widget.NewButton("Verify Memo", func(){
			setVerifyMemoPage(window, currentPage)
		})

	buttonsGrid := container.NewGridWithColumns(1, moderateButton, hostButton, networkStatisticsButton, generateCustomIdentityHashButton, deriveIdentityScoreAddressButton, createMemoButton, verifyMemoButton)
	
	buttonsGridCentered := getContainerCentered(buttonsGrid)
	
	page := container.NewVBox(title, backButton, widget.NewSeparator(), buttonsGridCentered)

	setPageContent(page, window)		
}

// This page is used to generate a new identity hash from the tools menu, not for the user's own identity
// The identity hash that is generated will not be saved to the disk when the user exits the utility.
func setChooseIdentityTypeForNewIdentityHashPage(window fyne.Window, previousPage func()){

	currentPage := func(){setChooseIdentityTypeForNewIdentityHashPage(window, previousPage)}

	title := getPageTitleCentered("Create New Identity Hash")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Choose the identity type for your new identity hash.")
	description2 := getLabelCentered("The last character of the identity hash will be different for each identity type.")
	description3 := getLabelCentered("Mate = m, Host = h, Moderator = r")
	description4 := getLabelCentered("You can change this later by importing the seed phrase as a different identity type.")

	getChooseIdentityTypeButtonWithIcon := func(identityType string)(*fyne.Container, error){

		identityTypeIcon, err := getIdentityTypeIcon(identityType, -2)
		if (err != nil) { return nil, err }

		submitPage := func(seedPhrase string, previousPageFunction func()){
			setViewNewSeedPhrasePage(window, identityType, seedPhrase, previousPageFunction, currentPage)
		}

		chooseIdentityTypeButton := widget.NewButton(identityType, func(){
				setCreateCustomIdentityHashPage(window, identityType, false, 0, 0, currentPage, submitPage)
			})

		buttonWithIcon := container.NewGridWithColumns(1, identityTypeIcon, chooseIdentityTypeButton)

		return buttonWithIcon, nil
	}
	
	mateButtonWithIcon, err := getChooseIdentityTypeButtonWithIcon("Mate")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	hostButtonWithIcon, err := getChooseIdentityTypeButtonWithIcon("Host")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	moderatorButtonWithIcon, err := getChooseIdentityTypeButtonWithIcon("Moderator")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	chooseIdentityTypeButtonsRow := getContainerCentered(container.NewGridWithRows(1, mateButtonWithIcon, hostButtonWithIcon, moderatorButtonWithIcon))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), chooseIdentityTypeButtonsRow)

	setPageContent(page, window)
}

// This page is used to view a newly generated seed phrase from the generation tool.
// The seed phrase is not saved anywhere
func setViewNewSeedPhrasePage(window fyne.Window, identityType string, newSeedPhrase string, previousPage func(), nextPage func()){

	title := getPageTitleCentered("View New Identity Hash")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Here is your generated identity hash.")

	newSeedPhraseHash, err := seedPhrase.ConvertSeedPhraseToSeedPhraseHash(newSeedPhrase)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	newIdentityHash, err := identity.GetIdentityHashFromSeedPhraseHash(newSeedPhraseHash, identityType)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	newIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(newIdentityHash)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	identityHashBox := getContainerCentered(getWidgetBoxed(getBoldLabel(newIdentityHashString)))

	doneButton := getWidgetCentered(widget.NewButtonWithIcon("Done", theme.ConfirmIcon(), nextPage))

	description2 := getBoldLabelCentered("When you press Done, this identity hash will be deleted.")
	description3 := getLabelCentered("Write down this seed phrase to save this identity.")

	seedPhraseLabel := widget.NewMultiLineEntry()
	seedPhraseLabel.Wrapping = 3
	seedPhraseLabel.SetText(newSeedPhrase)
	seedPhraseLabel.OnChanged = func(_ string){
			seedPhraseLabel.SetText(newSeedPhrase)
		}
	seedPhraseLabelBoxed := getWidgetBoxed(seedPhraseLabel)
	widener := widget.NewLabel("                                                                               ")
	seedPhraseLabelWidened := getContainerCentered(container.NewGridWithColumns(1, seedPhraseLabelBoxed, widener))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, identityHashBox, doneButton, widget.NewSeparator(), description2, description3, seedPhraseLabelWidened)
	
	setPageContent(page, window)
}


func setDeriveIdentityScoreAddressesPage(window fyne.Window, previousPage func()){

	title := getPageTitleCentered("Derive Identity Score Addresses")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Convert a moderator's identity hash to their identity score cryptocurrency addresses.")
	description2 := getLabelCentered("Send cryptocurrency to these addresses to increase the user's identity score.") 

	enterIdentityHashLabel := getBoldLabelCentered("               Enter Identity Hash:               ")

	identityHashEntry := widget.NewEntry()
	identityHashEntry.SetPlaceHolder("Enter Identity Hash.")
	identityHashEntryBoxed := getWidgetBoxed(identityHashEntry)

	enterIdentityHashLabelWithEntry := getContainerCentered(container.NewGridWithColumns(1, enterIdentityHashLabel, identityHashEntryBoxed))

	ethereumLabel := getBoldLabelCentered("                       Ethereum:                       ")

	cardanoLabel := getBoldLabelCentered("Cardano:")

	addressBinding_Ethereum := binding.NewString()

	addressBinding_Cardano := binding.NewString()

	addressEntry_Ethereum := widget.NewEntry()
	addressEntry_Cardano := widget.NewEntry()

	addressEntryOnChangedFunction_Ethereum := func(_ string){
			currentAddress, err := addressBinding_Ethereum.Get()
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			addressEntry_Ethereum.SetText(currentAddress)
		}
	
	addressEntryOnChangedFunction_Cardano := func(_ string){
			currentAddress, err := addressBinding_Cardano.Get()
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			addressEntry_Cardano.SetText(currentAddress)
		}
	

	addressEntry_Ethereum.OnChanged = addressEntryOnChangedFunction_Ethereum
	addressEntry_Ethereum.SetPlaceHolder("The Ethereum identity score address will display here.")
	addressEntryBoxed_Ethereum := getWidgetBoxed(addressEntry_Ethereum)

	addressEntry_Cardano.OnChanged = addressEntryOnChangedFunction_Cardano
	addressEntry_Cardano.SetPlaceHolder("The Cardano identity score address will display here.")
	addressEntryBoxed_Cardano := getWidgetBoxed(addressEntry_Cardano)

	deriveButton := getWidgetCentered(widget.NewButtonWithIcon("Derive", theme.MoveDownIcon(), func(){
			inputIdentityHashString := identityHashEntry.Text
			if (inputIdentityHashString == "Admin"){
				setAdminToolsPage(window)
				return
			}			
			if (inputIdentityHashString == ""){
				addressBinding_Ethereum.Set("")
				addressBinding_Cardano.Set("")
				addressEntry_Ethereum.SetText("")
				addressEntry_Cardano.SetText("")
				dialogTitle := translate("No Identity Hash Provided")
				dialogMessage := getLabelCentered("You must enter an identity hash.")
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}
			inputIdentityHash, identityType, err := identity.ReadIdentityHashString(inputIdentityHashString)
			if (err != nil){
				addressBinding_Ethereum.Set("")
				addressBinding_Cardano.Set("")
				addressEntry_Ethereum.SetText("")
				addressEntry_Cardano.SetText("")
				dialogTitle := translate("Identity Hash Is Invalid")
				dialogMessage1 := getLabelCentered("The identity hash you have entered is invalid.")
				dialogMessage2 := getLabelCentered("Identity hashes are 27 characters long.")
				dialogContent := container.NewVBox(dialogMessage1, dialogMessage2)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}
			if (identityType != "Moderator"){
				addressBinding_Ethereum.Set("")
				addressBinding_Cardano.Set("")
				addressEntry_Ethereum.SetText("")
				addressEntry_Cardano.SetText("")
				dialogTitle := translate("Identity Hash Is Invalid")
				dialogMessage1 := getLabelCentered("The identity hash you have entered is not a moderator identity.")
				dialogMessage2 := getLabelCentered("Moderator identity hashes end with an r character.")
				dialogContent := container.NewVBox(dialogMessage1, dialogMessage2)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			identityScoreAddress_Ethereum, err := ethereumAddress.GetIdentityScoreEthereumAddressFromIdentityHash(inputIdentityHash)
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			err = addressBinding_Ethereum.Set(identityScoreAddress_Ethereum)
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			addressEntry_Ethereum.SetText(identityScoreAddress_Ethereum)

			identityScoreAddress_Cardano, err := cardanoAddress.GetIdentityScoreCardanoAddressFromIdentityHash(inputIdentityHash)
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			err = addressBinding_Cardano.Set(identityScoreAddress_Cardano)
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			addressEntry_Cardano.SetText(identityScoreAddress_Cardano)

		}))

	resultAddressesSection := getContainerCentered(container.NewGridWithColumns(1, ethereumLabel, addressEntryBoxed_Ethereum, cardanoLabel, addressEntryBoxed_Cardano))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), enterIdentityHashLabelWithEntry, deriveButton, widget.NewSeparator(), resultAddressesSection)

	setPageContent(page, window)	
}


func setCreateMemoPage(window fyne.Window, messageExists bool, messageText string, previousPage func()){

	currentPage := func(){setCreateMemoPage(window, messageExists, messageText, previousPage)}

	title := getPageTitleCentered("Create Memo")

	backButton := getBackButtonCentered(previousPage)

	description := widget.NewLabel("This page allows you to create a Seekia memo.")
	memoHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
			setMemoExplainerPage(window, currentPage)
		})
	descriptionRow := container.NewHBox(layout.NewSpacer(), description, memoHelpButton, layout.NewSpacer())

	identityTypesList := []string{"Mate", "Host", "Moderator"}

	myIdentityHashesList := make([]string, 0)

	for _, identityType := range identityTypesList{

		myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash(identityType)
		if (err != nil) {
			setErrorEncounteredPage(window, err, previousPage)
			return
		}
		if (myIdentityExists == false){
			continue
		}

		myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}

		myIdentityHashesList = append(myIdentityHashesList, myIdentityHashString)
	}

	if (len(myIdentityHashesList) == 0){

		description2 := getBoldLabelCentered("No identities exist.")
		description3 := getLabelCentered("You must create a Seekia identity to create a memo.")
		description4 := getLabelCentered("Create your identity on the Settings - My Data - My Identity Hashes page.")

		page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), description2, description3, description4)

		setPageContent(page, window)
		return
	}

	chooseIdentityLabel := getBoldLabelCentered("Choose Identity:")

	chooseIdentitySelector := widget.NewSelect(myIdentityHashesList, nil)
	chooseIdentitySelector.Selected = myIdentityHashesList[0]

	chooseIdentitySelectorCentered := getWidgetCentered(chooseIdentitySelector)

	chooseDecorationLabel := getBoldLabelCentered("Choose Decoration:")

	decorationOptionsList := []string{
		"<~ Seekia Memo ~>",
		"«« Seekia Memo »»",
		"⁕ Seekia Memo ⁕",
		"⁂ Seekia Memo ⁂",
		"※ Seekia Memo ※",
	}

	chooseDecorationSelector := widget.NewSelect(decorationOptionsList, func(newDecoration string){
			err := mySettings.SetSetting("MemoDecoration", newDecoration)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
		})

	getCurrentMemoDecoration := func()(string, error){

		exists, memoDecoration, err := mySettings.GetSetting("MemoDecoration")
		if (err != nil) { return "", err }
		if (exists == false){
			return "<~ Seekia Memo ~>", nil
		}
		return memoDecoration, nil
	}

	currentMemoDecoration, err := getCurrentMemoDecoration()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	chooseDecorationSelector.Selected = currentMemoDecoration

	chooseDecorationSelectorCentered := getWidgetCentered(chooseDecorationSelector)

	chooseMessageOptionsGrid := getContainerCentered(container.NewGridWithColumns(2, chooseIdentityLabel, chooseDecorationLabel, chooseIdentitySelectorCentered, chooseDecorationSelectorCentered))

	enterTextLabel := getBoldLabelCentered("Enter Message:")

	header := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), chooseMessageOptionsGrid, widget.NewSeparator(), enterTextLabel)

	enterMessageEntry := widget.NewMultiLineEntry()
	if (messageExists == true){
		enterMessageEntry.SetText(messageText)
	} else {
		enterMessageEntry.SetPlaceHolder("Enter Message...")
	}

	createMemoButton := getWidgetCentered(widget.NewButtonWithIcon("Create Memo", theme.ConfirmIcon(), func(){

			newMemoMessage := enterMessageEntry.Text

			if (newMemoMessage == ""){
				title := translate("No Message Provided")
				dialogMessage := getLabelCentered(translate("You must enter a message to create a memo."))
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(title, translate("Close"), dialogContent, window)
				return
			}

			myIdentityHashString := chooseIdentitySelector.Selected

			myIdentityHash, _, err := identity.ReadIdentityHashString(myIdentityHashString)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}

			identityFound, myPublicIdentityKey, myPrivateIdentityKey, err := myIdentity.GetMyPublicPrivateIdentityKeysFromIdentityHash(myIdentityHash)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			if (identityFound == false){
				setErrorEncounteredPage(window, errors.New("My identity not found after being found already."), currentPage)
				return
			}

			myIdentityType, err := identity.GetIdentityTypeFromIdentityHash(myIdentityHash)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}

			getNewMemoDecorations := func()(string, string, error){

				exists, myMemoDecoration, err := mySettings.GetSetting("MemoDecoration")
				if (err != nil) { return "", "", err }
				if (exists == false){
					return "<~", "~>", nil
				}

				switch myMemoDecoration{

					case "<~ Seekia Memo ~>":{
						return "<~", "~>", nil
					}
					case "«« Seekia Memo »»":{
						return "««", "»»", nil
					}
					case "⁕ Seekia Memo ⁕":{
						return "⁕", "⁕", nil
					}
					case "⁂ Seekia Memo ⁂":{
						return "⁂", "⁂", nil
					}
					case "※ Seekia Memo ※":{
						return "※", "※", nil
					}
				}

				return "", "", errors.New("MySettings contains unknown MemoDecoration: " + myMemoDecoration)
			}

			newMemoDecorationPrefix, newMemoDecorationSuffix, err := getNewMemoDecorations()		
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}

			newMemoString, err := createMemos.CreateMemo(myPublicIdentityKey, myPrivateIdentityKey, myIdentityType, newMemoDecorationPrefix, newMemoDecorationSuffix, newMemoMessage)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}

			// We use this function so that the current memo is not lost if the user goes back
			nextPagePreviousPage := func(){
				setCreateMemoPage(window, true, newMemoMessage, previousPage)
			}

			setViewCreatedMemoButton(window, newMemoString, nextPagePreviousPage)
		}))

	emptyLabel := widget.NewLabel("")
	createMemoButtonWithSpacer := container.NewVBox(createMemoButton, emptyLabel)

	page := container.NewBorder(header, createMemoButtonWithSpacer, nil, nil, enterMessageEntry)
	setPageContent(page, window)
}

func setViewCreatedMemoButton(window fyne.Window, memoString string, previousPage func()){

	currentPage := func(){setViewCreatedMemoButton(window, memoString, previousPage)}

	title := getPageTitleCentered(translate("View Memo"))

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Here is your new Memo.")
	description2 := getLabelCentered("Send funds to the crypto addresses to timestamp your memo.")

	memoIsValid, memoHash, _, _, err := readMemos.ReadMemo(memoString)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (memoIsValid == false){
		setErrorEncounteredPage(window, errors.New("setViewCreatedMemoButton called with invalid memo."), previousPage)
		return
	}

	viewCryptocurrencyAddressesButton := getWidgetCentered(widget.NewButtonWithIcon("View Cryptocurrency Addresses", theme.VisibilityIcon(), func(){
			setViewMemoCryptocurrencyAddressesPage(window, memoHash, "Ethereum", currentPage)
		}))

	memoHashTitle := widget.NewLabel("Memo Hash:")

	memoHashHex := encoding.EncodeBytesToHexString(memoHash[:])

	memoHashTrimmed, _, err := helpers.TrimAndFlattenString(memoHashHex, 15)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	memoHashLabel := getBoldLabel(memoHashTrimmed)

	viewMemoHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
			setViewContentHashPage(window, "Memo", memoHash[:], currentPage)
		})

	memoHashRow := container.NewHBox(layout.NewSpacer(), memoHashTitle, memoHashLabel, viewMemoHashButton, layout.NewSpacer())

	header := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), viewCryptocurrencyAddressesButton, widget.NewSeparator(), memoHashRow, widget.NewSeparator())

	memoTextBox := widget.NewEntry()
	memoTextBox.SetText(memoString)
	memoTextBox.OnChanged = func(_ string){
			memoTextBox.SetText(memoString)
		}

	page := container.NewBorder(header, nil, nil, nil, memoTextBox)

	setPageContent(page, window)
}

func setViewMemoCryptocurrencyAddressesPage(window fyne.Window, memoHash [32]byte, cryptocurrencyName string, previousPage func()){

	if (cryptocurrencyName != "Ethereum" && cryptocurrencyName != "Cardano"){
		setErrorEncounteredPage(window, errors.New("setViewMemoCryptocurrencyAddressesPage called with invalid cryptocurrencyName: " + cryptocurrencyName), previousPage)
	}

	currentPage := func(){setViewMemoCryptocurrencyAddressesPage(window, memoHash, cryptocurrencyName, previousPage)}

	title := getPageTitleCentered("View Memo Cryptocurrency Addresses")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Below is the " + cryptocurrencyName + " address for this memo.")
	description2 := getLabelCentered("Send funds to this address to timestamp the memo.")
	description3 := getLabelCentered("Anyone can verify that the memo existed at the time of the earliest transaction to the address.")

	cryptocurrencyIcon, err := getFyneImageIcon(cryptocurrencyName)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	switchCryptocurrencyButton := widget.NewButton(cryptocurrencyName, func(){

			if (cryptocurrencyName == "Ethereum"){
				setViewMemoCryptocurrencyAddressesPage(window, memoHash, "Cardano", previousPage)
			} else {
				setViewMemoCryptocurrencyAddressesPage(window, memoHash, "Ethereum", previousPage)
			}
		})

	switchCryptocurrencyButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, cryptocurrencyIcon, switchCryptocurrencyButton))


	cryptocurrencyAddress, err := readMemos.GetBlockchainAddressFromMemoHash(cryptocurrencyName, memoHash)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	addressWithButtonsRow, err := getCryptocurrencyAddressLabelWithCopyAndQRButtons(window, cryptocurrencyName, cryptocurrencyAddress, currentPage)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), switchCryptocurrencyButtonWithIcon, widget.NewSeparator(), addressWithButtonsRow)

	setPageContent(page, window)
}

func setVerifyMemoPage(window fyne.Window, previousPage func()){

	currentPage := func(){setVerifyMemoPage(window, previousPage)}

	title := getPageTitleCentered("Verify Memo")

	backButton := getBackButtonCentered(previousPage)

	description := widget.NewLabel("This page can be used to verify a Seekia memo.")
	memoHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
			setMemoExplainerPage(window, currentPage)
		})
	descriptionRow := container.NewHBox(layout.NewSpacer(), description, memoHelpButton, layout.NewSpacer())

	memoEntry := widget.NewMultiLineEntry()

	verifyButton := getWidgetCentered(widget.NewButtonWithIcon("Verify", theme.NavigateNextIcon(), func(){

			memoToVerify := memoEntry.Text

			if (memoToVerify == ""){
				dialogTitle := translate("No Memo Provided")
				dialogMessage := getLabelCentered("The must enter a memo to verify.")
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			memoIsValid, _, _, _, err := readMemos.ReadMemo(memoToVerify)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			if (memoIsValid == false){
				dialogTitle := translate("Memo Is Invalid")
				dialogMessageA := getBoldLabelCentered("The memo you have entered is invalid.")
				dialogMessageB := getLabelCentered("You cannot trust that it was written by its alleged author.")
				dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}
			setViewVerifiedMemoInfoPage(window, memoToVerify, currentPage)
		}))

	emptyLabel := widget.NewLabel("")

	verifyButtonWithSpacer := container.NewVBox(verifyButton, emptyLabel)

	header := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow)

	page := container.NewBorder(header, verifyButtonWithSpacer, nil, nil, memoEntry) 

	setPageContent(page, window)
}


func setViewVerifiedMemoInfoPage(window fyne.Window, memoString string, previousPage func()){

	currentPage := func(){setViewVerifiedMemoInfoPage(window, memoString, previousPage)}

	title := getPageTitleCentered("View Memo Info")

	backButton := getBackButtonCentered(previousPage)

	description := getBoldLabelCentered("The memo is valid!")

	memoIsValid, memoHash, authorIdentityHash, memoUnarmoredContents, err := readMemos.ReadMemo(memoString)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (memoIsValid == false){
		setErrorEncounteredPage(window, errors.New("setViewVerifiedMemoInfoPage called with invalid memo: " + memoString), previousPage)
		return
	}

	memoHashTitle := widget.NewLabel("Memo Hash:")

	memoHashHex := encoding.EncodeBytesToHexString(memoHash[:])

	memoHashTrimmed, _, err := helpers.TrimAndFlattenString(memoHashHex, 15)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	memoHashLabel := getBoldLabel(memoHashTrimmed)

	viewMemoHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
			setViewContentHashPage(window, "Memo", memoHash[:], currentPage)
		})

	memoHashRow := container.NewHBox(layout.NewSpacer(), memoHashTitle, memoHashLabel, viewMemoHashButton, layout.NewSpacer())

	authorLabel := widget.NewLabel("Author:")

	authorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(authorIdentityHash)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	authorIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(authorIdentityHashString, 15)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	authorIdentityHashLabel := getBoldLabel(authorIdentityHashTrimmed)
	viewIdentityHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
			setViewIdentityHashPage(window, authorIdentityHash, currentPage) 
		})

	authorRow := container.NewHBox(layout.NewSpacer(), authorLabel, authorIdentityHashLabel, viewIdentityHashButton, layout.NewSpacer())

	viewCryptocurrencyAddressesButton := getWidgetCentered(widget.NewButtonWithIcon("View Cryptocurrency Addresses", theme.VisibilityIcon(), func(){
			setViewMemoCryptocurrencyAddressesPage(window, memoHash, "Ethereum", currentPage)
		}))

	viewUnarmoredContentsButton := getWidgetCentered(widget.NewButtonWithIcon("View Unarmored Contents", theme.VisibilityIcon(), func(){
			setViewTextPage(window, "Viewing Memo Unarmored Contents", memoUnarmoredContents, true, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), memoHashRow, authorRow, viewCryptocurrencyAddressesButton, viewUnarmoredContentsButton)

	setPageContent(page, window)
}


