package gui

// settingsGui.go implements pages to manage a user's settings and user data

import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/container"
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/appMemory"
import "seekia/internal/currencies"
import "seekia/internal/encoding"
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/localFilesystem"
import "seekia/internal/logger"
import "seekia/internal/messaging/chatMessageStorage"
import "seekia/internal/messaging/myChatMessages"
import "seekia/internal/moderation/reportStorage"
import "seekia/internal/moderation/reviewStorage"
import "seekia/internal/myIdentity"
import "seekia/internal/mySeedPhrases"
import "seekia/internal/mySettings"
import "seekia/internal/network/appNetworkType/getAppNetworkType"
import "seekia/internal/network/appNetworkType/setAppNetworkType"
import "seekia/internal/network/myBroadcasts"
import "seekia/internal/profiles/profileStorage"
import "seekia/internal/seedPhrase"

import "errors"

func setSettingsPage(window fyne.Window){
	
	appMemory.SetMemoryEntry("CurrentViewedPage", "Settings")

	currentPage := func(){setSettingsPage(window)}

	title := getPageTitleCentered("Settings")

	description := getLabelCentered("Manage your Seekia settings.")

	myDataButton := widget.NewButton("My Data", func(){
			setSettingsPage_MyData(window, currentPage)
		})

	themesButton := widget.NewButton("Themes", func(){
			setChooseAppThemePage(window, currentPage)
		})

	navigationButton := widget.NewButton("Navigation", func(){
			setNavigationSettingsPage(window, currentPage)
		})

	contentFilteringButton := widget.NewButton("Content Filtering", func(){
			setContentFilteringSettingsPage(window, currentPage)
		})

	networkSettingsButton := widget.NewButton("Network", func(){
			setManageNetworkSettingsPage(window, currentPage)
		})

	storageSettingsButton := widget.NewButton("Storage", func(){
			setManageStoragePage(window, currentPage)
		})

	toolsButton := widget.NewButton("Tools", func(){
			setToolsPage(window, currentPage)
		})

	languageButton := widget.NewButton("Language", func(){
			setSelectLanguagePage(window, true, currentPage)
		})

	logsButton := widget.NewButton("Logs", func(){
			setViewLogsPage(window, "General", currentPage)	
		})

	developerButton := widget.NewButton("Developer", func(){
			setViewDeveloperSettingsPage(window, currentPage)
		})

	buttonGrid := getContainerCentered(container.NewGridWithColumns(1, myDataButton, themesButton, navigationButton, contentFilteringButton, networkSettingsButton, storageSettingsButton, toolsButton, languageButton, logsButton, developerButton))

	pageContent := container.NewVBox(title, widget.NewSeparator(), description, widget.NewSeparator(), buttonGrid)

	setPageContent(pageContent, window)
}

func getMetricImperialSwitchButton(window fyne.Window, currentPage func())(fyne.Widget, error){

	currentUnitsExist, currentUnits, err := globalSettings.GetSetting("MetricOrImperial")
	if (err != nil){ return nil, err }

	getSwitchButton := func()fyne.Widget{

		if (currentUnitsExist == false || currentUnits == "Metric"){

				button := widget.NewButton(translate("Metric"), func(){
					err := globalSettings.SetSetting("MetricOrImperial", "Imperial")
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
				})
				return button
			}

		button := widget.NewButton(translate("Imperial"), func(){

			err := globalSettings.SetSetting("MetricOrImperial", "Metric")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		})

		return button
	}

	switchButton := getSwitchButton()

	return switchButton, nil
}


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

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

	title := getPageTitleCentered("My Data")

	backButton := getBackButtonCentered(previousPage)

	myIdentityHashesButton := widget.NewButton("My Identity Hashes", func(){
			setViewMyIdentityHashesPage(window, "Mate", currentPage)
		})

	mySeedPhrasesButton := widget.NewButton("My Seed Phrases", func(){
			setViewMySeedPhrasesPage(window, "Mate", currentPage)
		})

	deleteIdentityButton := widget.NewButton("Delete Identity", func(){
			setDeleteMyIdentityPage(window, "Mate", currentPage)
		})

	importIdentityButton := widget.NewButton("Import Identity", func(){
			setImportMyIdentityPage(window, "Mate", currentPage)
		})

	exportDataButton := widget.NewButton("Export Data", func(){
			//TODO
			// Page to export user data
			// This should export the UserData folder(s) to a folder, and that data should be able to be imported to a new device
			// The GUI should give options on which data to export
			showUnderConstructionDialog(window)
		})

	importDataButton := widget.NewButton("Import Data", func(){
			//TODO
			// On import, user should be able to select which elements to import, and any conflicts with existing data should be shown
			// When importing chat keys, we must make sure to prune the user's undecryptable message hashes list
			//		The new keys should be used to attempt to decrypt those messages again (if they still exist on the network)
			showUnderConstructionDialog(window)
		})

	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, myIdentityHashesButton, mySeedPhrasesButton, deleteIdentityButton, importIdentityButton, exportDataButton, importDataButton))
	
	page := container.NewVBox(title, backButton, widget.NewSeparator(), buttonsGrid)

	setPageContent(page, window)
}

func setViewMySeedPhrasesPage(window fyne.Window, myIdentityType string, previousPage func()){

	title := getPageTitleCentered(translate("My Seed Phrase"))

	currentPage := func(){setViewMySeedPhrasesPage(window, myIdentityType, previousPage)}

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Your seed phrase can recover your " + myIdentityType + " identity on any device.")
	description2 := getLabelCentered("Write it down to prevent the loss of your identity.")
	description3 := getBoldLabelCentered("Do not share your seed phrases!")

	identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	getIdentityTypeLabelOrChangeButton := func()(fyne.Widget, error){

		getHostModeEnabledBool := func()(bool, error){
			exists, hostModeOnOffStatus, err := mySettings.GetSetting("HostModeOnOffStatus")
			if (err != nil) { return false, err }
			if (exists == true && hostModeOnOffStatus == "On"){
				return true, nil
			}
			return false, nil
		}

		getModeratorModeEnabledBool := func()(bool, error){
			exists, moderatorModeOnOffStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
			if (err != nil) { return false, err }
			if (exists == true && moderatorModeOnOffStatus == "On"){
				return true, nil
			}
			return false, nil
		}

		hostModeEnabled, err := getHostModeEnabledBool()
		if (err != nil) { return nil, err }

		moderatorModeEnabled, err := getModeratorModeEnabledBool()
		if (err != nil) { return nil, err }

		hostIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Host")
		if (err != nil) { return nil, err }

		moderatorIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Moderator")
		if (err != nil) { return nil, err }

		if (hostModeEnabled == false && hostIdentityExists == false && moderatorModeEnabled == false && moderatorIdentityExists == false){

			// Mate identity is the only identity to show

			mateLabel := getBoldLabel("Mate")
			return mateLabel, nil
		}

		getNextIdentityType := func()string{

			if (myIdentityType == "Mate"){

				if (hostModeEnabled == true || hostIdentityExists == true){
					return "Host"
				}

				return "Moderator"
			}
			if (myIdentityType == "Host"){

				if (moderatorModeEnabled == true || moderatorIdentityExists == true){
					return "Moderator"
				}

				return "Mate"
			}

			return "Mate"
		}

		nextIdentityType := getNextIdentityType()

		changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
				setViewMySeedPhrasesPage(window, nextIdentityType, previousPage)
			})

		return changeIdentityTypeButton, nil
	}

	identityTypeLabelOrChangeButton, err := getIdentityTypeLabelOrChangeButton()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	identityTypeLabelOrChangeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, identityTypeLabelOrChangeButton))

	currentSeedPhraseExists, currentSeedPhrase, err := mySeedPhrases.GetMySeedPhrase(myIdentityType)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (currentSeedPhraseExists == false) {

		identityDoesNotExistLabel := getBoldLabelCentered("Your " + myIdentityType + " identity does not exist.")

		createIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Create Identity", theme.NavigateNextIcon(), func(){
				setChooseNewIdentityHashPage(window, myIdentityType, currentPage, currentPage)
			}))

		page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(),  identityTypeLabelOrChangeButtonWithIcon, identityDoesNotExistLabel, createIdentityButton, widget.NewSeparator())	

		setPageContent(page, window)
		return
	}

	seedPhraseLabel := widget.NewMultiLineEntry()
	seedPhraseLabel.Wrapping = 3
	seedPhraseLabel.SetText(currentSeedPhrase)
	seedPhraseLabel.OnChanged = func(_ string){
			seedPhraseLabel.SetText(currentSeedPhrase)
		}
	seedPhraseLabelBoxed := getWidgetBoxed(seedPhraseLabel)

	widener := widget.NewLabel("                                                                        ")
	seedPhraseBoxWidened := getContainerCentered(container.NewGridWithColumns(1, seedPhraseLabelBoxed, widener))

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

	setPageContent(page, window)
}

func setViewMyIdentityHashesPage(window fyne.Window, myIdentityType string, previousPage func()){

	currentPage := func(){setViewMyIdentityHashesPage(window, myIdentityType, previousPage)}

	title := getPageTitleCentered(translate("My Identity Hashes"))

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("All users of Seekia have a unique identity hash.")
	description2 := getLabelCentered("Share your identity hash to advertise your identity.")

	identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	getIdentityTypeLabelOrChangeButton := func()(fyne.Widget, error){

		getHostModeEnabledBool := func()(bool, error){
			exists, hostModeOnOffStatus, err := mySettings.GetSetting("HostModeOnOffStatus")
			if (err != nil) { return false, err }
			if (exists == true && hostModeOnOffStatus == "On"){
				return true, nil
			}
			return false, nil
		}

		getModeratorModeEnabledBool := func()(bool, error){
			exists, moderatorModeOnOffStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
			if (err != nil) { return false, err }
			if (exists == true && moderatorModeOnOffStatus == "On"){
				return true, nil
			}
			return false, nil
		}

		hostModeEnabled, err := getHostModeEnabledBool()
		if (err != nil) { return nil, err }

		moderatorModeEnabled, err := getModeratorModeEnabledBool()
		if (err != nil) { return nil, err }

		hostIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Host")
		if (err != nil) { return nil, err }

		moderatorIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Moderator")
		if (err != nil) { return nil, err }

		if (hostModeEnabled == false && hostIdentityExists == false && moderatorModeEnabled == false && moderatorIdentityExists == false){

			// Mate identity is the only identity to show
			mateLabel := getBoldLabel("Mate")
			return mateLabel, nil
		}

		getNextIdentityType := func()string{

			if (myIdentityType == "Mate"){

				if (hostModeEnabled == true || hostIdentityExists == true){
					return "Host"
				}
				return "Moderator"
			}

			if (myIdentityType == "Host"){

				if (moderatorModeEnabled == true || moderatorIdentityExists == true){
					return "Moderator"
				}
				return "Mate"
			}
			return "Mate"
		}

		nextIdentityType := getNextIdentityType()

		changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
				setViewMyIdentityHashesPage(window, nextIdentityType, previousPage)
			})

		return changeIdentityTypeButton, nil
	}

	identityTypeLabelOrChangeButton, err := getIdentityTypeLabelOrChangeButton()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	identityTypeLabelOrChangeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, identityTypeLabelOrChangeButton))

	currentIdentityHashExists, currentIdentityHash, err := myIdentity.GetMyIdentityHash(myIdentityType)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	if (currentIdentityHashExists == false) {

		identityDoesNotExistLabel := getBoldLabelCentered("Your " + myIdentityType + " identity does not exist.")

		createIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Create Identity", theme.NavigateNextIcon(), func(){
				setChooseNewIdentityHashPage(window, myIdentityType, currentPage, currentPage)
			}))

		page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, identityDoesNotExistLabel, createIdentityButton, widget.NewSeparator())

		setPageContent(page, window)
		return
	}

	currentIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(currentIdentityHash)
	if (err != nil){
		currentIdentityHashHex := encoding.EncodeBytesToHexString(currentIdentityHash[:])
		setErrorEncounteredPage(window, errors.New("GetMyIdentityHash returning invalid myIdentityHash: " + currentIdentityHashHex), previousPage)
		return
	}

	identityHashLabel := widget.NewMultiLineEntry()
	identityHashLabel.SetText(currentIdentityHashString)
	identityHashLabel.OnChanged = func(_ string){
			identityHashLabel.SetText(currentIdentityHashString)
		}
	identityHashLabelBoxed := getWidgetBoxed(identityHashLabel)

	boxWidener := widget.NewLabel("                                                                        ")
	identityHashBoxWidened := getContainerCentered(container.NewGridWithColumns(1, identityHashLabelBoxed, boxWidener))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, identityHashBoxWidened)

	setPageContent(page, window)
}


func setDeleteMyIdentityPage(window fyne.Window, myIdentityType string, previousPage func()){

	currentPage := func(){setDeleteMyIdentityPage(window, myIdentityType, previousPage)}

	if (myIdentityType != "Mate" && myIdentityType != "Host" && myIdentityType != "Moderator"){
		setErrorEncounteredPage(window, errors.New("setDeleteMyIdentityPage called with invalid identity type: " + myIdentityType), previousPage)
		return
	}

	title := getPageTitleCentered(translate("Delete Identity"))

	backButton := getBackButtonCentered(previousPage)

	getDescriptionSection := func()*fyne.Container{

		description1 := getLabelCentered("This page allows you to delete your " + myIdentityType + " identity.")

		if (myIdentityType == "Host"){
			description2 := getLabelCentered("You will lose your host identity balance and account funds.")
			description3 := getLabelCentered("Write down your seed phrase to keep access to your identity and funds.")
			description4 := getLabelCentered("Disable your profile before doing this.")
			descriptionSection := container.NewVBox(description1, description2, description3, description4)
			return descriptionSection
		}
		if (myIdentityType == "Moderator"){
			description2 := getLabelCentered("You will lose your identity score and account funds.")
			description3 := getLabelCentered("This will also delete your message history.")
			description4 := getLabelCentered("Write down your seed phrase to keep access to your identity and funds.")
			descriptionSection := container.NewVBox(description1, description2, description3, description4)
			return descriptionSection
		}

		description2 := getLabelCentered("This will delete your messages, identity balance, and account funds.")
		description3 := getLabelCentered("Write down your seed phrase to keep access to your identity and funds.")
		description4 := getLabelCentered("Disable your profile before doing this.")
		descriptionSection := container.NewVBox(description1, description2, description3, description4)

		return descriptionSection
	}

	descriptionSection := getDescriptionSection()

	getIdentityTypeLabelOrChangeButton := func()(fyne.Widget, error){

		hostIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Host")
		if (err != nil) { return nil, err }

		moderatorIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Moderator")
		if (err != nil) { return nil, err }

		if (myIdentityType == "Mate" && hostIdentityExists == false && moderatorIdentityExists == false){
			mateLabel := getBoldLabel("Mate")
			return mateLabel, nil
		}

		getNextIdentityType := func()string{

			if (myIdentityType == "Mate"){
				if (hostIdentityExists == true){
					return "Host"
				}
				return "Moderator"		
			}
			if (myIdentityType == "Host"){
				if (moderatorIdentityExists == true){
					return "Moderator"
				}
			}
			return "Mate"
		}

		nextIdentityType := getNextIdentityType()

		changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
				setDeleteMyIdentityPage(window, nextIdentityType, previousPage)
			})

		return changeIdentityTypeButton, nil
	}

	identityTypeLabelOrChangeButton, err := getIdentityTypeLabelOrChangeButton()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	identityTypeLabelOrChangeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, identityTypeLabelOrChangeButton))

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

		// This is only reached if the user has just deleted this identity

		description4 := getBoldLabelCentered("Your " + myIdentityType + " identity does not exist.")
		description5 := getLabelCentered("There is no identity to delete.")

		page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, description4, description5, widget.NewSeparator())

		setPageContent(page, window)
		return
	}

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

	identityHashTrimmed, _, err := helpers.TrimAndFlattenString(myIdentityHashString, 10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentIdentityHashText := widget.NewLabel("Current Identity:")
	identityHashLabel := getBoldLabel(identityHashTrimmed)
	myIdentityHashRow := getContainerCentered(container.NewHBox(currentIdentityHashText, identityHashLabel))

	deleteIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Delete Identity", theme.DeleteIcon(),  func(){
			setConfirmDeleteMyIdentityPage(window, myIdentityType, currentPage, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, myIdentityHashRow, deleteIdentityButton, widget.NewSeparator())

	setPageContent(page, window)
}


func setConfirmDeleteMyIdentityPage(window fyne.Window, myIdentityType string, previousPage func(), nextPage func()){

	title := getPageTitleCentered("Confirm Delete " + myIdentityType + " Identity")

	backButton := getBackButtonCentered(previousPage)

	identityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash(myIdentityType)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (identityExists == false){
		setErrorEncounteredPage(window, errors.New("setConfirmDeleteMyIdentityPage called with missing identity."), previousPage)
		return
	}

	subtitle := getPageSubtitleCentered("Delete your " + myIdentityType + " identity?")

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator())

	if (myIdentityType == "Mate"){

		description2 := getBoldLabelCentered(translate("You will lose access to your identity balance and account funds."))
		description3 := getBoldLabelCentered(translate("This will delete your chat messages and decryption keys."))
		description4 := getLabelCentered(translate("Write down your seed phrase to retain your identity and account funds."))
		description5 := getLabelCentered(translate("Export your data to save your chat messages and decryption keys."))

		page.Add(description2)
		page.Add(description3)
		page.Add(description4)
		page.Add(description5)

	} else if (myIdentityType == "Host"){

		description2 := getBoldLabelCentered(translate("You will lose access to your identity balance and account funds."))
		description3 := getLabelCentered(translate("Write down your seed phrase to retain your identity and account funds."))

		page.Add(description2)
		page.Add(description3)

	} else if (myIdentityType == "Moderator"){

		description2 := getBoldLabelCentered(translate("You will lose access to your identity score and account funds."))
		description3 := getBoldLabelCentered(translate("This will delete your chat messages and decryption keys."))
		description4 := getLabelCentered(translate("Write down your seed phrase to retain your identity and account funds."))
		description5 := getLabelCentered(translate("Export your data to save your chat messages and decryption keys."))

		page.Add(description2)
		page.Add(description3)
		page.Add(description4)
		page.Add(description5)
	}

	description5 := getLabelCentered("This will not delete your local profile.")
	page.Add(description5)

	page.Add(widget.NewSeparator())

	if (myIdentityType != "Host"){

		//Outputs:
		//	-int: Number of messages to delete
		//	-int: Number of conversations to delete
		getMessagesToDeleteInfo := func(networkType byte)(int, int, error){

			updateProgressFunction := func(_ int)error{
				return nil
			}

			myChatMessagesMapList, err := myChatMessages.GetUpdatedMyChatMessagesMapList(myIdentityType, networkType, updateProgressFunction)
			if (err != nil) { return 0, 0, err }

			numberOfMessagesToDelete := len(myChatMessagesMapList)

			//Map Structure: Recipient Identity Hash -> Nothing
			conversationRecipientsMap := make(map[string]struct{})

			for _, messageMap := range myChatMessagesMapList{
				theirIdentityHash, exists := messageMap["TheirIdentityHash"]
				if (exists == false) {
					return 0, 0, errors.New("Malformed myChatMessages map list: Item missing TheirIdentityHash")
				}

				conversationRecipientsMap[theirIdentityHash] = struct{}{}
			}

			numberOfConversationsToDelete := len(conversationRecipientsMap)

			return numberOfMessagesToDelete, numberOfConversationsToDelete, nil
		}

		numberOfMessagesToDelete_Network1, numberOfConversationsToDelete_Network1, err := getMessagesToDeleteInfo(1)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}

		numberOfMessagesToDelete_Network2, numberOfConversationsToDelete_Network2, err := getMessagesToDeleteInfo(2)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}

		numberOfMessagesToDelete := numberOfMessagesToDelete_Network1 + numberOfMessagesToDelete_Network2
		numberOfConversationsToDelete := numberOfConversationsToDelete_Network1 + numberOfConversationsToDelete_Network2

		if (numberOfMessagesToDelete != 0){

			thisWillDeleteLabel := widget.NewLabel("This will delete")

			numberOfMessagesString := helpers.ConvertIntToString(numberOfMessagesToDelete)
			numberOfMessagesLabel := getBoldLabel(numberOfMessagesString)

			getMessageOrMessagesText := func()string{
				if (numberOfMessagesToDelete == 1){
					return "message"	
				}
				return "messages"
			}
			messageOrMessagesText := getMessageOrMessagesText()
			messagesAndLabel := widget.NewLabel(messageOrMessagesText + " and")

			numberOfConversationsString := helpers.ConvertIntToString(numberOfConversationsToDelete)
			numberOfConversationsLabel := getBoldLabel(numberOfConversationsString)

			getConversationOrConversationsText := func()string{
				if (numberOfConversationsToDelete == 1){
					return "conversation"
				}
				return "conversations"
			}
			conversationOrConversationsText := getConversationOrConversationsText()
			conversationsLabel := widget.NewLabel(conversationOrConversationsText)

			chatDeleteWarningRow := container.NewHBox(layout.NewSpacer(), thisWillDeleteLabel, numberOfMessagesLabel, messagesAndLabel, numberOfConversationsLabel, conversationsLabel, layout.NewSpacer())

			page.Add(chatDeleteWarningRow)
			page.Add(widget.NewSeparator())
		}
	}

	//TODO: Show account funds balance

	if (myIdentityType == "Mate"){
		description6 := getLabelCentered("Disable your profile before doing this on the Profile - Broadcast page.")
		description7 := getLabelCentered("Otherwise, it will automatically expire from the network in 3 months.")

		page.Add(description6)
		page.Add(description7)
		page.Add(widget.NewSeparator())

	} else if (myIdentityType == "Host"){

		description6 := getLabelCentered("Disable your profile before doing this on the Profile - Broadcast page.")
		description7 := getLabelCentered("Otherwise, users will keep trying to connect to your inactive host address.")
		//TODO: Retrieve true expiration time from parameters
		description8 := getLabelCentered("This should stop after 6 hours, when your profile expires.")

		page.Add(description6)
		page.Add(description7)
		page.Add(description8)
		page.Add(widget.NewSeparator())
	}

	deleteIdentityFunction := func()error{

		err := myBroadcasts.DeleteMyBroadcastProfiles(myIdentityHash)
		if (err != nil) { return err }

		if (myIdentityType != "Host"){

			err := myChatMessages.DeleteMyChatMessagesMapList(myIdentityType)
			if (err != nil) { return err }

			err = mySettings.SetSetting(myIdentityType + "ChatConversationsGeneratedStatus", "No")
			if (err != nil) { return err }

			//TODO: Delete secret inboxes
			//TODO: Delete saved message cipher keys
			//TODO: Delete everything else relevant
		}

		err = mySeedPhrases.DeleteMySeedPhrase(myIdentityType)
		if (err != nil) { return err }

		return nil
	}

	confirmDeleteIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Delete Identity", theme.DeleteIcon(), func(){
			err := deleteIdentityFunction()
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
			}
			nextPage()
		}))

	page.Add(confirmDeleteIdentityButton)

	setPageContent(page, window)
}

func setImportMyIdentityPage(window fyne.Window, myIdentityType string, previousPage func()){

	if (myIdentityType != "Mate" && myIdentityType != "Host" && myIdentityType != "Moderator"){
		setErrorEncounteredPage(window, errors.New("setImportMyIdentityPage called with invalid identity type: " + myIdentityType), previousPage)
		return	
	}

	currentPage := func(){setImportMyIdentityPage(window, myIdentityType, previousPage)}

	title := getPageTitleCentered(translate("Import Identity"))

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Import your " + myIdentityType + " identity from a seed phrase.")

	getNextIdentityType := func()string{
		if (myIdentityType == "Mate"){
			return "Host"
		}
		if (myIdentityType == "Host"){
			return "Moderator"
		}
		return "Mate"
	}

	nextIdentityType := getNextIdentityType()

	identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
			setImportMyIdentityPage(window, nextIdentityType, previousPage)
		})

	changeIdentityTypeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, changeIdentityTypeButton))

	identityExists, _, err := mySeedPhrases.GetMySeedPhrase(myIdentityType)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	if (identityExists == true){

		description2 := getBoldLabelCentered("Your " + myIdentityType + " identity exists.")
		description3 := getLabelCentered("You must delete it before restoring a new identity.")
		description4 := getLabelCentered("Delete your identity on the Settings - My Data - Delete Identity page")
		
		page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), changeIdentityTypeButtonWithIcon, description2, description3, description4)

		setPageContent(page, window)
		return
	}

	seedPhraseEntry := widget.NewMultiLineEntry()
	seedPhraseEntry.Wrapping = 3
	seedPhraseEntry.SetPlaceHolder(translate("Enter seed phrase to import..."))

	seedPhraseEntryBoxed := getWidgetBoxed(seedPhraseEntry)

	submitSeedButton := getWidgetCentered(widget.NewButtonWithIcon(translate("Import " + myIdentityType + " Identity"), theme.UploadIcon(), func(){

			newSeedPhrase := seedPhraseEntry.Text

			seedPhraseIsValid := seedPhrase.VerifySeedPhrase(newSeedPhrase)
			if (seedPhraseIsValid == false){
				dialogTitle := translate("Invalid Seed Phrase")
				dialogMessageA := getLabelCentered("Your seed phrase is invalid.")
				dialogMessageB := getLabelCentered("A Seekia seed phrase is 15 words long.")
				dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			err = mySeedPhrases.SetMySeedPhrase(myIdentityType, newSeedPhrase)
			if (err != nil) {
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			setViewMySeedPhrasesPage(window, myIdentityType, previousPage)
		}))

	widener := widget.NewLabel("                                                                              ")
	heightener := widget.NewLabel("")
	submitSeedButtonWithWidener := container.NewVBox(submitSeedButton, widener, heightener)

	entryWithSubmitSeedButton := getContainerCentered(container.NewGridWithColumns(1, seedPhraseEntryBoxed, submitSeedButtonWithWidener))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), changeIdentityTypeButtonWithIcon, entryWithSubmitSeedButton)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("App Themes"))

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Choose your Seekia app theme.")

	getThemeButtonsGrid := func()(*fyne.Container, error){

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

			exists, currentTheme, err := globalSettings.GetSetting("AppTheme")
			if (err != nil){ return "", err }
			if (exists == false){
				return "Light", nil
			}
			return currentTheme, nil
		}

		currentAppTheme, err := getCurrentAppTheme()
		if (err != nil){ return nil, err }

		getThemeButtonWithIcon := func(themeName string, themeIconName string)(*fyne.Container, error){

			themeIcon, err := getFyneImageIcon(themeIconName)
			if (err != nil) { return nil, err }

			chooseThemeButton := widget.NewButton(translate(themeName), func(){

					_ = globalSettings.SetSetting("AppTheme", themeName)

					customTheme, _ := getCustomFyneTheme(themeName)

					app := fyne.CurrentApp()

					app.Settings().SetTheme(customTheme)

					currentPage()
				})

			if (themeName == currentAppTheme){
				chooseThemeButton.Importance = widget.HighImportance
			}

			buttonWithIcon := getContainerCentered(container.NewGridWithColumns(1, themeIcon, chooseThemeButton))

			return buttonWithIcon, nil
		}

		lightThemeButton, err := getThemeButtonWithIcon("Light", "Sun")
		if (err != nil) { return nil, err }

		darkThemeButton, err := getThemeButtonWithIcon("Dark", "Moon")
		if (err != nil) { return nil, err }

		loveThemeButton, err := getThemeButtonWithIcon("Love", "Mate")
		if (err != nil) { return nil, err }

		oceanThemeButton, err := getThemeButtonWithIcon("Ocean", "Ocean")
		if (err != nil) { return nil, err }

		buttonsGrid := container.NewGridWithColumns(2, lightThemeButton, darkThemeButton, loveThemeButton, oceanThemeButton)

		return buttonsGrid, nil
	}

	themeButtonsGrid, err := getThemeButtonsGrid()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	themeButtonsGridCentered := getContainerCentered(themeButtonsGrid)

	//TODO: Add a way to create a custom theme within the GUI

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), themeButtonsGridCentered)	

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("Navigation Settings"))

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Manage your navigation settings.")

	showButtonTextColumn := container.NewVBox()
	showButtonChecksColumn := container.NewVBox()

	addShowButtonCheckRow := func(showButtonText string, settingName string)error{

		showButtonTextLabel := getBoldLabelCentered(showButtonText)

		showButtonCheck := widget.NewCheck("", func(selected bool){

				yesOrNoString := helpers.ConvertBoolToYesOrNoString(selected)

				err := mySettings.SetSetting(settingName, yesOrNoString)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}

				currentPage()
			})

		exists, showButtonCurrent, err := mySettings.GetSetting(settingName)
		if (err != nil) { return err }
		if (exists == true && showButtonCurrent == "Yes"){
			showButtonCheck.Checked = true
		}

		showButtonTextColumn.Add(showButtonTextLabel)
		showButtonChecksColumn.Add(showButtonCheck)

		return nil
	}

	err := addShowButtonCheckRow("Show Host Button", "ShowHostButtonNavigation")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	showButtonTextColumn.Add(widget.NewSeparator())
	showButtonChecksColumn.Add(widget.NewSeparator())
	
	err = addShowButtonCheckRow("Show Moderate Button", "ShowModerateButtonNavigation")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	showButtonChecksGrid := container.NewHBox(layout.NewSpacer(), showButtonTextColumn, showButtonChecksColumn, layout.NewSpacer())

	navigationLocationLabel := getLabelCentered("Navigation Bar Location:")

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

		exists, currentNavigationLocation, err := mySettings.GetSetting("NavigationBarLocation")
		if (err != nil){ return "", err }
		if (exists == false){
			return "Top", nil
		}

		if (currentNavigationLocation != "Top" && currentNavigationLocation != "Bottom" && currentNavigationLocation != "Left" && currentNavigationLocation != "Right"){
			return "", errors.New("Invalid navigation bar location: " + currentNavigationLocation)
		}

		return currentNavigationLocation, nil
	}

	currentNavigationLocation, err := getMyCurrentNavigationBarLocation()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	option1Translated := translate("Top")
	option2Translated := translate("Bottom")
	option3Translated := translate("Left")
	option4Translated := translate("Right")

	untranslatedOptionsMap := map[string]string{
		option1Translated: "Top",
		option2Translated: "Bottom",
		option3Translated: "Left",
		option4Translated: "Right",
	}

	locationOptionsList := []string{option1Translated, option2Translated, option3Translated, option4Translated}

	locationSelector := widget.NewSelect(locationOptionsList, func(response string){
	
			responseUntranslated, exists := untranslatedOptionsMap[response]
			if (exists == false){
				setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing response: " + response), currentPage)
				return
			}

			if (responseUntranslated == currentNavigationLocation){
				return
			}

			err = mySettings.SetSetting("NavigationBarLocation", responseUntranslated)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}

			currentPage()
		})

	locationSelector.Selected = currentNavigationLocation

	locationSelectorCentered := getWidgetCentered(locationSelector)

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), showButtonChecksGrid, widget.NewSeparator(), navigationLocationLabel, locationSelectorCentered)	

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("Content Filtering Settings"))

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Manage your content filtering settings.")

	pixelateImagesButton := getWidgetCentered(widget.NewButton("Pixelate Images", func(){
			setManagePixelateImagesSettingPage(window, currentPage)
		}))

	// TODO: Add ability to mute/block/censor words?

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), pixelateImagesButton)
	
	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered("Pixelate Images Setting")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Seekia can pixelate the images you receive in messages.")
	description2 := getLabelCentered("You must slowly reveal the image by incrementally depixelating the image.")
	description3 := getLabelCentered("If you are not afraid of seeing unreviewed images, you can disable this feature.")

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

		exists, currentSetting, err := mySettings.GetSetting("PixelateImagesOnOffStatus")
		if (err != nil) { return "", err }
		if (exists == false){
			return "On", nil
		}
		return currentSetting, nil
	}

	currentStatus, err := getCurrentStatus()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentStatusTitle := widget.NewLabel("Current Status: ")
	currentStatusLabel := getBoldLabel(currentStatus)

	currentStatusRow := container.NewHBox(layout.NewSpacer(), currentStatusTitle, currentStatusLabel, layout.NewSpacer())

	getEnableOrDisableButton := func()fyne.Widget{

		if (currentStatus == "On"){

			disableButton := widget.NewButton("Disable", func(){
					err := mySettings.SetSetting("PixelateImagesOnOffStatus", "Off")
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
				})
			
			return disableButton
		}

		enableButton := widget.NewButton("Enable", func(){
				err := mySettings.SetSetting("PixelateImagesOnOffStatus", "On")
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
			})

		return enableButton
	}

	enableOrDisableButton := getEnableOrDisableButton()

	enableOrDisableButtonCentered := getWidgetCentered(enableOrDisableButton)

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

	setPageContent(page, window)
}

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

	appMemory.SetMemoryEntry("CurrentViewedPage", "ManageNetworkConnection")

	title := getPageTitleCentered("Manage Network Connection")

	//TODO
	//	Enable download profiles over clearnet mode
	//		This should not be possible for messages, only profiles
	//	Disable Tor mode (if using system-wide tor proxy already, such as Whonix. We can autodetect if user is using Whonix)
	//	Add HiddenServiceOnly mode so users can only download messages over .onion rather than using exit nodes to access clearnet hosts?

	backButton := getBackButtonCentered(previousPage)

	description := getBoldLabelCentered("Under Construction")

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description)

	setPageContent(page, window)
}

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

	setLoadingScreen(window, "Manage Storage", "Loading Manage Storage Page...") 

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

	title := getPageTitleCentered(translate("Manage Storage"))

	backButton := getBackButtonCentered(previousPage)

	getAllowedStorageGigabytes := func()(float64, error){	

		exists, allowedStorageSpaceString, err := globalSettings.GetSetting("AllowedStorageSpace")
		if (err != nil){ return 0, err }
		if (exists == false){

			//We default to 10 gigabytes

			return 10, nil
		}
		allowedStorageSpaceFloat, err := helpers.ConvertStringToFloat64(allowedStorageSpaceString)
		if (err != nil){
			return 0, errors.New("MySettings contains invalid AllowedStorageSpace: " + allowedStorageSpaceString)
		}

		return allowedStorageSpaceFloat, nil
	}

	allowedStorageSpace, err := getAllowedStorageGigabytes()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	databaseDirectory, err := localFilesystem.GetAppDatabaseFolderPath()
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	databaseSizeBytes, err := localFilesystem.GetFolderSizeInBytes(databaseDirectory)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	// TODO: Change to use actual gigabyte size
	databaseSizeGigabytes := float64(databaseSizeBytes)/1000000000

	allowedStorageSpaceString := helpers.ConvertFloat64ToStringRounded(allowedStorageSpace, 2)

	databaseSizeString := helpers.ConvertFloat64ToStringRounded(databaseSizeGigabytes, 1)

	percentageOfSpaceUsed := (databaseSizeGigabytes/allowedStorageSpace)*100

	percentageOfSpaceUsedString := helpers.ConvertFloat64ToStringRounded(percentageOfSpaceUsed, 0)

	spaceUsedTitle := getLabelCentered("Storage Space Used:")
	spaceUsedLabel := getBoldLabelCentered(databaseSizeString + "/" + allowedStorageSpaceString + " gigabytes" + " (" + percentageOfSpaceUsedString + "%)")

	numberOfStoredProfiles, err := profileStorage.GetNumberOfStoredProfiles()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	numberOfStoredProfilesString := helpers.ConvertInt64ToString(numberOfStoredProfiles)
	numberOfStoredProfilesLabel := widget.NewLabel("Stored Profiles:")
	numberOfStoredProfilesText := getBoldLabel(numberOfStoredProfilesString)
	numberOfStoredProfilesRow := container.NewHBox(layout.NewSpacer(), numberOfStoredProfilesLabel, numberOfStoredProfilesText, layout.NewSpacer())

	numberOfStoredMessages, err := chatMessageStorage.GetNumberOfStoredMessages()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	numberOfStoredMessagesString := helpers.ConvertInt64ToString(numberOfStoredMessages)

	numberOfStoredMessagesLabel := widget.NewLabel("Stored Messages:")
	numberOfStoredMessagesText := getBoldLabel(numberOfStoredMessagesString)
	numberOfStoredMessagesRow := container.NewHBox(layout.NewSpacer(), numberOfStoredMessagesLabel, numberOfStoredMessagesText, layout.NewSpacer())

	numberOfStoredReviews, err := reviewStorage.GetNumberOfStoredReviews()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	numberOfStoredReviewsString := helpers.ConvertInt64ToString(numberOfStoredReviews)

	numberOfStoredReviewsLabel := widget.NewLabel("Stored Reviews:")
	numberOfStoredReviewsText := getBoldLabel(numberOfStoredReviewsString)
	numberOfStoredReviewsRow := container.NewHBox(layout.NewSpacer(), numberOfStoredReviewsLabel, numberOfStoredReviewsText, layout.NewSpacer())

	numberOfStoredReports, err := reportStorage.GetNumberOfStoredReports()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	numberOfStoredReportsString := helpers.ConvertInt64ToString(numberOfStoredReports)

	numberOfStoredReportsLabel := widget.NewLabel("Stored Reports:")
	numberOfStoredReportsText := getBoldLabel(numberOfStoredReportsString)
	numberOfStoredReportsRow := container.NewHBox(layout.NewSpacer(), numberOfStoredReportsLabel, numberOfStoredReportsText, layout.NewSpacer())

	
	freeUpSpaceButton := widget.NewButton("Free Up Space", func(){
			//TODO: A page to manually prune data
			// This should also be happening automatically by backgroundJobs
			showUnderConstructionDialog(window)
		})
	
	allowedSpaceButton := widget.NewButton("Manage Allowed Space", func(){
			setManageAllowedStorageSpacePage(window, currentPage)
		})

	changeDownloadsDirectoryButton := widget.NewButton("Change Database Location", func(){
			setManageDatabaseLocationPage(window, currentPage)
		})

	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, freeUpSpaceButton, allowedSpaceButton, changeDownloadsDirectoryButton))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), spaceUsedTitle, spaceUsedLabel, widget.NewSeparator(), numberOfStoredProfilesRow, numberOfStoredMessagesRow, numberOfStoredReviewsRow, numberOfStoredReportsRow, widget.NewSeparator(), buttonsGrid)
	
	setPageContent(page, window)
}

func setManageAllowedStorageSpacePage(window fyne.Window, previousPage func()){
	
	currentPage := func(){setManageAllowedStorageSpacePage(window, previousPage)}

	title := getPageTitleCentered(translate("Manage Allowed Storage Space"))

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Select the amount of storage space Seekia is allowed to use.")

	getCurrentAllowedSpace := func()(float64, error){

		exists, currentAllowedStorageSpace, err := globalSettings.GetSetting("AllowedStorageSpace")
		if (err != nil){ return 0, err }
		if (exists == false){
			// Default to 10 GB
			return 10, nil
		}

		currentAllowedSpaceFloat64, err := helpers.ConvertStringToFloat64(currentAllowedStorageSpace)
		if (err != nil) {
			return 0, errors.New("MyGlobalSettings Malformed: Contains invalid AllowedStorageSpace: " + currentAllowedStorageSpace)
		}

		return currentAllowedSpaceFloat64, nil
	}

	currentAllowedSpaceFloat64, err := getCurrentAllowedSpace()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentAllowedSpaceString := helpers.ConvertFloat64ToStringRounded(currentAllowedSpaceFloat64, 2)

	allowedStorageSpaceLabel := getLabelCentered("Allowed storage space:")
	allowedStorageSpaceText := getBoldLabelCentered(currentAllowedSpaceString + " gigabytes")

	allowedStorageSpaceGigabytesText := getLabelCentered("Enter a new allowed amount in gigabytes:")

	allowedStorageSpaceEntry := widget.NewEntry()
	allowedStorageSpaceEntry.Text = currentAllowedSpaceString

	allowedStorageSpaceSubmitButton := widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){

			newSize := allowedStorageSpaceEntry.Text
	
			if (newSize == ""){
				dialogTitle := translate("Invalid Size.")
				dialogMessage := getLabelCentered(translate("Your must enter a new allowed amount."))
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}
			newSizeFloat64, err := helpers.ConvertStringToFloat64(newSize)
			if (err != nil){
				dialogTitle := translate("Invalid Size.")
				dialogMessage := getLabelCentered(translate("Your new maximum size must be a number."))
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			if (newSizeFloat64 < 3){
				dialogTitle := translate("Invalid Size.")
				dialogMessage := getLabelCentered(translate("Your new maximum size must be at least 3 GB."))
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			err = globalSettings.SetSetting("AllowedStorageSpace", newSize)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		})

	allowedStorageSpaceEntryRow := getContainerCentered(container.NewGridWithRows(1, allowedStorageSpaceEntry, allowedStorageSpaceSubmitButton))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), allowedStorageSpaceLabel, allowedStorageSpaceText, widget.NewSeparator(), allowedStorageSpaceGigabytesText, allowedStorageSpaceEntryRow)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("Manage Database Location"))

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Use this page to change the location of the Seekia database.")
	description2 := getLabelCentered("After changing the location, close Seekia.")
	description3 := getLabelCentered("Then, you must manually move the existing database folder contents to the new location.")	
	description4 := getLabelCentered("Upon starting Seekia again, all existing data should be available.")
	description5 := getLabelCentered("If you don't copy the folder, you will still retain your user data.")

	databaseDirectory, err := localFilesystem.GetAppDatabaseFolderPath()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentLocationLabel := getLabelCentered("Current Database Directory:")

	currentLocationText := getBoldLabelCentered(databaseDirectory)

	resetLocation := widget.NewButtonWithIcon("Reset To Original", theme.ContentUndoIcon(), func(){

			confirmDialogCallbackFunction := func(response bool){
				if (response == false){
					return		
				}

				err := globalSettings.DeleteSetting("DatabaseFolderpath")
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}

				currentPage()
			}

			dialogTitle := translate("Confirm Reset Database Location?")
			dialogMessageA := getLabelCentered("Confirm to reset the database location?")
			dialogMessageB := getLabelCentered("You must restart Seekia for the change to take effect.")
			dialogMessageC := getLabelCentered("Move your existing database to the new location before starting Seekia again.")
			dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
			dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)	
		})

	selectNewLocationButton := widget.NewButtonWithIcon("Select New Location", theme.FolderIcon(), func(){

			folderOpenCallbackFunction := func(folderObject fyne.ListableURI, err error){

				if (err != nil) {
					title := translate("Failed To Open Folder Path.")
					dialogMessage := getLabelCentered(translate("Report this error to Seekia developers: " + err.Error()))
					dialogContent := container.NewVBox(dialogMessage)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				if (folderObject == nil){
					return
				}

				folderPath := folderObject.Path()

				err = globalSettings.SetSetting("DatabaseFolderpath", folderPath)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
			}

			dialog.ShowFolderOpen(folderOpenCallbackFunction, window)
		})

	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, resetLocation, selectNewLocationButton))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), currentLocationLabel, currentLocationText, widget.NewSeparator(), buttonsGrid)

	setPageContent(page, window)
}
/*
func setSyncSettingsPage(window fyne.Window, previousPage func()){

	title := getPageTitleCentered(translate("Sync Settings"))
	backButton := getBackButtonCentered(previousPage)

	underConstructionLabel := getBoldLabelCentered("Under construction.")

	//TODO

	page := container.NewVBox(title, backButton, widget.NewSeparator(), underConstructionLabel)

	setPageContent(page, window)
}
*/

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

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

		exists, currentAppCurrency, err := globalSettings.GetSetting("Currency")
		if (err != nil) { return "", err }
		if (exists == false){
			return "USD", nil
		}

		return currentAppCurrency, nil
	}

	onSelectFunction := func(newCurrencyCode string)error{

			err := globalSettings.SetSetting("Currency", newCurrencyCode)
			if (err != nil){ return err }

			return nil
		}

	setChooseCurrencyPage(window, getCurrentCurrencyFunction, onSelectFunction, previousPage) 
}


func setChooseCurrencyPage(window fyne.Window, getCurrentCurrencyFunction func()(string, error), onSelectFunction func(string)error, previousPage func()){

	currentPage := func(){setChooseCurrencyPage(window, getCurrentCurrencyFunction, onSelectFunction, previousPage)}

	title := getPageTitleCentered(translate("Choose Currency"))

	backButton := getBackButtonCentered(previousPage)

	currentCurrencyCode, err := getCurrentCurrencyFunction()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentCurrencyName, currentCurrencySymbol, err := currencies.GetCurrencyInfoFromCurrencyCode(currentCurrencyCode)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	
	currentCurrencyLabel := getLabelCentered("Current Currency:")
	currentCurrencyText := getBoldLabelCentered(currentCurrencySymbol + " - " + currentCurrencyName + " - " + currentCurrencyCode)

	chooseCurrencyLabel := getItalicLabelCentered("Choose Currency:")

	allCurrencyObjectsList, err := currencies.GetCurrencyObjectsList()
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	allCurrencyDescriptionsList := make([]string, 0, len(allCurrencyObjectsList))
	allCurrencyCodesList := make([]string, 0, len(allCurrencyObjectsList))

	for _, currencyObject := range allCurrencyObjectsList{

		currencyName := currencyObject.Name
		currencySymbol := currencyObject.Symbol
		currencyCode := currencyObject.Code

		currencyNameTranslated := translate(currencyName)

		currencyDescription := currencySymbol + " - " + currencyNameTranslated + " - " + currencyCode

		allCurrencyDescriptionsList = append(allCurrencyDescriptionsList, currencyDescription)
		allCurrencyCodesList = append(allCurrencyCodesList, currencyCode)
	}

	onSelectedFunction := func(currencyIndex int) {

		selectedCurrencyCode := allCurrencyCodesList[currencyIndex]

		err := onSelectFunction(selectedCurrencyCode)
		if (err != nil){
			setErrorEncounteredPage(window, err, currentPage)
			return
		}

		currentPage()
	}

	widgetList, err := getFyneWidgetListFromStringList(allCurrencyDescriptionsList, onSelectedFunction)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}	

	header := container.NewVBox(title, backButton, widget.NewSeparator(), currentCurrencyLabel, currentCurrencyText, widget.NewSeparator(), chooseCurrencyLabel, widget.NewSeparator())

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

	setPageContent(page, window)
}

func setViewLogsPage(window fyne.Window, logType string, previousPage func()){

	if (logType != "General" && logType != "Network" && logType != "BackgroundJobs"){
		setErrorEncounteredPage(window, errors.New("setViewLogsPage called with invalid logType: " + logType), previousPage)
		return	
	}

	currentPage := func(){setViewLogsPage(window, logType, previousPage)}

	title := getPageTitleCentered("Logs")

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("View Seekia logs.")

	logTypeLabel := getBoldLabelCentered("Log Type:")

	logTypesList := []string{translate("General"), translate("Network"), translate("Background Jobs")}

	logTypeSelector := widget.NewSelect(logTypesList, func(selection string){

			if (selection == translate("General")){

				setViewLogsPage(window, "General", previousPage)

			} else if (selection == translate("Network")){

				setViewLogsPage(window, "Network", previousPage)

			} else if (selection == translate("Background Jobs")){
		
				setViewLogsPage(window, "BackgroundJobs", previousPage)
			}
		})

	if (logType == "General"){

		logTypeSelector.Selected = translate("General")

	} else if (logType == "Network"){

		logTypeSelector.Selected = translate("Network")

	} else if (logType == "BackgroundJobs"){

		logTypeSelector.Selected = translate("Background Jobs")
	}

	logTypeSelectorCentered := getWidgetCentered(logTypeSelector)

	logList, err := logger.GetLogList(logType)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	if (len(logList) == 0){

		noLogsExistLabel := getBoldLabelCentered("No log entries exist.")

		refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))

		page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), logTypeLabel, logTypeSelectorCentered, widget.NewSeparator(), noLogsExistLabel, refreshButton)

		setPageContent(page, window)
		return
	}

	trimmedLogList := make([]string, 0, len(logList))

	for _, logText := range logList{

		trimmedText, _, err := helpers.TrimAndFlattenString(logText, 30)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}

		trimmedLogList = append(trimmedLogList, trimmedText)
	}

	onClickedFunction := func(selectedIndex int){

		logText := logList[selectedIndex]

		setViewTextPage(window, "Viewing Log", logText, false, currentPage)
	}

	logsWidgetList, err := getFyneWidgetListFromStringList(logList, onClickedFunction)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))

	header := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), logTypeLabel, logTypeSelectorCentered, widget.NewSeparator())

	page := container.NewBorder(header, refreshButton, nil, nil, logsWidgetList)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered("Developer Settings")

	backButton := getBackButtonCentered(previousPage)

	networkTypeButton := getWidgetCentered(widget.NewButton("Network Type", func(){
			setViewAppNetworkTypePage(window, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), networkTypeButton)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered("Network Type")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Your Seekia application can interact with different network types.")
	description2 := getLabelCentered("There are 2 network types: Mainnet and Testnet 1.")
	description3 := getLabelCentered("You can change your app network type to interact with a different network.")
	description4 := getLabelCentered("You should use Testnet 1 when testing new releases of Seekia before they are versioned.")

	currentNetworkType, err := getAppNetworkType.GetAppNetworkType()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	getCurrentNetworkTypeString := func()(string, error){
		if (currentNetworkType == 1){
			return "Mainnet", nil
		}
		if (currentNetworkType == 2){
			return "Testnet 1", nil
		}

		currentNetworkTypeString := helpers.ConvertByteToString(currentNetworkType)

		return "", errors.New("GetAppNetworkType returning invalid network type: " + currentNetworkTypeString)
	}

	currentNetworkTypeString, err := getCurrentNetworkTypeString()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentNetworkTypeLabel := widget.NewLabel("Current Network Type:")

	currentNetworkTypeText := getBoldLabel(currentNetworkTypeString)

	currentNetworkTypeRow := container.NewHBox(layout.NewSpacer(), currentNetworkTypeLabel, currentNetworkTypeText, layout.NewSpacer())

	changeNetworkTypeButton := getWidgetCentered(widget.NewButtonWithIcon("Change Network Type", theme.NavigateNextIcon(), func(){
			setChooseNewAppNetworkTypePage(window, currentPage)
		}))

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

	setPageContent(page, window)
}


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

	title := getPageTitleCentered("Choose Network Type")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("Choose your new network type.")
	description2 := getLabelCentered("This change will impact your matches and chat conversations.")
	description3 := getLabelCentered("Your client will automatically delete content for other network types from the database.")
	description4 := getLabelCentered("Your broadcasted content and messages will not be deleted.")
	description5 := getLabelCentered("This change will take effect for all of your app users.")

	currentNetworkType, err := getAppNetworkType.GetAppNetworkType()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	chooseMainnetButton := widget.NewButton("Mainnet", func(){
			if (currentNetworkType == 1){
				dialogTitle := translate("Cannot Change Network Type")
				dialogMessageA := getLabelCentered("This network type is already your current app network type.")
				dialogContent := container.NewVBox(dialogMessageA)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			setChangeAppNetworkTypePage(window, 1, previousPage)
		})
	if (currentNetworkType == 1){
		chooseMainnetButton.Importance = widget.HighImportance
	}

	chooseTestnet1Button := widget.NewButton("Testnet 1", func(){
			if (currentNetworkType == 2){
				dialogTitle := translate("Cannot Change Network Type")
				dialogMessageA := getLabelCentered("This network type is already your current app network type.")
				dialogContent := container.NewVBox(dialogMessageA)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			setChangeAppNetworkTypePage(window, 2, previousPage)
		})

	if (currentNetworkType == 2){
		chooseTestnet1Button.Importance = widget.HighImportance
	}

	chooseNetworkTypesGrid := getContainerCentered(container.NewGridWithColumns(1, chooseMainnetButton, chooseTestnet1Button))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), chooseNetworkTypesGrid)
	
	setPageContent(page, window)
}


func setChangeAppNetworkTypePage(window fyne.Window, newAppNetworkType byte, nextPage func()){

	isValid := helpers.VerifyNetworkType(newAppNetworkType)
	if (isValid == false){
		newAppNetworkTypeString := helpers.ConvertByteToString(newAppNetworkType)
		setErrorEncounteredPage(window, errors.New("setChangeAppNetworkTypePage called with invalid newAppNetworkType: " + newAppNetworkTypeString), nextPage)
		return
	}

	title := getPageTitleCentered("Changing Network Type")

	description := getLabelCentered("Changing network type...")

	progressBar := getWidgetCentered(widget.NewProgressBarInfinite())

	page := container.NewVBox(title, widget.NewSeparator(), description, progressBar)

	window.SetContent(page)

	err := setAppNetworkType.SetAppNetworkType(newAppNetworkType)
	if (err != nil){
		setErrorEncounteredPage(window, err, nextPage)
		return
	}

	nextPage()
}



