package gui

//desiresGui_General.go implements pages to view and manage a user's General mate desires, view all their desires, and manage their download desires

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/allowedText"
import "seekia/internal/appMemory"
import "seekia/internal/desires/mateDesires"
import "seekia/internal/desires/myLocalDesires"
import "seekia/internal/encoding"
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "seekia/internal/network/myMateCriteria"
import "seekia/internal/profiles/attributeDisplay"
import "seekia/internal/worldLanguages"
import "seekia/internal/worldLocations"

import "strings"
import "errors"
import "slices"

func setDesiresPage(window fyne.Window){

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

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

	title := getPageTitleCentered(translate("My Mate Desires"))

	description1 := getLabelCentered(translate("Select your Mate desires."))
	description2 := getLabelCentered(translate("Your desires are used to generate your matches."))
	description3 := getLabelCentered(translate("These desires not shared on your profile."))

	generalIcon, err := getFyneImageIcon("General")
	if (err != nil){
		setErrorEncounteredPage(window, err, func(){setHomePage(window)})
		return
	}
	generalButton := widget.NewButton(translate("General"), func(){
			setChooseDesiresCategoryPage_General(window, currentPage)
		})
	generalButtonWithIcon := container.NewGridWithRows(2, generalIcon, generalButton)

	physicalIcon, err := getFyneImageIcon("Person")
	if (err != nil){
		setErrorEncounteredPage(window, err, func(){setHomePage(window)})
		return
	}
	physicalButton := widget.NewButton(translate("Physical"), func(){
			setChooseDesiresCategoryPage_Physical(window, currentPage)
		})
	physicalButtonWithIcon := container.NewGridWithRows(2, physicalIcon, physicalButton)

	lifestyleIcon, err := getFyneImageIcon("Lifestyle")
	if (err != nil){
		setErrorEncounteredPage(window, err, func(){setHomePage(window)})
		return
	}
	lifestyleButton := widget.NewButton(translate("Lifestyle"), func(){
			setChooseDesiresCategoryPage_Lifestyle(window, currentPage)
		})
	lifestyleButtonWithIcon := container.NewGridWithRows(2, lifestyleIcon, lifestyleButton)

	mentalIcon, err := getFyneImageIcon("Mental")
	if (err != nil){
		setErrorEncounteredPage(window, err, func(){setHomePage(window)})
		return
	}
	mentalButton := widget.NewButton(translate("Mental"), func(){
			setChooseDesiresCategoryPage_Mental(window, currentPage)
		})
	mentalButtonWithIcon := container.NewGridWithRows(2, mentalIcon, mentalButton)
	
	categoriesRow := getContainerCentered(container.NewGridWithRows(1, generalButtonWithIcon, physicalButtonWithIcon, lifestyleButtonWithIcon, mentalButtonWithIcon))

	allDesiresIcon, err := getFyneImageIcon("Choice")
	if (err != nil){
		setErrorEncounteredPage(window, err, func(){setHomePage(window)})
		return
	}

	viewAllDesiresButton := widget.NewButton("View All Desires", func(){
			setViewAllMyDesiresPage(window, currentPage)
		})

	viewAllDesiresButtonWithIcon := container.NewGridWithRows(2, allDesiresIcon, viewAllDesiresButton)

	statisticsIcon, err := getFyneImageIcon("Stats")
	if (err != nil){
		setErrorEncounteredPage(window, err, func(){setHomePage(window)})
		return
	}

	viewAllStatisticsButton := widget.NewButton("View All Statistics", func(){
			setViewAllMyDesireStatisticsPage(window, false, 0, 0, nil, currentPage)
		})

	viewAllStatisticsButtonWithIcon := container.NewGridWithColumns(1, statisticsIcon, viewAllStatisticsButton)

	viewAllButtonsRow := getContainerCentered(container.NewGridWithRows(1, viewAllDesiresButtonWithIcon, viewAllStatisticsButtonWithIcon))

	downloadDesiresIcon, err := getFyneImageIcon("Host")
	if (err != nil){
		setErrorEncounteredPage(window, err, func(){setHomePage(window)})
		return
	}
	downloadDesiresButton := widget.NewButton("Download Desires", func(){
			setManageMateDownloadDesiresPage(window, currentPage)
		})

	downloadDesiresButtonWithIcon := getContainerCentered(container.NewGridWithRows(2, downloadDesiresIcon, downloadDesiresButton))

	page := container.NewVBox(title, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), categoriesRow, widget.NewSeparator(), viewAllButtonsRow, widget.NewSeparator(), downloadDesiresButtonWithIcon)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	profileLanguageButton := widget.NewButton("Profile Language", func(){
			setChooseDesiresPage_ProfileLanguage(window, currentPage)
		})

	ageButton := widget.NewButton(translate("Age"), func(){
			setChooseDesiresPage_Age(window, currentPage)
		})

	distanceButton := widget.NewButton("Distance", func(){
			setChooseDesiresPage_Distance(window, currentPage)
		})

	countryButton := widget.NewButton("Country", func(){
			setChooseDesiresPage_Country(window, currentPage)
		})

	sexualityButton := widget.NewButton("Sexuality", func(){
			setChooseDesiresPage_Sexuality(window, currentPage)
		})

	searchTermsButton := widget.NewButton("Search Terms", func(){
			setChooseDesiresPage_SearchTerms(window, currentPage)
		})

	chatButton := widget.NewButton("Chat", func(){
			setChooseDesiresPage_Chat(window, currentPage)
		})

	likedUsersButton := widget.NewButton("Liked Users", func(){
			setChooseDesiresPage_LikedUsers(window, currentPage)
		})

	ignoredUsersButton := widget.NewButton("Ignored Users", func(){
			setChooseDesiresPage_IgnoredUsers(window, currentPage)
		})

	contactsButton := widget.NewButton("Contacts", func(){
			setChooseDesiresPage_Contacts(window, currentPage)
		})

	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, profileLanguageButton, ageButton, distanceButton, countryButton, sexualityButton, searchTermsButton, chatButton, likedUsersButton, ignoredUsersButton, contactsButton))

	buttonsGridPadded := container.NewPadded(buttonsGrid)

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

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered("My Mate Desires - General")

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Profile Language")

	description1 := getLabelCentered("Choose your profile language desires.")
	description2 := getLabelCentered("A profile language is the language that a profile is written in.")
	description3 := getLabelCentered("Choose all of the languages you can read.")

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

		getCurrentDesiredChoicesList := func()([]string, error){

			currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("ProfileLanguage")
			if (err != nil) { return nil, err }
			if (currentChoicesListExists == false){

				emptyList := make([]string, 0)
				return emptyList, nil
			}
			//currentChoicesList is a "+" separated list of choices
			// Each choice option is encoded in base64
			currentDesiredChoicesList := strings.Split(currentChoicesList, "+")

			return currentDesiredChoicesList, nil
		}

		currentDesiredChoicesList, err := getCurrentDesiredChoicesList()
		if (err != nil) { return nil, err }

		addLanguageButton := getWidgetCentered(widget.NewButtonWithIcon("Add Language", theme.ContentAddIcon(), func(){

				submitLanguageFunction := func(newLanguageIdentifier int, _ string)error{

					newLanguageIdentifierString := helpers.ConvertIntToString(newLanguageIdentifier)

					newLanguageIdentifierBase64 := encoding.EncodeBytesToBase64String([]byte(newLanguageIdentifierString))

					newLanguagesList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, newLanguageIdentifierBase64)

					newDesireString := strings.Join(newLanguagesList, "+")

					err = myLocalDesires.SetDesire("ProfileLanguage", newDesireString)
					if (err != nil){ return err }

					return nil
				}

				setChooseDesiresPage_AddLanguage(window, submitLanguageFunction, currentPage, currentPage)
			}))

		if (len(currentDesiredChoicesList) == 0){

			noLanguagesLabel := getBoldLabelCentered("No Languages Selected.")
		
			selectedLanguagesSection := container.NewVBox(noLanguagesLabel, addLanguageButton)

			return selectedLanguagesSection, nil
		}

		myDesiredLanguagesLabel := getItalicLabelCentered("My Desired Languages:")

		languageNameColumn := container.NewVBox(widget.NewSeparator())

		deleteButtonsColumn := container.NewVBox(widget.NewSeparator())

		for _, languageIdentifierBase64 := range currentDesiredChoicesList{

			languageIdentifierString, err := encoding.DecodeBase64StringToUnicodeString(languageIdentifierBase64)
			if (err != nil){
				return nil, errors.New("My current profile language desire is malformed: Contains invalid language: " + languageIdentifierBase64)
			}

			languageIdentifier, err := helpers.ConvertStringToInt(languageIdentifierString)
			if (err != nil){
				return nil, errors.New("My current profile language desire is malformed: Contains invalid language: " + languageIdentifierString)
			}

			languageObject, err := worldLanguages.GetLanguageObjectFromLanguageIdentifier(languageIdentifier)
			if (err != nil){
				return nil, errors.New("My current profile language desire is malformed: Contains unknown language identifier: " + languageIdentifierString)	
			}

			languageNamesList := languageObject.NamesList

			languageDescription := helpers.TranslateAndJoinStringListItems(languageNamesList, "/")

			languageDescriptionTrimmed, _, err := helpers.TrimAndFlattenString(languageDescription, 20)
			if (err != nil) { return nil, err }

			languageNameLabel := getBoldLabelCentered(languageDescriptionTrimmed)

			deleteLanguageButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){

					newDesiredLanguagesList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, languageIdentifierBase64)

					if (len(newDesiredLanguagesList) == 0){

						err := myLocalDesires.DeleteDesire("ProfileLanguage")
						if (err != nil){
							setErrorEncounteredPage(window, err, currentPage)
							return
						}
						currentPage()
						return				
					}

					newDesireValueString := strings.Join(newDesiredLanguagesList, "+")

					err := myLocalDesires.SetDesire("ProfileLanguage", newDesireValueString)
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
				})

			languageNameColumn.Add(languageNameLabel)
			deleteButtonsColumn.Add(deleteLanguageButton)

			languageNameColumn.Add(widget.NewSeparator())
			deleteButtonsColumn.Add(widget.NewSeparator())
		}

		languagesGrid := container.NewHBox(layout.NewSpacer(), languageNameColumn, deleteButtonsColumn, layout.NewSpacer())

		selectedLanguagesSection := container.NewVBox(addLanguageButton, widget.NewSeparator(), myDesiredLanguagesLabel, languagesGrid)

		return selectedLanguagesSection, nil
	}

	selectedLanguagesSection, err := getSelectedLanguagesSection()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "ProfileLanguage", true)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Profile Language", "ProfileLanguage", true, "Bar", "ProfileLanguage", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), selectedLanguagesSection, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}


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

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

	pageTitle := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered(translate("Age"))

	description := getLabelCentered("Choose your age desires.")

	desireEditor, err := getDesireEditor_Numeric(window, currentPage, "Age", 18, 200, "Years", 0, false, nil, nil, false, "", "", nil)	
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Age", "Age", true, "Bar", "Age", currentPage)
		}))

	page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered(translate("Distance"))

	description1 := getLabelCentered("Choose your desired user distance.")
	description2 := getLabelCentered("You must add a primary location to your profile to calculate distance.")

	metricOrImperialSwitchButton, err := getMetricImperialSwitchButton(window, currentPage)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return	
	}

	currentUnitsLabel := getItalicLabel("Current Units:")

	currentUnitsRow := container.NewHBox(layout.NewSpacer(), currentUnitsLabel, metricOrImperialSwitchButton, layout.NewSpacer())

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

		exists, metricOrImperial, err := globalSettings.GetSetting("MetricOrImperial")
		if (err != nil) { return "", err }
		if (exists == false){
			return "Metric", nil
		}
		if (metricOrImperial != "Metric" && metricOrImperial != "Imperial"){
			return "", errors.New("Malformed globalSettings: Invalid metricOrImperial: " + metricOrImperial)
		}

		return metricOrImperial, nil
	}

	myMetricOrImperial, err := getMyMetricOrImperial()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	getCurrentUnits := func()string{
		if (myMetricOrImperial == "Metric"){
			return "kilometers"
		}
		return "miles"
	}

	currentUnits := getCurrentUnits()

	// Distance is normally represented in metric
	// Metric is the standard, and Imperial is custom

	getUnitsAreCustomBool := func()bool{
		
		if (myMetricOrImperial == "Metric"){
			return false
		}
		return true
	}

	unitsAreCustomBool := getUnitsAreCustomBool()

	convertToMetricFunction := helpers.ConvertMilesToKilometers

	convertToImperialFunction := helpers.ConvertKilometersToMiles

	desireEditor, err := getDesireEditor_Numeric(window, currentPage, "Distance", 0, 20000, currentUnits, 2, unitsAreCustomBool, convertToMetricFunction, convertToImperialFunction, false, "", "", nil)
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Distance", "Distance", true, "Bar", "Distance", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentUnitsRow, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered("My Mate Desires - General")

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Country")

	description1 := getLabelCentered("Choose your country desires.")
	description2 := getLabelCentered("Select the countries where you want your matches to live in.")
	description3 := getLabelCentered("Most users should only use this desire if they live near a border.")
	description4 := getLabelCentered("Most users should only need to use the Distance desire.")

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

		getCurrentDesiredChoicesList := func()([]string, error){

			currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("PrimaryLocationCountry")
			if (err != nil) { return nil, err }
			if (currentChoicesListExists == false){

				emptyList := make([]string, 0)
				return emptyList, nil
			}
			//currentChoicesList is a "+" separated list of choices
			// Each choice option is encoded in base64
			currentDesiredChoicesList := strings.Split(currentChoicesList, "+")

			return currentDesiredChoicesList, nil
		}

		currentDesiredChoicesList, err := getCurrentDesiredChoicesList()
		if (err != nil) { return nil, err }

		addCountryButton := getWidgetCentered(widget.NewButtonWithIcon("Add Country", theme.ContentAddIcon(), func(){

				setChooseMateDesiresPage_ChooseCountry(window, currentPage, currentPage)
			}))

		if (len(currentDesiredChoicesList) == 0){

			noCountriesLabel := getBoldLabelCentered("No Countries Selected.")

			selectedCountriesSection := container.NewVBox(noCountriesLabel, addCountryButton)

			return selectedCountriesSection, nil
		}

		myDesiredCountriesLabel := getItalicLabelCentered("My Desired Countries:")

		countryNameColumn := container.NewVBox(widget.NewSeparator())

		deleteButtonsColumn := container.NewVBox(widget.NewSeparator())

		for _, countryIdentifierBase64 := range currentDesiredChoicesList{

			countryIdentifierString, err := encoding.DecodeBase64StringToUnicodeString(countryIdentifierBase64)
			if (err != nil){
				return nil, errors.New("My current profile country desire is malformed: Contains invalid country: " + countryIdentifierBase64)
			}

			countryIdentifier, err := helpers.ConvertStringToInt(countryIdentifierString)
			if (err != nil){
				return nil, errors.New("My current profile country desire is malformed: Contains invalid country: " + countryIdentifierString)
			}

			countryObject, err := worldLocations.GetCountryObjectFromCountryIdentifier(countryIdentifier)
			if (err != nil){
				return nil, errors.New("My current profile country is malformed: Contains unknown country identifier: " + countryIdentifierString)
			}

			countryNamesList := countryObject.NamesList

			countryDescription := helpers.TranslateAndJoinStringListItems(countryNamesList, "/")

			countryNameLabel := getBoldLabelCentered(countryDescription)

			deleteCountryButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){

					newDesiredCountriesList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, countryIdentifierBase64)

					if (len(newDesiredCountriesList) == 0){

						err := myLocalDesires.DeleteDesire("PrimaryLocationCountry")
						if (err != nil){
							setErrorEncounteredPage(window, err, currentPage)
							return
						}
						currentPage()
						return				
					}

					newDesireValueString := strings.Join(newDesiredCountriesList, "+")

					err := myLocalDesires.SetDesire("PrimaryLocationCountry", newDesireValueString)
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
				})

			countryNameColumn.Add(countryNameLabel)
			deleteButtonsColumn.Add(deleteCountryButton)

			countryNameColumn.Add(widget.NewSeparator())
			deleteButtonsColumn.Add(widget.NewSeparator())
		}

		countriesGrid := container.NewHBox(layout.NewSpacer(), countryNameColumn, deleteButtonsColumn, layout.NewSpacer())

		selectedCountriesSection := container.NewVBox(addCountryButton, widget.NewSeparator(), myDesiredCountriesLabel, countriesGrid)

		return selectedCountriesSection, nil
	}

	selectedCountriesSection, err := getSelectedCountriesSection()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "PrimaryLocationCountry", true)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Country", "PrimaryLocationCountry", true, "Donut", "PrimaryLocationCountry", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), selectedCountriesSection, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}

func setChooseMateDesiresPage_ChooseCountry(window fyne.Window, previousPage func(), nextPage func()){

	currentPage := func(){setChooseMateDesiresPage_ChooseCountry(window, previousPage, nextPage)}

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered(translate("Add Country"))

	description1 := getLabelCentered("Choose the country to add.")

	allCountryObjectsList, err := worldLocations.GetAllCountryObjectsList()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	allTranslatedCountriesList := make([]string, 0, len(allCountryObjectsList))

	// Map Structure: Country Description -> Country identifier
	countryIdentifiersMap := make(map[string]int)

	for _, countryObject := range allCountryObjectsList{

		countryIdentifier := countryObject.Identifier
		countryNamesList := countryObject.NamesList

		countryDescription := helpers.TranslateAndJoinStringListItems(countryNamesList, "/")

		countryIdentifiersMap[countryDescription] = countryIdentifier
		allTranslatedCountriesList = append(allTranslatedCountriesList, countryDescription)
	}

	helpers.SortStringListToUnicodeOrder(allTranslatedCountriesList)

	onSelectedFunction := func(selectedCountryIndex int) {

		selectedCountryDescription := allTranslatedCountriesList[selectedCountryIndex]

		selectedCountryIdentifier, exists := countryIdentifiersMap[selectedCountryDescription]
		if (exists == false){
			setErrorEncounteredPage(window, errors.New("countryIdentifiersMap missing country description."), currentPage)
			return
		}

		selectedCountryIdentifierString := helpers.ConvertIntToString(selectedCountryIdentifier)

		newCountryIdentifierBase64 := encoding.EncodeBytesToBase64String([]byte(selectedCountryIdentifierString))

		getNewDesiredAttributeList := func()([]string, error){

			currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("PrimaryLocationCountry")
			if (err != nil) { return nil, err }		
			if (currentChoicesListExists == false){

				newList := []string{newCountryIdentifierBase64}
				return newList, nil
			}
			//currentChoicesList is a "+" separated list of choices
			// Each choice option is encoded in base64
			currentDesiredChoicesList := strings.Split(currentChoicesList, "+")

			newCountriesList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, newCountryIdentifierBase64)

			return newCountriesList, nil
		}

		newDesiredAttributeList, err := getNewDesiredAttributeList()
		if (err != nil){
			setErrorEncounteredPage(window, err, currentPage)
			return
		}

		newDesireString := strings.Join(newDesiredAttributeList, "+")

		err = myLocalDesires.SetDesire("PrimaryLocationCountry", newDesireString)
		if (err != nil){
			setErrorEncounteredPage(window, err, currentPage)
			return
		}

		nextPage()
	}

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

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

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

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered("My Mate Desires - General")

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered(translate("Sexuality"))

	description1 := getLabelCentered("Choose the user sexualities that you desire.")
	description2 := getLabelCentered("This refers to which sexes the users are interested in.")
	description3 := getLabelCentered("For example, if you are Male, you should at least select Male.")

	option1Translated := translate("Male")
	option2Translated := translate("Female")
	option3Translated := translate("Male And Female")

	optionTitlesList := []string{option1Translated, option2Translated, option3Translated}

	optionNamesMap := map[string][]string{
		option1Translated: []string{"Male"},
		option2Translated: []string{"Female"},
		option3Translated: []string{"Male And Female"},
	}

	desireEditor, err := getDesireEditor_Choice(window, currentPage, "Sexuality", optionTitlesList, optionNamesMap, false, true, 1)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Sexuality", "Sexuality", true, "Donut", "Sexuality", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))
	
	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Search Terms")

	description1 := getLabelCentered("Choose your desired search terms.")
	description2 := getLabelCentered("Seekia will search through each user's profile for your terms.")
	description3 := getLabelCentered("Each user's description, tags, hobbies, and beliefs will be searched.")	
	description4 := getLabelCentered("A user's profile must contain at least 1 of your terms to pass the desire.")

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

		getCurrentDesiredChoicesList := func()([]string, error){

			currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("SearchTerms")
			if (err != nil) { return nil, err }		
			if (currentChoicesListExists == false){

				emptyList := make([]string, 0)
				return emptyList, nil
			}
			// currentChoicesList is a "+" separated list of choices
			// Each choice option is encoded in base64
			currentDesiredChoicesList := strings.Split(currentChoicesList, "+")

			return currentDesiredChoicesList, nil
		}

		currentDesiredChoicesList, err := getCurrentDesiredChoicesList()
		if (err != nil) { return nil, err }

		addTermEntry := widget.NewEntry()
		addTermEntry.SetPlaceHolder("Enter term name...")

		addTermButton := getWidgetCentered(widget.NewButtonWithIcon("Add Term", theme.ContentAddIcon(), func(){

				newTermName := addTermEntry.Text

				if (newTermName == ""){
					return
				}
				isAllowed := allowedText.VerifyStringIsAllowed(newTermName)
				if (isAllowed == false){
					title := translate("Invalid Term Name")
					dialogMessageA := getLabelCentered(translate("Your search term contains an invalid character."))
					dialogMessageB := getLabelCentered(translate("It must be encoded in UTF-8."))
					dialogMessageC := getLabelCentered(translate("Remove this character and resubmit."))
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				containsTabsOrNewlines := helpers.CheckIfStringContainsTabsOrNewlines(newTermName)
				if (containsTabsOrNewlines == true){
					title := translate("Invalid Term Name")
					dialogMessageA := getLabelCentered(translate("Your search term contains a tab or a newline."))
					dialogMessageB := getLabelCentered(translate("Remove the tab or newline and resubmit."))
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				termNameBase64 := encoding.EncodeBytesToBase64String([]byte(newTermName))

				newDesireList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, termNameBase64)
				newDesireAttributeValue := strings.Join(newDesireList, "+")

				err := myLocalDesires.SetDesire("SearchTerms", newDesireAttributeValue)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}

				currentPage()
			}))

		addTermRow := getContainerCentered(container.NewGridWithRows(1, addTermEntry, addTermButton))

		if (len(currentDesiredChoicesList) == 0){

			noTermsExistLabel := getBoldLabelCentered("No Terms Exist.")

			selectedSearchTermsSection := container.NewVBox(addTermRow, widget.NewSeparator(), noTermsExistLabel)

			return selectedSearchTermsSection, nil
		}

		myDesiredTermsLabel := getItalicLabelCentered("My Desired Terms:")

		termNameColumn := container.NewVBox(widget.NewSeparator())

		deleteButtonsColumn := container.NewVBox(widget.NewSeparator())

		for _, termNameBase64 := range currentDesiredChoicesList{

			termName, err := encoding.DecodeBase64StringToUnicodeString(termNameBase64)
			if (err != nil){
				return nil, errors.New("My current search terms desire is malformed: Contains invalid term: " + termNameBase64)
			}

			termNameLabel := getBoldLabelCentered(termName)

			deleteTermButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){

					newDesiredTermsList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, termNameBase64)

					if (len(newDesiredTermsList) == 0){

						err := myLocalDesires.DeleteDesire("SearchTerms")
						if (err != nil){
							setErrorEncounteredPage(window, err, currentPage)
							return
						}
						currentPage()
						return				
					}

					newDesireValueString := strings.Join(newDesiredTermsList, "+")
			
					err := myLocalDesires.SetDesire("SearchTerms", newDesireValueString)
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
				})

			termNameColumn.Add(termNameLabel)
			deleteButtonsColumn.Add(deleteTermButton)

			termNameColumn.Add(widget.NewSeparator())
			deleteButtonsColumn.Add(widget.NewSeparator())
		}

		termsGrid := container.NewHBox(layout.NewSpacer(), termNameColumn, deleteButtonsColumn, layout.NewSpacer())

		selectedTermsSection := container.NewVBox(addTermRow, widget.NewSeparator(), myDesiredTermsLabel, termsGrid)

		return selectedTermsSection, nil
	}

	selectedTermsSection, err := getSelectedSearchTermsSection()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "SearchTerms", false)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Search Terms", "SearchTerms", true, "Bar", "SearchTermsCount", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), selectedTermsSection, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Chat Desires")

	description1 := getLabelCentered("Choose your chat desires.")

	hasMessagedMeButton := widget.NewButton("Has Messaged Me", func(){
			setChooseDesiresPage_HasMessagedMe(window, currentPage)
		})

	iHaveMessagedButton := widget.NewButton("I Have Messaged", func(){
			setChooseDesiresPage_IHaveMessaged(window, currentPage)
		})

	hasRejectedMeButton := widget.NewButton("Has Rejected Me", func(){
			setChooseDesiresPage_HasRejectedMe(window, currentPage)
		})

	hasAnsweredQuestionnaireButton := widget.NewButton("Has Answered Questionnaire", func(){
			//TODO
			// We need to include the functionality to only show users who responded in a specified way
			// For example, if the user's question is: Do you like french fries?, and the user has 2 options: Yes/No, 
			//		the user should be able to filter users who answered with yes/no
			showUnderConstructionDialog(window)
		})

	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, hasMessagedMeButton, iHaveMessagedButton, hasRejectedMeButton, hasAnsweredQuestionnaireButton))
	
	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, widget.NewSeparator(), buttonsGrid)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered("My Mate Desires - General")

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Has Messaged Me")

	description1 := getLabelCentered("Use this desire to show or hide users who have messaged you.")
	description2 := getLabelCentered("Select the kind of users to include in your matches.")

	//TODO: Change this to HasGreetedMe? Currently, a user who has rejected us will be included by this desire

	option1Translated := translate("Has Messaged Me")
	option2Translated := translate("Has Not Messaged Me")

	optionTitlesList := []string{option1Translated, option2Translated}

	optionNamesMap := map[string][]string{
		option1Translated: []string{"Yes"},
		option2Translated: []string{"No"},
	}

	desireEditor, err := getDesireEditor_Choice(window, currentPage, "HasMessagedMe", optionTitlesList, optionNamesMap, false, false, 1)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Has Messaged Me", "HasMessagedMe", true, "Donut", "HasMessagedMe", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered("My Mate Desires - General")

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("I Have Messaged")

	description1 := getLabelCentered("Use this desire to show or hide users whom you have messaged.")
	description2 := getLabelCentered("Select the kind of users to include in your matches.")

	option1Translated := translate("I Have Messaged")
	option2Translated := translate("I Have Not Messaged")

	optionTitlesList := []string{option1Translated, option2Translated}

	optionNamesMap := map[string][]string{
		option1Translated: []string{"Yes"},
		option2Translated: []string{"No"},
	}

	desireEditor, err := getDesireEditor_Choice(window, currentPage, "IHaveMessaged", optionTitlesList, optionNamesMap, false, false, 1)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "I Have Messaged", "IHaveMessaged", true, "Donut", "IHaveMessaged", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Has Rejected Me")

	description1 := getLabelCentered("Use this desire to show or hide users who have rejected you.")
	description2 := getLabelCentered("These are users who sent you a message that they are not interested.")
	description3 := getLabelCentered("Select the kind of users to include in your matches.")

	option1Translated := translate("Has Rejected Me")
	option2Translated := translate("Has Not Rejected Me")

	optionTitlesList := []string{option1Translated, option2Translated}

	optionNamesMap := map[string][]string{
		option1Translated: []string{"Yes"},
		option2Translated: []string{"No"},
	}

	desireEditor, err := getDesireEditor_Choice(window, currentPage, "HasRejectedMe", optionTitlesList, optionNamesMap, false, false, 1)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Has Rejected Me", "HasRejectedMe", true, "Donut", "HasRejectedMe", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Liked Users")

	description1 := getLabelCentered("Use this desire to show or hide liked users.")
	description2 := getLabelCentered("A liked user is a user that you have added to your likes.")
	description3 := getLabelCentered("Select the kind of users to include in your matches.")

	option1Translated := translate("Liked")
	option2Translated := translate("Not Liked")

	optionTitlesList := []string{option1Translated, option2Translated}

	optionNamesMap := map[string][]string{
		option1Translated: []string{"Yes"},
		option2Translated: []string{"No"},
	}

	desireEditor, err := getDesireEditor_Choice(window, currentPage, "IsLiked", optionTitlesList, optionNamesMap, false, false, 1)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Is Liked", "IsLiked", true, "Donut", "IsLiked", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Ignored Users")

	description1 := getLabelCentered("Use this desire to show or hide ignored users.")
	description2 := getLabelCentered("An Ignored user is a user that you have ignored.")
	description3 := getLabelCentered("Select the kind of users to include in your matches.")

	option1Translated := translate("Ignored")
	option2Translated := translate("Not Ignored")

	optionTitlesList := []string{option1Translated, option2Translated}

	optionNamesMap := map[string][]string{
		option1Translated: []string{"Yes"},
		option2Translated: []string{"No"},
	}

	desireEditor, err := getDesireEditor_Choice(window, currentPage, "IsIgnored", optionTitlesList, optionNamesMap, false, false, 1)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Is Ignored", "IsIgnored", true, "Donut", "IsIgnored", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("My Mate Desires - General"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Contacts")

	description1 := getLabelCentered("Use this desire to show or hide your contacts.")
	description2 := getLabelCentered("These are users you have added to your contacts.")
	description3 := getLabelCentered("Select the kind of users to include in your matches.")

	option1Translated := translate("Is My Contact")
	option2Translated := translate("Is Not My Contact")

	optionTitlesList := []string{option1Translated, option2Translated}

	optionNamesMap := map[string][]string{
		option1Translated: []string{"Yes"},
		option2Translated: []string{"No"},
	}

	desireEditor, err := getDesireEditor_Choice(window, currentPage, "IsMyContact", optionTitlesList, optionNamesMap, false, false, 1)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
			setViewMyMateDesireStatisticsPage(window, "Is My Contact", "IsMyContact", true, "Donut", "IsMyContact", currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)

	setPageContent(page, window)
}


// This function provides the editor to edit a choice desire
// A choice desire is one where there are a some canonical choices available, and the potential for an "Other" choice
// Inputs:
//	-fyne.Window
//	-func(): Current page
//	-string: Desire name
//	-[]string: Option titles list: What each check will show. Example: "1/5", "2/5", "3/5", "4/5", "5/5")
//	-map[string][]string: Option Title -> Option Names list (Example ("1/5" -> "1", "2/5" -> "2"...)
//	-bool: Show other choice: True if we want to show the "Other" option
//	-bool: Show the "Require Response" button (false for attributes which do not allow that option)
//	-int: Number of columns for the grid
// Outputs:
//	-*fyne.Container
//	-error
func getDesireEditor_Choice(window fyne.Window, currentPage func(), desireName string, optionTitlesList []string, optionsNamesMap map[string][]string, showOtherChoice bool, showRequireResponseButton bool, numberOfGridColumns int)(*fyne.Container, error){

	getCurrentDesiredChoicesList := func()([]string, error){

		currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire(desireName)
		if (err != nil) { return nil, err }
		if (currentChoicesListExists == false){

			emptyList := make([]string, 0)
			return emptyList, nil
		}
		//currentChoicesList is a "+" separated list of choices
		// Each choice option is encoded in base64 (Except for "Other")
		currentDesiredChoicesList := strings.Split(currentChoicesList, "+")

		return currentDesiredChoicesList, nil
	}

	currentDesiredChoicesList, err := getCurrentDesiredChoicesList()
	if (err != nil) { return nil, err }

	selectButtonsGrid := container.NewGridWithColumns(numberOfGridColumns)

	for _, optionTitle := range optionTitlesList{

		optionNamesList, exists := optionsNamesMap[optionTitle]
		if (exists == false){
			return nil, errors.New("getDesireEditor_Choice called with optionsNamesMap missing optionTitle: " + optionTitle)
		}

		optionBase64NamesList := make([]string, 0, len(optionNamesList))

		for _, optionName := range optionNamesList{

			optionNameBase64 := encoding.EncodeBytesToBase64String([]byte(optionName))	

			optionBase64NamesList = append(optionBase64NamesList, optionNameBase64)
		}

		handleSelectFunction := func(selection bool){

			//Outputs:
			//	-[]string: New desire attribute list (list of base64 option names)
			getNewDesireAttributeList := func()[]string{

				if (selection == false){
					if (len(currentDesiredChoicesList) == 0){
						// This should not happen, because the option was already selected
						// The list should have had at least 1 item before
						emptyList := make([]string, 0)
						return emptyList
					}

					newAttributeList := make([]string, 0)

					for _, optionNameBase64 := range currentDesiredChoicesList{
						// We see if this option name belongs to the current optionTitle
						// If it does, we remove it from our selected attributes list
						shouldDelete := slices.Contains(optionBase64NamesList, optionNameBase64)
						if (shouldDelete == false){
							newAttributeList = append(newAttributeList, optionNameBase64)
						}
					}

					return newAttributeList
				}
				//selection == true

				newDesiredChoicesList := slices.Concat(currentDesiredChoicesList, optionBase64NamesList)

				duplicatesRemovedList := helpers.RemoveDuplicatesFromStringList(newDesiredChoicesList)

				return duplicatesRemovedList
			}

			newDesireAttributeList := getNewDesireAttributeList()
			if (len(newDesireAttributeList) == 0){

				err := myLocalDesires.DeleteDesire(desireName)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
				return
			}

			newDesireAttribute := strings.Join(newDesireAttributeList, "+")	

			err := myLocalDesires.SetDesire(desireName, newDesireAttribute)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}

		optionSelectCheck := widget.NewCheck(optionTitle, handleSelectFunction)

		getChoiceIsSelectedBool := func()bool{

			// Every option name associated with this choice must be selected for this choice to be considered selected

			for _, optionNameBase64 := range optionBase64NamesList{
				listContainsItem := slices.Contains(currentDesiredChoicesList, optionNameBase64)
				if (listContainsItem == false){
					return false
				}
			}
			return true
		}
		choiceIsSelected := getChoiceIsSelectedBool()
		if (choiceIsSelected == true){
			optionSelectCheck.Checked = true
		}

		selectButtonsGrid.Add(optionSelectCheck)
	}

	if (showOtherChoice == true){

		handleOtherSelectFunction := func(selection bool){

			//Outputs:
			//	-[]string: New desire attribute list (list of base64 option names)
			getNewDesireAttributeList := func()[]string{

				if (selection == false){
					if (len(currentDesiredChoicesList) == 0){
						// This should not happen, because "Other" had to have been selected for it to be deselected
						emptyList := make([]string, 0)
						return emptyList
					}

					newAttributeList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, "Other")

					return newAttributeList
				}
				//selection == true

				newAttributeList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, "Other")

				return newAttributeList
			}

			newDesireAttributeList := getNewDesireAttributeList()
			if (len(newDesireAttributeList) == 0){

				err := myLocalDesires.DeleteDesire(desireName)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
				return
			}
			newDesireAttribute := strings.Join(newDesireAttributeList, "+")	

			err := myLocalDesires.SetDesire(desireName, newDesireAttribute)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}

		otherSelectCheck := widget.NewCheck("Other", handleOtherSelectFunction)

		otherIsSelected := slices.Contains(currentDesiredChoicesList, "Other")
		if (otherIsSelected == true){
			otherSelectCheck.Checked = true
		}

		selectButtonsGrid.Add(otherSelectCheck)
	}

	selectButtonsGridCentered := getContainerCentered(selectButtonsGrid)

	filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, desireName, showRequireResponseButton)
	if (err != nil){ return nil, err }

	desireEditor := container.NewVBox(selectButtonsGridCentered, widget.NewSeparator(), filterOptionsSection)

	return desireEditor, nil
}

// This function provides the editor to edit a numeric attribute
// The user can choose a minimum and maximum allowed value
// Units are shown for each minimum/maximum value, and a secondary row of alternate units can optionally be shown
func getDesireEditor_Numeric(
		window fyne.Window,
		currentPage func(),
		desireName string,
		minimumAllowed int64,
		maximumAllowed int64,
		currentUnits string,
		unitsRoundingPrecision int,
		unitsAreCustom bool, // This will be true if we need to convert the shown units
		convertToStandardFunction func(float64)(float64, error),
		convertToCustomFunction func(float64)(float64, error),
		showSecondaryForm bool, // Secondary form is an alternate representation of the bound. Example: Offspring variants
		secondaryFormTitle string,
		secondaryFormPrefix string, // A prefix to add to the secondary form representation. Example: "~" for offspring variants
		getSecondaryFormFunction func(float64)(float64, error))(*fyne.Container, error){

	getBoundColumn := func(minimumOrMaximum string)(*fyne.Container, error){

		if (minimumOrMaximum != "Minimum" && minimumOrMaximum != "Maximum"){
			return nil, errors.New("getBoundColumn called with invalid minimumOrMaximum: " + minimumOrMaximum)
		}

		desireBoundName := desireName + "_" + minimumOrMaximum

		boundLabel := getBoldLabelCentered(minimumOrMaximum)

		myBoundExists, myCurrentBound, err := myLocalDesires.GetDesire(desireBoundName)
		if (err != nil) { return nil, err }

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

			if (myBoundExists == false){
				noneLabel := getBoldItalicLabelCentered(translate("None"))

				if (showSecondaryForm == false){
					return noneLabel, nil
				}

				noneLabel2 := getBoldItalicLabelCentered(translate("None"))

				secondaryFormTitle := getItalicLabelCentered(secondaryFormTitle + ":")

				myBoundSection := container.NewVBox(noneLabel, widget.NewSeparator(), secondaryFormTitle, noneLabel2)

				return myBoundSection, nil
			}

			// This will convert the bound if unitsAreCustom is true
			getMyCurrentBound := func()(float64, error){

				myBoundFloat64, err := helpers.ConvertStringToFloat64(myCurrentBound)
				if (err != nil){
					return 0, errors.New("My " + desireName + " desire malformed: not float64: " + myCurrentBound)
				}

				if (unitsAreCustom == false){
					return myBoundFloat64, nil
				}

				myBoundCustom, err := convertToCustomFunction(myBoundFloat64)
				if (err != nil){
					return 0, errors.New("My " + desireName + " desire malformed: is negative: " + myCurrentBound)
				}

				return myBoundCustom, nil
			}

			myCurrentBound, err := getMyCurrentBound()
			if (err != nil){ return nil, err }
	
			myCurrentBoundString := helpers.ConvertFloat64ToStringRounded(myCurrentBound, unitsRoundingPrecision)

			myBoundLabelText := myCurrentBoundString + " " + translate(currentUnits)
			myBoundLabel := getBoldLabelCentered(myBoundLabelText)
	
			if (showSecondaryForm == false){

				return myBoundLabel, nil
			}

			secondaryFormBound, err := getSecondaryFormFunction(myCurrentBound)
			if (err != nil){ return nil, err }

			secondaryFormBoundString := helpers.ConvertFloat64ToStringRounded(secondaryFormBound, unitsRoundingPrecision)

			secondaryFormTitle := getItalicLabelCentered(secondaryFormTitle + ":")

			mySecondaryFormBoundLabelText := secondaryFormPrefix + secondaryFormBoundString + " " + translate(currentUnits)
			mySecondaryFormBoundLabel := getBoldItalicLabelCentered(mySecondaryFormBoundLabelText)

			myBoundSection := container.NewVBox(myBoundLabel, widget.NewSeparator(), secondaryFormTitle, mySecondaryFormBoundLabel)

			return myBoundSection, nil
		}

		myBoundSection, err := getMyBoundSection()
		if (err != nil) { return nil, err }

		minimumOrMaximumLowercase := strings.ToLower(minimumOrMaximum)

		boundEntry := widget.NewEntry()
		
		if (myBoundExists == true){

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

				myCurrentBoundFloat64, err := helpers.ConvertStringToFloat64(myCurrentBound)
				if (err != nil) {
					return "", errors.New("My desires malformed: Contains invalid numeric desire: " + desireName)
				}
				if (myCurrentBoundFloat64 < float64(minimumAllowed) || myCurrentBoundFloat64 > float64(maximumAllowed)) {
					return "", errors.New("My desires malformed: Contains invalid numeric desire: " + desireName)
				}

				if (unitsAreCustom == false){
					myCurrentBoundRounded := helpers.ConvertFloat64ToStringRounded(myCurrentBoundFloat64, unitsRoundingPrecision)
					return myCurrentBoundRounded, nil
				}

				myCurrentBoundCustom, err := convertToCustomFunction(myCurrentBoundFloat64)
				if (err != nil){
					return "", errors.New("My desires malformed: Contains invalid numeric desire: " + desireName)
				}	

				myCurrentBoundCustomString := helpers.ConvertFloat64ToStringRounded(myCurrentBoundCustom, unitsRoundingPrecision)

				return myCurrentBoundCustomString, nil
			}

			myCurrentBoundString, err := getMyCurrentBoundString()
			if (err != nil) { return nil, err }

			boundEntry.SetText(myCurrentBoundString)

		} else {
			boundEntry.SetPlaceHolder(translate("Enter " + minimumOrMaximumLowercase + "..."))
		}

		saveBoundButton := widget.NewButtonWithIcon(translate("Save"), theme.ConfirmIcon(), func(){

			newBound := boundEntry.Text

			if (newBound == ""){

				err := myLocalDesires.DeleteDesire(desireBoundName)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
				return
			}

			//TODO: If min is greater than max, or max is greater than min, show dialog and don't allow change

			newBoundFloat64, err := helpers.ConvertStringToFloat64(newBound)
			if (err != nil){

				title := translate("Invalid Bound")
				dialogMessage := getLabelCentered(translate("Your bound must be a number."))
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(title, translate("Close"), dialogContent, window)
				return
			}

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

				if (unitsAreCustom == false){
					return newBoundFloat64, nil
				}

				boundInStandardUnits, err := convertToStandardFunction(newBoundFloat64)
				if (err != nil){
					return 0, errors.New("Invalid new numeric bound: " + err.Error())
				}

				return boundInStandardUnits, nil
			}

			newDesireBoundConverted, err := getNewDesireBoundConverted()
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}	

			if (newDesireBoundConverted < float64(minimumAllowed) || newDesireBoundConverted > float64(maximumAllowed)){

				minimumAllowedString := helpers.ConvertInt64ToString(minimumAllowed)
				maximumAllowedString := helpers.ConvertInt64ToString(maximumAllowed)

				dialogTitle := translate("Invalid Desire")
				dialogMessage := getLabelCentered(translate("Your " + minimumOrMaximumLowercase + " must be a number between " + minimumAllowedString + " and " + maximumAllowedString + "."))
				dialogContent := container.NewVBox(dialogMessage)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			newDesireBoundString := helpers.ConvertFloat64ToStringRounded(newDesireBoundConverted, unitsRoundingPrecision)

			err = myLocalDesires.SetDesire(desireBoundName, newDesireBoundString)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}

			currentPage()
		})

		saveBoundButtonWithEntry := container.NewGridWithRows(1, boundEntry, saveBoundButton)

		deleteBoundButton := widget.NewButtonWithIcon(translate("No Preference"), theme.CancelIcon(), func(){

			if (myBoundExists == false){
				return
			}

			err := myLocalDesires.DeleteDesire(desireBoundName)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		})

		boundColumn := getContainerCentered(container.NewVBox(boundLabel, widget.NewSeparator(), myBoundSection, widget.NewSeparator(), saveBoundButtonWithEntry, deleteBoundButton))
		return boundColumn, nil
	}

	minimumColumn, err := getBoundColumn("Minimum")
	if (err != nil){ return nil, err }

	maximumColumn, err := getBoundColumn("Maximum")
	if (err != nil){ return nil, err }

	boundColumns := getContainerCentered(container.NewGridWithRows(1, minimumColumn, maximumColumn))

	filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, desireName, true)
	if (err != nil){ return nil, err }

	editorContent := container.NewVBox(boundColumns, widget.NewSeparator(), filterOptionsSection)
		
	return editorContent, nil
}

func getDesireEditorFilterOptionsSection(window fyne.Window, currentPage func(), desireName string, showRequireResponseButton bool)(*fyne.Container, error){

	configureFiltersDescription := widget.NewLabel("Configure your desire filter options.")

	desireFilterOptionsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
			setDesireFilterOptionsExplainerPage(window, currentPage)
		})

	desireFilterOptionsDescriptionRow := container.NewHBox(layout.NewSpacer(), configureFiltersDescription, desireFilterOptionsHelpButton, layout.NewSpacer())

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

		filterAllExists, currentFilterAllResponse, err := myLocalDesires.GetDesire(desireName + "_FilterAll")
		if (err != nil) { return nil, err }

		if (filterAllExists == true && currentFilterAllResponse == "Yes"){
			button := widget.NewButtonWithIcon(translate("Filter All"), theme.CheckButtonCheckedIcon(), func(){
				_ = myLocalDesires.SetDesire(desireName + "_FilterAll", "No")
				currentPage()
			})
			return button, nil
		}
		button := widget.NewButtonWithIcon(translate("Filter All"), theme.CheckButtonIcon(), func(){
			_ = myLocalDesires.SetDesire(desireName + "_FilterAll", "Yes")
			currentPage()
		})
		return button, nil
	}

	filterAllButton, err := getFilterAllButton()
	if (err != nil) { return nil, err }

	if (showRequireResponseButton == false){

		filterAllButtonCentered := getWidgetCentered(filterAllButton)

		filterOptionsSection := container.NewVBox(desireFilterOptionsDescriptionRow, filterAllButtonCentered)

		return filterOptionsSection, nil
	}

	getRequireResponseButton := func()(fyne.Widget, error){
	
		requireResponseExists, currentRequireResponse, err := myLocalDesires.GetDesire(desireName + "_RequireResponse")
		if (err != nil) { return nil, err }

		if (requireResponseExists == true && currentRequireResponse == "Yes"){
			button := widget.NewButtonWithIcon(translate("Require Response"), theme.CheckButtonCheckedIcon(), func(){
					_ = myLocalDesires.SetDesire(desireName + "_RequireResponse", "No")
					currentPage()
				})
			return button, nil
		}
		button := widget.NewButtonWithIcon(translate("Require Response"), theme.CheckButtonIcon(), func(){
				_ = myLocalDesires.SetDesire(desireName + "_RequireResponse", "Yes")
				currentPage()
			})
		return button, nil
	}

	requireResponseButton, err := getRequireResponseButton()
	if (err != nil) { return nil, err }

	filterSettingsButtonsGrid := getContainerCentered(container.NewGridWithColumns(1, filterAllButton, requireResponseButton))

	filterOptionsSection := container.NewVBox(desireFilterOptionsDescriptionRow, filterSettingsButtonsGrid)

	return filterOptionsSection, nil
}


// This is a page to view all of a user's desires
func setViewAllMyDesiresPage(window fyne.Window, previousPage func()){

	setLoadingScreen(window, "My Mate Desires", "Loading My Mate Desires...")

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

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

	title := getPageTitleCentered("My Mate Desires")

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Below are all of your mate desires.")

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

		desireButtonsColumn := container.NewVBox(widget.NewSeparator())
		desireNameAndDataColumn := container.NewVBox(widget.NewSeparator())
		filterOptionChecksColumn := container.NewVBox(widget.NewSeparator())

		getFilterOptionCheck := func(desireName string, optionType string)(fyne.Widget, error){

			if (optionType != "FilterAll" && optionType != "RequireResponse"){
				return nil, errors.New("getFilterOptionCheck called with invalid optionType: " + optionType)
			}

			filterOptionDesireName := desireName + "_" + optionType

			getOptionTitle := func()string{

				if (optionType == "FilterAll"){
					result := translate("Filter All")
					return result
				}

				result := translate("Require Response")
				return result
			}

			optionTitle := getOptionTitle()

			filterOptionCheck := widget.NewCheck(optionTitle, func(newSelection bool){

					newSelectionString := helpers.ConvertBoolToYesOrNoString(newSelection)
					_ = myLocalDesires.SetDesire(filterOptionDesireName, newSelectionString)
				})

			exists, currentValue, err := myLocalDesires.GetDesire(filterOptionDesireName)
			if (err != nil) { return nil, err }
			if (exists == true && currentValue == "Yes"){
				filterOptionCheck.Checked = true
			}

			return filterOptionCheck, nil
		}

		addDesireRow_Numerical := func(desireTitle string, desireName string, editPage func(), barOrDonutChart string, attributeName string)error{

			editDesireButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), editPage)

			desireTitleLabel := getBoldLabelCentered(desireTitle)

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

				minimumExists, desireMinimum, err := myLocalDesires.GetDesire(desireName + "_Minimum")
				if (err != nil) { return nil, err }

				maximumExists, desireMaximum, err := myLocalDesires.GetDesire(desireName + "_Maximum")
				if (err != nil) { return nil, err }

				if (minimumExists == false && maximumExists == false){
					noPreferenceLabel := getItalicLabelCentered("No Preference")
					return noPreferenceLabel, nil
				}

				// We may have to format the desire value
				// For example: converting distance units from kilometers to miles

				_, attributeIsNumerical, formatDesireValuesFunction, desireValueUnits, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeName)
				if (err != nil) { return nil, err }
				if (attributeIsNumerical == false){
					return nil, errors.New("addDesireRow_Numerical called with non-numerical attribute: " + attributeName)
				}

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

					if (minimumExists == true && maximumExists == false){

						desireMinimumFormatted, err := formatDesireValuesFunction(desireMinimum)
						if (err != nil) { return "", err }

						result := desireMinimumFormatted + "+"

						return result, nil
					}
					if (minimumExists == false && maximumExists == true){

						desireMaximumFormatted, err := formatDesireValuesFunction(desireMaximum)
						if (err != nil) { return "", err }

						result := "<" + desireMaximumFormatted

						return result, nil
					}

					desireMinimumFormatted, err := formatDesireValuesFunction(desireMinimum)
					if (err != nil) { return "", err }

					desireMaximumFormatted, err := formatDesireValuesFunction(desireMaximum)
					if (err != nil) { return "", err }

					result := desireMinimumFormatted + " - " + desireMaximumFormatted

					return result, nil
				}

				desireRangeFormatted, err := getDesireRangeFormatted()
				if (err != nil) { return nil, err }

				labelText := desireRangeFormatted + desireValueUnits

				minMaxLabel := getBoldItalicLabelCentered(labelText)

				return minMaxLabel, nil
			}

			desireValueLabel, err := getDesireValueLabel()
			if (err != nil) { return err }		

			filterAllCheck, err := getFilterOptionCheck(desireName, "FilterAll")
			if (err != nil) { return err }

			requireResponseCheck, err := getFilterOptionCheck(desireName, "RequireResponse")
			if (err != nil) { return err }

			viewStatisticsButton := widget.NewButtonWithIcon("Stats", theme.InfoIcon(), func(){

					setViewMyMateDesireStatisticsPage(window, desireTitle, desireName, true, barOrDonutChart, attributeName, currentPage)
				})

			desireButtonsColumn.Add(editDesireButton)
			desireButtonsColumn.Add(viewStatisticsButton)

			desireNameAndDataColumn.Add(desireTitleLabel)
			desireNameAndDataColumn.Add(desireValueLabel)

			filterOptionChecksColumn.Add(filterAllCheck)
			filterOptionChecksColumn.Add(requireResponseCheck)

			desireButtonsColumn.Add(widget.NewSeparator())
			desireNameAndDataColumn.Add(widget.NewSeparator())
			filterOptionChecksColumn.Add(widget.NewSeparator())

			return nil
		}

		addDesireRow_Choice := func(desireTitle string, desireName string, editPage func(), barOrDonutChart string, attributeName string)error{		

			editDesireButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), editPage)

			desireTitleLabel := getBoldLabelCentered(desireTitle)

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

				desireExists, desireChoicesList, err := myLocalDesires.GetDesire(desireName)
				if (err != nil) { return nil, err }

				if (desireExists == false){
					noPreferenceLabel := getItalicLabelCentered(translate("No Preference"))
					return noPreferenceLabel, nil
				}


				// We may have to format the desired choices for readability
				// For example: Converting "1" -> "1/6"

				_, _, formatDesireValuesFunction, desireValueUnits, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeName)
				if (err != nil) { return nil, err }

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

					base64ChoicesList := strings.Split(desireChoicesList, "+")

					choicesList := make([]string, 0, len(base64ChoicesList))

					for _, base64Choice := range base64ChoicesList{

						choiceString, err := encoding.DecodeBase64StringToUnicodeString(base64Choice)
						if (err != nil) {
							return "", errors.New("My Desire choices list is malformed: Contains non-base64 choice: " + base64Choice)
						}

						choiceFormatted, err := formatDesireValuesFunction(choiceString)
						if (err != nil) { return "", err }

						choiceFormattedWithUnits := choiceFormatted + desireValueUnits

						choicesList = append(choicesList, choiceFormattedWithUnits)
					}

					choicesListJoined := strings.Join(choicesList, ", ")
					choicesListTrimmed, _, err := helpers.TrimAndFlattenString(choicesListJoined, 35)
					if (err != nil) { return "", err }

					return choicesListTrimmed, nil
				}

				labelText, err := getLabelText()
				if (err != nil) { return nil, err }

				desireValueLabel := getBoldItalicLabelCentered(labelText)

				return desireValueLabel, nil
			}

			choiceValueLabel, err := getChoiceValueLabel()
			if (err != nil) { return err }

			filterAllCheck, err := getFilterOptionCheck(desireName, "FilterAll")
			if (err != nil) { return err }

			requireResponseCheck, err := getFilterOptionCheck(desireName, "RequireResponse")
			if (err != nil) { return err }

			viewStatisticsButton := widget.NewButtonWithIcon("Stats", theme.InfoIcon(), func(){

					setViewMyMateDesireStatisticsPage(window, desireTitle, desireName, true, barOrDonutChart, attributeName, currentPage)
				})

			desireButtonsColumn.Add(editDesireButton)
			desireButtonsColumn.Add(viewStatisticsButton)

			desireNameAndDataColumn.Add(desireTitleLabel)
			desireNameAndDataColumn.Add(choiceValueLabel)

			filterOptionChecksColumn.Add(filterAllCheck)
			filterOptionChecksColumn.Add(requireResponseCheck)

			desireButtonsColumn.Add(widget.NewSeparator())
			desireNameAndDataColumn.Add(widget.NewSeparator())
			filterOptionChecksColumn.Add(widget.NewSeparator())

			return nil
		}

		// This function is used for desires which are not choice/numerical, so their value cannot be displayed automatically
		//TODO: Add a function to format the desire value to something readable
		addDesireRow_Custom := func(desireTitle string, desireName string, editPage func())error{

			editDesireButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), editPage)

			desireTitleLabel := getBoldLabelCentered(desireTitle)

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

				desireExists, _, err := myLocalDesires.GetDesire(desireName)
				if (err != nil) { return nil, err }
				if (desireExists == false){
					noPreferenceLabel := getItalicLabelCentered("No Preference")
					return noPreferenceLabel, nil
				}

				customLabel := getBoldItalicLabelCentered("Custom")

				return customLabel, nil
			}

			desireValueLabel, err := getDesireValueLabel()
			if (err != nil) { return err }

			filterAllCheck, err := getFilterOptionCheck(desireName, "FilterAll")
			if (err != nil) { return err }

			requireResponseCheck, err := getFilterOptionCheck(desireName, "RequireResponse")
			if (err != nil) { return err }

			desireButtonsColumn.Add(editDesireButton)
			desireButtonsColumn.Add(widget.NewLabel(""))

			desireNameAndDataColumn.Add(desireTitleLabel)
			desireNameAndDataColumn.Add(desireValueLabel)

			filterOptionChecksColumn.Add(filterAllCheck)
			filterOptionChecksColumn.Add(requireResponseCheck)

			desireButtonsColumn.Add(widget.NewSeparator())
			desireNameAndDataColumn.Add(widget.NewSeparator())
			filterOptionChecksColumn.Add(widget.NewSeparator())

			return nil
		}

		editAgeDesirePage := func(){setChooseDesiresPage_Age(window, currentPage)}
		err := addDesireRow_Numerical("Age", "Age", editAgeDesirePage, "Bar", "Age")
		if (err != nil){ return nil, err }

		editHeightDesirePage := func(){setChooseDesiresPage_Height(window, currentPage)}
		err = addDesireRow_Numerical("Height", "Height", editHeightDesirePage, "Bar", "Height")
		if (err != nil){ return nil, err }

		editWealthDesirePage := func(){setChooseDesiresPage_Wealth(window, currentPage)}
		err = addDesireRow_Numerical("Wealth", "Wealth", editWealthDesirePage, "Bar", "WealthInGold")
		if (err != nil){ return nil, err }

		editSexDesirePage := func(){setChooseDesiresPage_Sex(window, currentPage)}
		err = addDesireRow_Choice("Sex", "Sex", editSexDesirePage, "Donut", "Sex")
		if (err != nil){ return nil, err }

		editProfileLanguageDesirePage := func(){setChooseDesiresPage_ProfileLanguage(window, currentPage)}
		err = addDesireRow_Choice("Profile Language", "ProfileLanguage", editProfileLanguageDesirePage, "Bar", "ProfileLanguage")
		if (err != nil){ return nil, err }

		editCountryDesirePage := func(){setChooseDesiresPage_Country(window, currentPage)}
		err = addDesireRow_Choice("Country", "PrimaryLocationCountry", editCountryDesirePage, "Donut", "PrimaryLocationCountry")
		if (err != nil){ return nil, err }

		editSearchTermsDesirePage := func(){setChooseDesiresPage_SearchTerms(window, currentPage)}
		err = addDesireRow_Choice("Search Terms", "SearchTerms", editSearchTermsDesirePage, "Donut", "SearchTermsCount")
		if (err != nil){ return nil, err }

		editHasMessagedMeDesirePage := func(){setChooseDesiresPage_HasMessagedMe(window, currentPage)}
		err = addDesireRow_Choice("Has Messaged Me", "HasMessagedMe", editHasMessagedMeDesirePage, "Donut", "HasMessagedMe")
		if (err != nil){ return nil, err }

		editIHaveMessagedDesirePage := func(){setChooseDesiresPage_IHaveMessaged(window, currentPage)}
		err = addDesireRow_Choice("I Have Messaged", "IHaveMessaged", editIHaveMessagedDesirePage, "Donut", "IHaveMessaged")
		if (err != nil){ return nil, err }

		editHasRejectedMeDesirePage := func(){setChooseDesiresPage_HasRejectedMe(window, currentPage)}
		err = addDesireRow_Choice("Has Rejected Me", "HasRejectedMe", editHasRejectedMeDesirePage, "Donut", "HasRejectedMe")
		if (err != nil){ return nil, err }

		editIsLikedDesirePage := func(){setChooseDesiresPage_LikedUsers(window, currentPage)}
		err = addDesireRow_Choice("Is Liked", "IsLiked", editIsLikedDesirePage, "Donut", "IsLiked")
		if (err != nil){ return nil, err }

		editIsIgnoredDesirePage := func(){setChooseDesiresPage_IgnoredUsers(window, currentPage)}
		err = addDesireRow_Choice("Is Ignored", "IsIgnored", editIsIgnoredDesirePage, "Donut", "IsIgnored")
		if (err != nil){ return nil, err }

		editIsMyContactDesirePage := func(){setChooseDesiresPage_Contacts(window, currentPage)}
		err = addDesireRow_Choice("Is My Contact", "IsMyContact", editIsMyContactDesirePage, "Donut", "IsMyContact")
		if (err != nil){ return nil, err }

		editDistanceDesirePage := func(){setChooseDesiresPage_Distance(window, currentPage)}
		err = addDesireRow_Numerical("Distance", "Distance", editDistanceDesirePage, "Bar", "Distance")
		if (err != nil){ return nil, err }

		editSexualityDesirePage := func(){setChooseDesiresPage_Sexuality(window, currentPage)}
		err = addDesireRow_Choice("Sexuality", "Sexuality", editSexualityDesirePage, "Donut", "Sexuality")
		if (err != nil){ return nil, err }

		editBodyFatDesirePage := func(){setChooseDesiresPage_BodyFat(window, currentPage)}
		err = addDesireRow_Choice("Body Fat", "BodyFat", editBodyFatDesirePage, "Donut", "BodyFat")
		if (err != nil){ return nil, err }

		editBodyMuscleDesirePage := func(){setChooseDesiresPage_BodyMuscle(window, currentPage)}
		err = addDesireRow_Choice("Body Muscle", "BodyMuscle", editBodyMuscleDesirePage, "Donut", "BodyMuscle")
		if (err != nil){ return nil, err }

		editEyeColorDesirePage := func(){setChooseDesiresPage_EyeColor(window, currentPage)}
		err = addDesireRow_Choice("Eye Color", "EyeColor", editEyeColorDesirePage, "Donut", "EyeColor")
		if (err != nil){ return nil, err }

		editSkinColorDesirePage := func(){setChooseDesiresPage_SkinColor(window, currentPage)}
		err = addDesireRow_Choice("Skin Color", "SkinColor", editSkinColorDesirePage, "Donut", "SkinColor")
		if (err != nil){ return nil, err }

		editHairColorDesirePage := func(){setChooseDesiresPage_HairColor(window, currentPage)}
		err = addDesireRow_Choice("Hair Color", "HairColor", editHairColorDesirePage, "Donut", "HairColor")
		if (err != nil){ return nil, err }

		editHairTextureDesirePage := func(){setChooseDesiresPage_HairTexture(window, currentPage)}
		err = addDesireRow_Choice("Hair Texture", "HairTexture", editHairTextureDesirePage, "Donut", "HairTexture")
		if (err != nil){ return nil, err }

		editHasHIVDesirePage := func(){setChooseDesiresPage_Infections(window, currentPage)}
		err = addDesireRow_Choice("Has HIV", "HasHIV", editHasHIVDesirePage, "Donut", "HasHIV")
		if (err != nil){ return nil, err }

		editHasGenitalHerpesDesirePage := func(){setChooseDesiresPage_Infections(window, currentPage)}
		err = addDesireRow_Choice("Has Genital Herpes", "HasGenitalHerpes", editHasGenitalHerpesDesirePage, "Donut", "HasGenitalHerpes")
		if (err != nil){ return nil, err }

		foodNamesList := []string{
			"Fruit",
			"Vegetables",
			"Nuts",
			"Grains",
			"Dairy",
			"Seafood",
			"Beef",
			"Pork",
			"Poultry",
			"Eggs",
			"Beans",
		}

		for _, foodName := range foodNamesList{

			foodRatingDesireTitle := foodName + " Rating"
			foodRatingDesireName := foodName + "Rating"

			editFoodRatingDesirePage := func(){setChooseDesiresPage_FoodRating(window, foodName, currentPage)}
			err = addDesireRow_Choice(foodRatingDesireTitle, foodRatingDesireName, editFoodRatingDesirePage, "Bar", foodRatingDesireName)
			if (err != nil){ return nil, err }
		}

		editFameDesirePage := func(){setChooseDesiresPage_Fame(window, currentPage)}
		err = addDesireRow_Choice("Fame", "Fame", editFameDesirePage, "Bar", "Fame")
		if (err != nil){ return nil, err }

		editAlcoholFrequencyDesirePage := func(){setChooseDesiresPage_DrugFrequency(window, "Alcohol", currentPage)}
		err = addDesireRow_Choice("Alcohol Frequency", "AlcoholFrequency", editAlcoholFrequencyDesirePage, "Bar", "AlcoholFrequency")
		if (err != nil){ return nil, err }

		editTobaccoFrequencyDesirePage := func(){setChooseDesiresPage_DrugFrequency(window, "Tobacco", currentPage)}
		err = addDesireRow_Choice("Tobacco Frequency", "TobaccoFrequency", editTobaccoFrequencyDesirePage, "Bar", "TobaccoFrequency")
		if (err != nil){ return nil, err }

		editCannabisFrequencyDesirePage := func(){setChooseDesiresPage_DrugFrequency(window, "Cannabis", currentPage)}
		err = addDesireRow_Choice("Cannabis Frequency", "CannabisFrequency", editCannabisFrequencyDesirePage, "Bar", "CannabisFrequency")
		if (err != nil){ return nil, err }

		editGenderIdentityDesirePage := func(){setChooseDesiresPage_GenderIdentity(window, currentPage)}
		err = addDesireRow_Choice("Gender Identity", "GenderIdentity", editGenderIdentityDesirePage, "Donut", "GenderIdentity")
		if (err != nil){ return nil, err }

		editPetsRatingDesirePage := func(){setChooseDesiresPage_Pets(window, currentPage)}
		err = addDesireRow_Choice("Pets Rating", "PetsRating", editPetsRatingDesirePage, "Bar", "PetsRating")
		if (err != nil){ return nil, err }

		editDogsRatingDesirePage := func(){setChooseDesiresPage_Pets(window, currentPage)}
		err = addDesireRow_Choice("Dogs Rating", "DogsRating", editDogsRatingDesirePage, "Bar", "DogsRating")
		if (err != nil){ return nil, err }

		editCatsRatingDesirePage := func(){setChooseDesiresPage_Pets(window, currentPage)}
		err = addDesireRow_Choice("Cats Rating", "CatsRating", editCatsRatingDesirePage, "Bar", "CatsRating")
		if (err != nil){ return nil, err }

		editOffspringProbabilityOfAnyMonogenicDiseaseDesirePage := func(){setChooseDesiresPage_MonogenicDiseases(window, currentPage)}
		err = addDesireRow_Numerical("Offspring Probability Of Any Monogenic Disease", "OffspringProbabilityOfAnyMonogenicDisease", editOffspringProbabilityOfAnyMonogenicDiseaseDesirePage, "Donut", "OffspringProbabilityOfAnyMonogenicDisease")
		if (err != nil){ return nil, err }

		edit23andMeMaternalHaplogroupDesirePage := func(){setChooseDesiresPage_23andMe_Haplogroup(window, "Maternal", currentPage)}
		err = addDesireRow_Choice("23andMe Maternal Haplogroup", "23andMe_MaternalHaplogroup", edit23andMeMaternalHaplogroupDesirePage, "Bar", "23andMe_MaternalHaplogroup")
		if (err != nil){ return nil, err }

		edit23andMePaternalHaplogroupDesirePage := func(){setChooseDesiresPage_23andMe_Haplogroup(window, "Paternal", currentPage)}
		err = addDesireRow_Choice("23andMe Paternal Haplogroup", "23andMe_PaternalHaplogroup", edit23andMePaternalHaplogroupDesirePage, "Bar", "23andMe_PaternalHaplogroup")
		if (err != nil){ return nil, err }

		edit23andMeNeanderthalVariantsDesirePage := func(){setChooseDesiresPage_23andMe_NeanderthalVariants(window, currentPage)}
		err = addDesireRow_Numerical("23andMe Neanderthal Variants", "23andMe_NeanderthalVariants", edit23andMeNeanderthalVariantsDesirePage, "Donut", "23andMe_NeanderthalVariants")
		if (err != nil){ return nil, err }

		edit23andMeAncestryCompositionDesirePage := func(){setChooseDesiresPage_23andMe_AncestryComposition(window, "User", currentPage)}
		err = addDesireRow_Custom("23andMe Ancestry Composition", "23andMe_AncestryComposition", edit23andMeAncestryCompositionDesirePage)
		if (err != nil){ return nil, err }

		editLanguageDesirePage := func(){setChooseDesiresPage_Language(window, currentPage)}
		err = addDesireRow_Custom("Language", "Language", editLanguageDesirePage)
		if (err != nil){ return nil, err }

		allDesiresGrid := container.NewHBox(layout.NewSpacer(), widget.NewSeparator(), desireButtonsColumn, widget.NewSeparator(), desireNameAndDataColumn, widget.NewSeparator(), filterOptionChecksColumn, widget.NewSeparator(), layout.NewSpacer())

		return allDesiresGrid, nil
	}

	allDesiresGrid, err := getAllDesiresGrid()
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

	setPageContent(page, window)
}


func setManageMateDownloadDesiresPage(window fyne.Window, previousPage func()){
	
	currentPage := func(){setManageMateDownloadDesiresPage(window, previousPage)}
	
	title := getPageTitleCentered("My Mate Download Desires")

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("My Mate Download Desires")

	description1 := getLabelCentered("Seekia downloads mate profiles from network hosts.")
	description2 := getLabelCentered("These are servers run by volunteers.")
	description3 := getLabelCentered("Your download desires are shared to hosts when you download profiles.")
	description4 := getLabelCentered("These desires limit the profiles you download.")
	description5 := getLabelCentered("You can choose how much information to share.")
	description6 := getLabelCentered("The more desires you share, the less time it will take to download profiles.")
	description7 := getLabelCentered("The hosts could be tracking this information, so more desires will reduce your privacy.")
	description8 := getLabelCentered("All profiles are downloaded over the Tor anonymity network.")

	chooseDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("Choose Desires", theme.NavigateNextIcon(), func(){
			setChooseMateDownloadDesiresPage(window, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8, chooseDesiresButton)

	setPageContent(page, window)
}



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

	setLoadingScreen(window, "Choose Mate Download Desires", "Loading Download Desires...")

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

	title := getPageTitleCentered("Choose Mate Download Desires")

	backButton := getBackButtonCentered(previousPage)

	description1 := getLabelCentered("You will share the selected desires with Hosts when you download profiles.")
	description2 := getLabelCentered("These desires will not be displayed on your profile.")
	description3 := getLabelCentered("Each desire will only be shared if you have enabled Filter All or Require Response")
	description4 := getLabelCentered("Select each desire you are comfortable sharing with hosts.")

	//TODO: Add Help buttons to explain this better
	// User should understand that the hosts will not necessarily know who they are.
	// They will make requests over Tor, and their requestor fingerprint will be defined by these desires
	// Each shared desire will increase the entropy of a requestor's fingerprint
	// Most requestors will probably have a very unique fingerprint
	//
	// The challenge for malicious hosts will be to link a requestor fingerprint to a requestor's mate identity
	// This may be difficult or easy, depending on how similar the requestor's desires are to their own profile

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

		desireTitlesColumn := container.NewVBox()
		desireSelectChecksColumn := container.NewVBox()

		desireNameLabel := getItalicLabelCentered("Desire Name:")
		shareDesireLabel := getItalicLabelCentered("Share Desire?")

		desireTitlesColumn.Add(desireNameLabel)
		desireSelectChecksColumn.Add(shareDesireLabel)

		desireTitlesColumn.Add(widget.NewSeparator())
		desireSelectChecksColumn.Add(widget.NewSeparator())

		allMyDownloadDesiresList := myMateCriteria.GetAllMyMateDownloadDesiresList()

		for _, desireName := range allMyDownloadDesiresList{

			desireTitle, err := mateDesires.GetDesireTitleFromDesireName(desireName)
			if (err != nil) { return nil, err }

			desireTitleLabel := getBoldLabelCentered(translate(desireTitle))

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

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

						err := myMateCriteria.SetShareMyDesireStatus(desireName, selected)
						if (err != nil){
							setErrorEncounteredPage(window, err, currentPage)
							return
						}
					})

				isSelected, err := myMateCriteria.GetShareMyDesireStatus(desireName)
				if (err != nil){ return nil, err }
				if (isSelected == true){
					selectCheck.Checked = true
				}

				return selectCheck, nil
			}

			desireSelectCheck, err := getDesireSelectCheck()
			if (err != nil) { return nil, err }

			desireSelectCheckCentered := getWidgetCentered(desireSelectCheck)

			desireTitlesColumn.Add(desireTitleLabel)
			desireSelectChecksColumn.Add(desireSelectCheckCentered)

			desireTitlesColumn.Add(widget.NewSeparator())
			desireSelectChecksColumn.Add(widget.NewSeparator())
		}
	
		desiresGrid := container.NewHBox(layout.NewSpacer(), desireTitlesColumn, desireSelectChecksColumn, layout.NewSpacer())

		return desiresGrid, nil
	}

	desiresGrid, err := getDesiresGrid()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

	setPageContent(page, window)
}


