package gui

// buildProfileGui_Physical.go implements pages to build the Physical portion of a user's mate profile

import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/canvas"
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/genetics/companyAnalysis"
import "seekia/internal/genetics/myChosenAnalysis"
import "seekia/internal/genetics/myGenomes"
import "seekia/internal/genetics/myPeople"
import "seekia/internal/genetics/geneticReferences/traits"
import "seekia/internal/genetics/geneticReferences/monogenicDiseases"
import "seekia/internal/genetics/geneticReferences/polygenicDiseases"
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "seekia/internal/profiles/myLocalProfiles"

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

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

	currentPage := func(){ setBuildMateProfileCategoryPage_Physical(window, previousPage) }
	
	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	sexButton := widget.NewButton(translate("Sex"), func(){
			setBuildMateProfilePage_Sex(window, currentPage)
		})

	ancestryCompositionButton := widget.NewButton("Ancestry Composition", func(){
			setBuildMateProfilePage_23andMe_AncestryComposition(window, currentPage)
		})

	neanderthalVariantsButton := widget.NewButton("Neanderthal Variants", func(){
			setBuildMateProfilePage_23andMe_NeanderthalVariants(window, currentPage)
		})

	maternalHaplogroupButton := widget.NewButton("Maternal Haplogroup", func(){
			setBuildMateProfilePage_23andMe_Haplogroup(window, "Maternal", currentPage)
		})

	paternalHaplogroupButton := widget.NewButton("Paternal Haplogroup", func(){
			setBuildMateProfilePage_23andMe_Haplogroup(window, "Paternal", currentPage)
		})

	geneticInformationButton := widget.NewButton(translate("Genetic Information"), func(){
			setBuildMateProfilePage_GeneticInformation(window, currentPage)
		})
	
	heightButton := widget.NewButton(translate("Height"), func(){
			setBuildMateProfilePage_Height(window, currentPage)
		})
	
	bodyButton := widget.NewButton(translate("Body"), func(){
			setBuildMateProfilePage_Body(window, currentPage)
		})

	eyeColorButton := widget.NewButton(translate("Eye Color"), func(){
			setBuildMateProfilePage_EyeColor(window, currentPage)
		})

	hairColorButton := widget.NewButton(translate("Hair Color"), func(){
			setBuildMateProfilePage_HairColor(window, currentPage)
		})
	
	hairTextureButton := widget.NewButton(translate("Hair Texture"), func(){
			setBuildMateProfilePage_HairTexture(window, currentPage)
		})
	
	skinColorButton := widget.NewButton(translate("Skin Color"), func(){
			setBuildMateProfilePage_SkinColor(window, currentPage)
		})

	infectionsButton := widget.NewButton(translate("Infections"), func(){
			setBuildMateProfilePage_Infections(window, currentPage)
		})
	
	buttonsGrid := container.NewGridWithColumns(1, sexButton, ancestryCompositionButton, neanderthalVariantsButton, maternalHaplogroupButton, paternalHaplogroupButton, geneticInformationButton, heightButton, bodyButton, eyeColorButton, hairColorButton, hairTextureButton, skinColorButton, infectionsButton)

	buttonsGridCentered := getContainerCentered(buttonsGrid)

	buttonsGridPadded := container.NewPadded(buttonsGridCentered)

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

	setPageContent(page, window)
}


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

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

	pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("Sex"))

	sexDescription := widget.NewLabel(translate("What is your physical sex?"))
	sexHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
			setSexExplainerPage(window, currentPage)
		})

	sexDescriptionRow := container.NewHBox(layout.NewSpacer(), sexDescription, sexHelpButton, layout.NewSpacer())

	option1Translated := translate("Male")
	option2Translated := translate("Female")
	option3Translated := translate("Intersex Male")
	option4Translated := translate("Intersex Female")
	option5Translated := translate("Intersex")

	untranslatedOptionsMap := map[string]string{
		option1Translated: "Male",
		option2Translated: "Female",
		option3Translated: "Intersex Male",
		option4Translated: "Intersex Female",
		option5Translated: "Intersex",
	}

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

	sexSelector := widget.NewRadioGroup(sexSelectorOptions, func(response string){

			if (response == ""){
				err := myLocalProfiles.DeleteProfileData("Mate", "Sex")
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				return
			}

			responseUntranslated, exists := untranslatedOptionsMap[response]
			if (exists == false){
				setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing response: " + response), currentPage)
				return
			}
			err := myLocalProfiles.SetProfileData("Mate", "Sex", responseUntranslated)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
		})

	exists, currentSex, err := myLocalProfiles.GetProfileData("Mate", "Sex")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (exists == true){
		if (currentSex != "Male" && currentSex != "Female" && currentSex != "Intersex Male" && currentSex != "Intersex Female" && currentSex != "Intersex"){
			setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid Sex: " + currentSex), previousPage)
			return
		}
		sexSelector.Selected = translate(currentSex)
	}
	sexSelectorCentered := getWidgetCentered(sexSelector)

	sexNoResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
			err := myLocalProfiles.DeleteProfileData("Mate", "Sex")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}))

	page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), sexDescriptionRow, sexSelectorCentered, sexNoResponseButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("23andMe Ancestry Composition")

	description := getLabelCentered("Enter your 23andMe ancestry location composition.")

	exists, myAncestryCompositionAttribute, err := myLocalProfiles.GetProfileData("Mate", "23andMe_AncestryComposition")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (exists == false){

		noCompositionFoundLabel := getBoldLabelCentered("No ancestry composition exists.")

		addCompositionButton := getWidgetCentered(widget.NewButtonWithIcon("Add Composition", theme.ContentAddIcon(), func(){

				emptyMapA := make(map[string]float64)
				emptyMapB := make(map[string]float64)
				emptyMapC := make(map[string]float64)
				setBuildMateProfilePage_23andMe_EditAncestryComposition(window, emptyMapA, emptyMapB, emptyMapC, currentPage, currentPage)
			}))

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

		setPageContent(page, window)
		return
	}

	visibilityLabel := getBoldLabel("Visibility:")

	visibilityOptions := []string{translate("Show On Profile"), translate("Hide From Profile")}
	visibilitySelector := widget.NewSelect(visibilityOptions, func(newVisibility string){

			getNewVisibilityStatus := func()string{

				if (newVisibility == translate("Show On Profile")){
					return "Yes"				
				}
	
				return "No"
			}

			newVisibilityStatus := getNewVisibilityStatus()

			err := myLocalProfiles.SetProfileData("Mate", "VisibilityStatus_23andMe_AncestryComposition", newVisibilityStatus)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
		})

	exists, visibilityStatus, err := myLocalProfiles.GetProfileData("Mate", "VisibilityStatus_23andMe_AncestryComposition")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (exists == true && visibilityStatus == "No"){
		visibilitySelector.Selected = translate("Hide From Profile")
	} else {
		visibilitySelector.Selected = translate("Show On Profile")
	}

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

	visibilitySelectorRow := container.NewHBox(layout.NewSpacer(), visibilityLabel, visibilitySelector, profileVisibilityHelpButton, layout.NewSpacer())

	attributeIsValid, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, err := companyAnalysis.ReadAncestryCompositionAttribute_23andMe(true, myAncestryCompositionAttribute)
	if (err != nil){
		setErrorEncounteredPage(window, err, currentPage)
		return
	}
	if (attributeIsValid == false){
		setErrorEncounteredPage(window, errors.New("MyLocalProfiles 23andMe ancestry composition attribute is invalid."), currentPage)
		return
	}

	editCompositionButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), func(){
			setBuildMateProfilePage_23andMe_EditAncestryComposition(window, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, currentPage, currentPage)
		})

	noResponseButton := widget.NewButtonWithIcon("No Response", theme.CancelIcon(), func(){
			setBuildMateProfilePage_23andMe_ConfirmDeleteAncestryComposition(window, currentPage, currentPage)
		})

	buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, editCompositionButton, noResponseButton))

	myCompositionLabel := getBoldLabelCentered("My Composition:")

	myCompositionDisplay, err := get23andMeAncestryCompositionDisplay(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	header := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), visibilitySelectorRow, widget.NewSeparator(), buttonsGrid, widget.NewSeparator(), myCompositionLabel)

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

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	description1 := getBoldLabelCentered("Delete Ancestry Composition?")

	description2 := getLabelCentered("Confirm to delete your 23andMe ancestry composition?")
	confirmButton := getWidgetCentered(widget.NewButtonWithIcon("Confirm", theme.ConfirmIcon(), func(){
			err := myLocalProfiles.DeleteProfileData("Mate", "23andMe_AncestryComposition")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			nextPage()
		}))

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

	setPageContent(page, window)
}

func setBuildMateProfilePage_23andMe_EditAncestryComposition(window fyne.Window, myContinentPercentagesMap map[string]float64, myRegionPercentagesMap map[string]float64, mySubregionPercentagesMap map[string]float64, previousPage func(), afterCompletePage func()){

	currentPage := func(){setBuildMateProfilePage_23andMe_EditAncestryComposition(window, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, afterCompletePage)}

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButtonFunction := func(){

		confirmDialogCallbackFunction := func(response bool){
			if (response == true){
				previousPage()
			}
		}

		dialogTitle := translate("Confirm Go Back")
		dialogMessageA := getLabelCentered("Confirm to go back?")
		dialogMessageB := getLabelCentered("You will lose any changes you made.")
		dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
		dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
	}

	backButton := getBackButtonCentered(backButtonFunction)

	subtitle := getPageSubtitleCentered("Build 23andMe Ancestry Composition")

	// We use this function to make changes and return to this page
	currentPageWithNewPercentagesFunction := func(newContinentPercentagesMap map[string]float64, newRegionPercentagesMap map[string]float64, newSubregionPercentagesMap map[string]float64){

		setBuildMateProfilePage_23andMe_EditAncestryComposition(window, newContinentPercentagesMap, newRegionPercentagesMap, newSubregionPercentagesMap, previousPage, afterCompletePage)
	}

	addLocationButton := widget.NewButtonWithIcon("Add Location", theme.ContentAddIcon(), func(){

			setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, false, "", false, "", false, "", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, currentPage, currentPageWithNewPercentagesFunction)
		})

	if (len(myContinentPercentagesMap) == 0 && len(myRegionPercentagesMap) == 0 && len(mySubregionPercentagesMap) == 0){

		addLocationButtonCentered := getWidgetCentered(addLocationButton)

		noCompositionExistsLabel := getBoldLabelCentered("No locations added.")

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

		setPageContent(page, window)
		return
	}

	deleteLocationButton := widget.NewButtonWithIcon("Delete Location", theme.DeleteIcon(), func(){

			setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation(window, "Continent", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, currentPage, currentPageWithNewPercentagesFunction)
		})

	addAndDeleteLocationButtons := getContainerCentered(container.NewGridWithRows(1, addLocationButton, deleteLocationButton))

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

			inputsAreValid, newAncestryCompositionAttribute, err := companyAnalysis.CreateAncestryCompositionAttribute_23andMe(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			if (inputsAreValid == false){
				dialogTitle := translate("Invalid Ancestry Composition")
				dialogMessageA := getBoldLabelCentered(translate("The ancestry composition you entered is invalid."))
				dialogMessageB := getLabelCentered(translate("All continent percentages must add to 100."))
				dialogMessageC := getLabelCentered(translate("All region percentages must add up to their continent percentage."))
				dialogMessageD := getLabelCentered(translate("All subregion percentages must add up to their region percentage."))
				dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC, dialogMessageD)
				dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
				return
			}

			setBuildMateProfilePage_23andMe_ConfirmUpdateAncestryComposition(window, newAncestryCompositionAttribute, currentPage, afterCompletePage)
		}))

	emptyLabel := widget.NewLabel("")

	footer := container.NewVBox(widget.NewSeparator(), submitButton, emptyLabel)

	myCompositionTree, err := get23andMeAncestryCompositionDisplay(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

	page := container.NewBorder(header, footer, nil, nil, myCompositionTree)

	setPageContent(page, window)	
}

func setBuildMateProfilePage_23andMe_ConfirmUpdateAncestryComposition(window fyne.Window, newAncestryCompositionAttribute string, previousPage func(), nextPage func()){

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	description1 := getBoldLabelCentered("Add Ancestry Composition?")

	description2 := getLabelCentered("Confirm update your ancestry composition?")
	description3 := getLabelCentered("This will be visible on your profile.")

	confirmButton := getWidgetCentered(widget.NewButtonWithIcon("Confirm", theme.ConfirmIcon(), func(){
			err := myLocalProfiles.SetProfileData("Mate", "23andMe_AncestryComposition", newAncestryCompositionAttribute)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}

			nextPage()
		}))

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

	setPageContent(page, window) 
}

func setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(
		window fyne.Window,
		continentProvided bool,
		currentContinent string,
		regionProvided bool,
		currentRegion string,
		subregionProvided bool,
		currentSubregion string,
		myContinentPercentagesMap map[string]float64,
		myRegionPercentagesMap map[string]float64,
		mySubregionPercentagesMap map[string]float64,
		previousPage func(),
		nextPage func(map[string]float64, map[string]float64, map[string]float64)){

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Add 23andMe Ancestry Location")

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

		continentLabel := getBoldLabel("Continent:")

		allContinentsList := companyAnalysis.GetAncestryContinentsList_23andMe()

		handleContinentSelectFunction := func(newContinent string){
				if (continentProvided == true && newContinent == currentContinent){
					return
				}

				setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, true, newContinent, false, "", false, "", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
			}

		continentSelector := widget.NewSelect(allContinentsList, handleContinentSelectFunction)
		if (continentProvided == true){
			continentSelector.Selected = currentContinent
		}

		continentRow := container.NewHBox(layout.NewSpacer(), continentLabel, continentSelector, layout.NewSpacer())

		if (continentProvided == false){

			pageContent := container.NewVBox(continentRow)
			return pageContent, nil
		}

		percentageLabel := getBoldLabelCentered("Percentage:")

		percentageEntry := widget.NewEntry()
		percentageEntry.SetPlaceHolder("Enter percentage.")

		percentageRow := getContainerCentered(container.NewGridWithRows(1, percentageLabel, percentageEntry))

		showInvalidPercentageDialog := func(){
			dialogTitle := translate("Invalid Percentage")
			dialogMessageA := getLabelCentered(translate("The location percentage is invalid."))
			dialogMessageB := getLabelCentered(translate("You must enter a number between 0 and 100."))
			dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
			dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
		}

		regionsList, err := companyAnalysis.GetAncestryContinentRegionsList_23andMe(currentContinent)
		if (err != nil) { return nil, err }
		
		if (len(regionsList) == 0){

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

					newPercentageRaw := percentageEntry.Text
					newPercentage := strings.TrimSuffix(newPercentageRaw, "%")

					newPercentageFloat64, err := helpers.ConvertStringToFloat64(newPercentage)
					if (err != nil){
						showInvalidPercentageDialog()
						return
					}

					if (newPercentageFloat64 <= 0 || newPercentageFloat64 > 100){
						showInvalidPercentageDialog()
						return
					}

					addContinentFunction := func(){
						myContinentPercentagesMap[currentContinent] = newPercentageFloat64

						nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
					}

					existingPercentage, exists := myContinentPercentagesMap[currentContinent]
					if (exists == false){

						addContinentFunction()
						return
					}

					// We allow user to confirm they want to overwrite existing value	
		
					currentPercentageString := helpers.ConvertFloat64ToStringRounded(existingPercentage, 1)

					confirmDialogCallbackFunction := func(response bool){
						if (response == true){
							addContinentFunction()	
						}
					}

					dialogTitle := translate("Confirm Overwrite Existing")
					dialogMessageA := getLabelCentered("You already have a percentage for " + currentContinent)
					dialogMessageB := getLabelCentered("Current Percentage: " + currentPercentageString + "%")
					dialogMessageC := getLabelCentered("Confirm to overwrite this percentage?")
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
					dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
				}))

			pageContent := container.NewVBox(continentRow, widget.NewSeparator(), percentageRow, submitButton)

			return pageContent, nil
		}

		regionLabel := getBoldLabel("Region:")

		handleRegionSelectFunction := func(newRegion string){

			if (regionProvided == true && currentRegion == newRegion){
				return
			}

			setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, true, currentContinent, true, newRegion, false, "", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
		}

		regionSelector := widget.NewSelect(regionsList, handleRegionSelectFunction)

		if (regionProvided == true){
			regionSelector.Selected = currentRegion
		}

		regionRow := container.NewHBox(layout.NewSpacer(), regionLabel, regionSelector, layout.NewSpacer())

		if (regionProvided == false){

			pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow)

			return pageContent, nil
		}

		subregionsList, err := companyAnalysis.GetAncestryRegionSubregionsList_23andMe(currentContinent, currentRegion)
		if (err != nil) { return nil, err }		

		if (len(subregionsList) == 0){

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

					newPercentageRaw := percentageEntry.Text
					newPercentage := strings.TrimSuffix(newPercentageRaw, "%")

					newPercentageFloat64, err := helpers.ConvertStringToFloat64(newPercentage)
					if (err != nil){
						showInvalidPercentageDialog()
						return
					}

					if (newPercentageFloat64 <= 0 || newPercentageFloat64 > 100){
						showInvalidPercentageDialog()
						return
					}

					addRegionFunction := func(){
						myRegionPercentagesMap[currentRegion] = newPercentageFloat64

						nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
					}

					existingPercentage, exists := myRegionPercentagesMap[currentRegion]
					if (exists == false){

						addRegionFunction()
						return
					}

					// We allow user to confirm they want to overwrite existing value

					currentPercentageString := helpers.ConvertFloat64ToStringRounded(existingPercentage, 1)

					confirmDialogCallbackFunction := func(response bool){
						if (response == true){
							addRegionFunction()
						}
					}

					dialogTitle := translate("Confirm Overwrite Existing")
					dialogMessageA := getLabelCentered("You already have a percentage for " + currentRegion)
					dialogMessageB := getLabelCentered("Current Percentage: " + currentPercentageString + "%")
					dialogMessageC := getLabelCentered("Confirm to overwrite this percentage?")
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
					dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
				}))

			pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow, widget.NewSeparator(), percentageRow, submitButton)

			return pageContent, nil
		}

		subregionLabel := getBoldLabel("Subregion:")

		handleSubregionSelectFunction := func(newSubregion string){

			if (subregionProvided == true && currentSubregion == newSubregion){
				return
			}

			setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, true, currentContinent, true, currentRegion, true, newSubregion, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
		}

		subregionSelector := widget.NewSelect(subregionsList, handleSubregionSelectFunction)
		if (subregionProvided == true){
			subregionSelector.Selected = currentSubregion
		}

		subregionRow := container.NewHBox(layout.NewSpacer(), subregionLabel, subregionSelector, layout.NewSpacer())

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

				if (subregionProvided == false){

					dialogTitle := translate("Missing Subregion")
					dialogMessage := getLabelCentered(translate("You must select a subregion."))
					dialogContent := container.NewVBox(dialogMessage)
					dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
					return
				}

				newPercentageRaw := percentageEntry.Text
				newPercentage := strings.TrimSuffix(newPercentageRaw, "%")

				newPercentageFloat64, err := helpers.ConvertStringToFloat64(newPercentage)
				if (err != nil){
					showInvalidPercentageDialog()
					return
				}

				if (newPercentageFloat64 <= 0 || newPercentageFloat64 > 100){
					showInvalidPercentageDialog()
					return
				}

				addSubregionFunction := func(){
					mySubregionPercentagesMap[currentSubregion] = newPercentageFloat64

					nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
				}

				existingPercentage, exists := mySubregionPercentagesMap[currentSubregion]
				if (exists == false){

					addSubregionFunction()
					return
				}

				// We allow user to confirm they want to overwrite existing value
	
				currentPercentageString := helpers.ConvertFloat64ToStringRounded(existingPercentage, 1)

				confirmDialogCallbackFunction := func(response bool){
					if (response == true){
						addSubregionFunction()
					}
				}

				dialogTitle := translate("Confirm Overwrite Existing")
				dialogMessageA := getLabelCentered("You already have a percentage for " + currentSubregion)
				dialogMessageB := getLabelCentered("Current Percentage: " + currentPercentageString + "%")
				dialogMessageC := getLabelCentered("Confirm to overwrite this percentage?")
				dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
				dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
			}))

		pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow, widget.NewSeparator(), subregionRow, widget.NewSeparator(), percentageRow, submitButton)

		return pageContent, nil
	}

	pageContent, err := getPageContent()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

	setPageContent(page, window)
}

func setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation(
		window fyne.Window,
		locationType string,
		myContinentPercentagesMap map[string]float64,
		myRegionPercentagesMap map[string]float64,
		mySubregionPercentagesMap map[string]float64,
		previousPage func(),
		nextPage func(map[string]float64, map[string]float64, map[string]float64)){

	if (locationType != "Continent" && locationType != "Region" && locationType != "Subregion"){
		setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation called with invalid locationType: " + locationType), previousPage)
		return
	}

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	description := getLabelCentered("Select a location to delete.")

	locationTypeLabel := getBoldLabelCentered("Location Type")

	locationTypesList := []string{"Continent", "Region", "Subregion"}

	handleLocationTypeSelectFunction := func(newLocationType string){
		if (newLocationType == locationType){
			return
		}

		setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation(window, newLocationType, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
	}

	locationTypeSelector := widget.NewSelect(locationTypesList, handleLocationTypeSelectFunction)
	locationTypeSelector.Selected = locationType

	locationTypeSelectorCentered := getWidgetCentered(locationTypeSelector)

	// This function either returns a "No (locationType) Exists" label or the locations grid. 
	getLocationsSection := func()(*fyne.Container, error){

		if (locationType == "Continent" && len(myContinentPercentagesMap) == 0){
			locationsSection := getBoldLabelCentered("No continents exist.")
			return locationsSection, nil
		}
		if (locationType == "Region" && len(myRegionPercentagesMap) == 0){
			locationsSection := getBoldLabelCentered("No regions exist.")
			return locationsSection, nil
		}
		if (locationType == "Subregion" && len(mySubregionPercentagesMap) == 0){
			locationsSection := getBoldLabelCentered("No subregions exist.")
			return locationsSection, nil
		}

		locationLabel := getItalicLabelCentered(locationType)
		percentageLabel := getItalicLabelCentered("Percentage")
		emptyLabel := widget.NewLabel("")

		locationNameColumn := container.NewVBox(locationLabel, widget.NewSeparator())
		locationPercentageColumn := container.NewVBox(percentageLabel, widget.NewSeparator())
		deleteButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator())

		addLocationRow := func(locationName string, locationPercentage float64)error{

			locationNameLabel := getBoldLabelCentered(locationName)
			locationPercentageString := helpers.ConvertFloat64ToStringRounded(locationPercentage, 1)

			locationPercentageFormatted := locationPercentageString + "%"
			locationPercentageLabel := getBoldLabelCentered(locationPercentageFormatted)	

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

					if (locationType == "Continent"){

						delete(myContinentPercentagesMap, locationName)

					} else if (locationType == "Region"){

						delete(myRegionPercentagesMap, locationName)

					} else if (locationType == "Subregion") {

						delete(mySubregionPercentagesMap, locationName)
					}

					nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
				})

			locationNameColumn.Add(locationNameLabel)
			locationPercentageColumn.Add(locationPercentageLabel)
			deleteButtonsColumn.Add(deleteLocationButton)

			locationNameColumn.Add(widget.NewSeparator())
			locationPercentageColumn.Add(widget.NewSeparator())
			deleteButtonsColumn.Add(widget.NewSeparator())

			return nil
		}

		if (locationType == "Continent"){

			for continentName, continentPercentage := range myContinentPercentagesMap{
				err := addLocationRow(continentName, continentPercentage)
				if (err != nil){ return nil, err }		
			}
		} else if (locationType == "Region"){
			for regionName, regionPercentage := range myRegionPercentagesMap{
				err := addLocationRow(regionName, regionPercentage)
				if (err != nil){ return nil, err }
			}
		} else if (locationType == "Subregion"){

			for subregionName, subregionPercentage := range mySubregionPercentagesMap{
				err := addLocationRow(subregionName, subregionPercentage)
				if (err != nil){ return nil, err }
			}
		}

		locationsGrid := container.NewHBox(layout.NewSpacer(), locationNameColumn, locationPercentageColumn, deleteButtonsColumn, layout.NewSpacer())

		return locationsGrid, nil
	}

	locationsSection, err := getLocationsSection()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("23andMe - Neanderthal Variants"))

	description := getLabelCentered(translate("Enter how many neanderthal variants you have."))

	neanderthalVariantsEntry := widget.NewEntry()

	variantCountExists, currentNeanderthalVariants, err := myLocalProfiles.GetProfileData("Mate", "23andMe_NeanderthalVariants")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (variantCountExists == true){
		isValid, err := helpers.VerifyStringIsIntWithinRange(currentNeanderthalVariants, 0, 7462)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}
		if (isValid == false){
			setErrorEncounteredPage(window, errors.New("MyLocalProfile contains invalid 23andMe neanderthalvariants."), previousPage)
			return
		}

		neanderthalVariantsEntry.SetText(currentNeanderthalVariants)
	} else {
		neanderthalVariantsEntry.SetPlaceHolder(translate("Enter Variant Count"))
	}

	getCurrentNeanderthalVariantsCountLabel := func()fyne.Widget{

		if (variantCountExists == false){

			result := translate("No Response")

			variantsLabel := getBoldItalicLabel(result)
			return variantsLabel
		}

		variantsLabel := getBoldLabel(currentNeanderthalVariants)

		return variantsLabel
	}

	currentVariantCountLabel := getCurrentNeanderthalVariantsCountLabel()

	myVariantCountLabel := widget.NewLabel("My Variant Count:")

	currentVariantsCountRow := container.NewHBox(layout.NewSpacer(), myVariantCountLabel, currentVariantCountLabel, layout.NewSpacer())

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

		newVariantsCount := neanderthalVariantsEntry.Text

		isValid, err := helpers.VerifyStringIsIntWithinRange(newVariantsCount, 0, 7462)
		if (err != nil){
			setErrorEncounteredPage(window, err, currentPage)
			return
		}
		if (isValid == false){
			neanderthalVariantsEntry.SetText("")
			neanderthalVariantsEntry.SetPlaceHolder(translate("Enter Variant Count"))

			dialogTitle := translate("Invalid Variant Count")
			dialogMessageA := getLabelCentered(translate("Invalid neanderthal variants count entered."))
			dialogMessageB := getLabelCentered(translate("You must provide a number between 0 and 7462 variants."))
			dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
			dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
			return
		}

		err = myLocalProfiles.SetProfileData("Mate", "23andMe_NeanderthalVariants", newVariantsCount)
		if (err != nil){
			setErrorEncounteredPage(window, err, currentPage)
			return
		}

		currentPage()
	})

	variantsEntryWithSubmitButton := getContainerCentered(container.NewGridWithRows(1, neanderthalVariantsEntry, submitChangesButton))

	noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
			err := myLocalProfiles.DeleteProfileData("Mate", "23andMe_NeanderthalVariants")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description, widget.NewSeparator(), currentVariantsCountRow, widget.NewSeparator(), variantsEntryWithSubmitButton, noResponseButton)

	setPageContent(page, window)
}

func setBuildMateProfilePage_23andMe_Haplogroup(window fyne.Window, maternalOrPaternal string, previousPage func()){

	if (maternalOrPaternal != "Maternal" && maternalOrPaternal != "Paternal"){
		setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_23andMe_Haplogroup called with invalid maternalOrPaternal: " + maternalOrPaternal), previousPage)
		return
	}

	currentPage := func(){setBuildMateProfilePage_23andMe_Haplogroup(window, maternalOrPaternal, previousPage)}

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("23andMe - " + maternalOrPaternal + " Haplogroup"))

	maternalOrPaternalLowercase := strings.ToLower(maternalOrPaternal)

	description1 := getLabelCentered("Choose your " + maternalOrPaternalLowercase + " haplogroup.")
	description2 := getLabelCentered("If it is not listed, enter it in manually.")	

	getKnownHaplogroupsList := func()[]string{

		if (maternalOrPaternal == "Maternal"){
			maternalHaplogroupsList := companyAnalysis.GetKnownMaternalHaplogroupsList_23andMe()
			return maternalHaplogroupsList		
		}

		paternalHaplogroupsList := companyAnalysis.GetKnownPaternalHaplogroupsList_23andMe()
		return paternalHaplogroupsList
	}

	knownHaplogroupsList := getKnownHaplogroupsList()

	haplogroupEntry := widget.NewSelectEntry(knownHaplogroupsList)

	attributeName := "23andMe_" + maternalOrPaternal + "Haplogroup"

	haplogroupExists, currentHaplogroup, err := myLocalProfiles.GetProfileData("Mate", attributeName)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (haplogroupExists == true){

		if (len(currentHaplogroup) > 25){
			setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid haplogroup: " + currentHaplogroup), previousPage)
			return
		}

		haplogroupEntry.SetText(currentHaplogroup)
	} else {
		haplogroupEntry.SetPlaceHolder(translate("Select or enter haplogroup..."))
	}
	
	getCurrentHaplogroupLabel := func()fyne.Widget{

		if (haplogroupExists == false){
			result := translate("No Response")

			haplogroupLabel := getBoldItalicLabel(result)
			return haplogroupLabel
		}

		haplogroupLabel := getBoldLabel(currentHaplogroup)
		return haplogroupLabel
	}

	currentHaplogroupLabel := getCurrentHaplogroupLabel()

	myHaplogroupLabel := widget.NewLabel("My " + maternalOrPaternal + " Haplogroup:")

	currentHaplogroupRow := container.NewHBox(layout.NewSpacer(), myHaplogroupLabel, currentHaplogroupLabel, layout.NewSpacer())

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

		newHaplogroup := haplogroupEntry.Text

		if (newHaplogroup == ""){
			title := translate("Invalid Haplogroup")
			dialogMessageA := getLabelCentered(translate("Invalid haplogroup entered."))
			dialogMessageB := getLabelCentered(translate("Your haplogroup cannot be empty."))
			dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
			dialog.ShowCustom(title, translate("Close"), dialogContent, window)
			return
		}

		if (len(newHaplogroup) > 25){

			haplogroupEntry.SetText("")
			haplogroupEntry.SetPlaceHolder(translate("Select or enter haplogroup..."))

			title := translate("Invalid Haplogroup")
			dialogMessageA := getLabelCentered(translate("Invalid haplogroup entered."))
			dialogMessageB := getLabelCentered(translate("It must be less than 25 bytes."))
			dialogMessageC := getLabelCentered(translate("Contact the Seekia developers if this is too short to fit your haplogroup."))
			dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
			dialog.ShowCustom(title, translate("Close"), dialogContent, window)
			return
		}

		isAllowed := allowedText.VerifyStringIsAllowed(newHaplogroup)
		if (isAllowed == false){
			title := translate("Invalid Haplogroup")
			dialogMessageA := getLabelCentered(translate("Your haplogroup contains an invalid character."))
			dialogMessageB := getLabelCentered(translate("It must be encoded in UTF-8."))
			dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
			dialog.ShowCustom(title, translate("Close"), dialogContent, window)
			return
		}

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

		err := myLocalProfiles.SetProfileData("Mate", attributeName, newHaplogroup)
		if (err != nil){
			setErrorEncounteredPage(window, err, currentPage)
			return
		}
		currentPage()
	})

	haplogroupEntryWithSubmitButton := getContainerCentered(container.NewGridWithRows(1, haplogroupEntry, submitChangesButton))

	noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
		err := myLocalProfiles.DeleteProfileData("Mate", attributeName)
		if (err != nil){
			setErrorEncounteredPage(window, err, currentPage)
			return
		}
		currentPage()
	}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentHaplogroupRow, widget.NewSeparator(), haplogroupEntryWithSubmitButton, noResponseButton)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered(translate("Genetic Information"))

	description1 := widget.NewLabel("You can display your genetic information on your profile.")
	shareGeneticInfoHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
			setProfileGenomeInfoExplainerPage(window, currentPage)
		})

	description1Row := container.NewHBox(layout.NewSpacer(), description1, shareGeneticInfoHelpButton, layout.NewSpacer())

	description2 := getLabelCentered("You must link your genome person to your profile.")
	description3 := getLabelCentered("You can hide some or all of your genetic information.")

	myGenomePersonIdentifierExists, myGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (myGenomePersonIdentifierExists == true){
		personFound, _, _, _, err := myPeople.GetPersonInfo(myGenomePersonIdentifier)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}
		if (personFound == false){
			// Genome person was deleted
			// We will delete the missing person and refresh the page

			// We show a loading screen so the user can tell if this wrongfully keeps happening
			setLoadingScreen(window, "Build Mate Profile - Physical", "Deleting old genome person identifier...")

			err := myLocalProfiles.DeleteProfileData("Mate", "GenomePersonIdentifier")
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			currentPage()
			return
		}
	}

	myPersonLabel := widget.NewLabel("My Person:")		

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

		if (myGenomePersonIdentifierExists == false){
			noneLabel := getBoldItalicLabel(translate("None"))
			return noneLabel, nil
		}

		personFound, personName, _, _, err := myPeople.GetPersonInfo(myGenomePersonIdentifier)
		if (err != nil){ return nil, err }
		if (personFound == false){
			return nil, errors.New("Genome person not found after being found already.")
		}

		personNameLabel := getBoldLabel(personName)

		return personNameLabel, nil
	}

	currentPersonNameLabel, err := getCurrentPersonNameLabel()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentPersonNameRow := container.NewHBox(layout.NewSpacer(), myPersonLabel, currentPersonNameLabel, layout.NewSpacer())	

	getChooseOrChangeButtonTextAndIcon := func()(string, fyne.Resource){

		if (myGenomePersonIdentifierExists == false){
			result := translate("Choose Person")
			return result, theme.NavigateNextIcon()
		}

		result := translate("Change Person")

		return result, theme.DocumentCreateIcon()
	}

	chooseOrChangeButtonText, chooseOrChangeButtonIcon := getChooseOrChangeButtonTextAndIcon()

	chooseOrChangePersonButton := getWidgetCentered(widget.NewButtonWithIcon(chooseOrChangeButtonText, chooseOrChangeButtonIcon, func(){
			setBuildMateProfilePage_EditGenomePerson(window, currentPage, currentPage)
		}))

	if (myGenomePersonIdentifierExists == false){

		page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1Row, description2, description3, widget.NewSeparator(), currentPersonNameRow, chooseOrChangePersonButton)

		setPageContent(page, window)
		return
	}

	currentlySharingLabel := getItalicLabelCentered("Currently Sharing:")

	//Outputs:
	//	-int: Total number of monogenic diseases
	//	-int: Number of monogenic diseases being shared
	//	-error
	getNumberOfMonogenicDiseasesBeingSharedInfo := func()(int, int, error){

		monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
		if (err != nil) { return 0, 0, err }	

		totalMonogenicDiseases := len(monogenicDiseaseNamesList)
		totalMonogenicDiseasesBeingShared := 0

		for _, diseaseName := range monogenicDiseaseNamesList{

			shareDiseaseInfoAttributeName := "ShareMonogenicDiseaseInfo_" + diseaseName

			currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", shareDiseaseInfoAttributeName)
			if (err != nil){ return 0, 0, err }

			if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
				totalMonogenicDiseasesBeingShared += 1
			}
		}

		return totalMonogenicDiseases, totalMonogenicDiseasesBeingShared, nil
	}

	//Outputs:
	//	-int: Total number of polygenic diseases
	//	-int: Number of polygenic diseases being shared
	//	-error
	getNumberOfPolygenicDiseasesBeingSharedInfo := func()(int, int, error){

		polygenicDiseaseNamesList, err := polygenicDiseases.GetPolygenicDiseaseNamesList()
		if (err != nil) { return 0, 0, err }

		totalPolygenicDiseases := len(polygenicDiseaseNamesList)
		totalPolygenicDiseasesBeingShared := 0

		for _, diseaseName := range polygenicDiseaseNamesList{

			sharePolygenicDiseaseInfoAttributeName := "SharePolygenicDiseaseInfo_" + diseaseName

			currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", sharePolygenicDiseaseInfoAttributeName)
			if (err != nil){ return 0, 0, err }

			if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
				totalPolygenicDiseasesBeingShared += 1
			}
		}

		return totalPolygenicDiseases, totalPolygenicDiseasesBeingShared, nil
	}

	//Outputs:
	//	-int: Total number of traits
	//	-int: Number of traits being shared
	//	-error
	getNumberOfTraitsBeingSharedInfo := func()(int, int, error){
		
		traitNamesList, err := traits.GetTraitNamesList()
		if (err != nil) { return 0, 0, err }	

		totalTraits := len(traitNamesList)
		totalTraitsBeingShared := 0

		for _, traitName := range traitNamesList{

			shareTraitInfoAttributeName := "ShareTraitInfo_" + traitName

			currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", shareTraitInfoAttributeName)
			if (err != nil){ return 0, 0, err }

			if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
				totalTraitsBeingShared += 1
			}
		}

		return totalTraits, totalTraitsBeingShared, nil
	}

	totalMonogenicDiseases, numberOfMonogenicDiseasesBeingShared, err := getNumberOfMonogenicDiseasesBeingSharedInfo()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	totalPolygenicDiseases, numberOfPolygenicDiseasesBeingShared, err := getNumberOfPolygenicDiseasesBeingSharedInfo()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	totalTraits, numberOfTraitsBeingShared, err := getNumberOfTraitsBeingSharedInfo()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	totalMonogenicDiseasesString := helpers.ConvertIntToString(totalMonogenicDiseases)
	numberOfMonogenicDiseasesBeingSharedString := helpers.ConvertIntToString(numberOfMonogenicDiseasesBeingShared)
	numberOfMonogenicDiseasesBeingSharedLabel := getBoldLabelCentered("Monogenic Diseases: " + numberOfMonogenicDiseasesBeingSharedString + "/" + totalMonogenicDiseasesString)

	totalPolygenicDiseasesString := helpers.ConvertIntToString(totalPolygenicDiseases)
	numberOfPolygenicDiseasesBeingSharedString := helpers.ConvertIntToString(numberOfPolygenicDiseasesBeingShared)
	numberOfPolygenicDiseasesBeingSharedLabel := getBoldLabelCentered("Polygenic Diseases: " + numberOfPolygenicDiseasesBeingSharedString + "/" + totalPolygenicDiseasesString)

	totalTraitsString := helpers.ConvertIntToString(totalTraits)
	numberOfTraitsBeingSharedString := helpers.ConvertIntToString(numberOfTraitsBeingShared)
	numberOfTraitsBeingSharedLabel := getBoldLabelCentered("Traits: " + numberOfTraitsBeingSharedString + "/" + totalTraitsString)

	changeVisibilityButton := getWidgetCentered(widget.NewButtonWithIcon("Change Visibility", theme.DocumentCreateIcon(), func(){
			setBuildMateProfilePage_ChangeGeneticInformationVisibility(window, "MonogenicDiseases", currentPage)
		}))

	currentGenomeLabel := widget.NewLabel("Current Genome:")

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

		myGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(myGenomePersonIdentifier)
		if (err != nil) { return "", err }

		if (len(myGenomesMapList) == 0){
			genomeText := translate("None")
			return genomeText, nil
		}
		if (len(myGenomesMapList) == 1){
			myGenomeMap := myGenomesMapList[0]

			myGenomeCompanyName, exists := myGenomeMap["CompanyName"]
			if (exists == false){
				return "", errors.New("MyGenomesMapList is malformed: Genome map missing CompanyName")
			}

			return myGenomeCompanyName, nil
		}

		currentCombinedGenomeToUse, err := myChosenAnalysis.GetMyCombinedGenomeToUse()
		if (err != nil){ return "", err }
	
		result := translate(currentCombinedGenomeToUse)
		return result, nil
	}

	currentGenomeText, err := getCurrentGenomeText()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentGenomeTextLabel := getBoldLabel(currentGenomeText)

	currentGenomeRow := container.NewHBox(layout.NewSpacer(), currentGenomeLabel, currentGenomeTextLabel, layout.NewSpacer())

	chooseGenomeButton := getWidgetCentered(widget.NewButtonWithIcon("Choose Genome", theme.DocumentCreateIcon(), func(){
			setBuildMateProfilePage_ChooseGeneticInformationGenome(window, currentPage)
		}))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1Row, description2, description3, widget.NewSeparator(), currentPersonNameRow, chooseOrChangePersonButton, widget.NewSeparator(), currentlySharingLabel, numberOfMonogenicDiseasesBeingSharedLabel, numberOfPolygenicDiseasesBeingSharedLabel, numberOfTraitsBeingSharedLabel, changeVisibilityButton, widget.NewSeparator(), currentGenomeRow, chooseGenomeButton)

	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Choose Genome Person")	

	description1 := getLabelCentered("Choose your genome person.")	
	description2 := getLabelCentered("You must first import your genome(s) on the Genetics page.")
	description3 := getLabelCentered("As you import or remove genomes, the changes will be reflected in your profile.")
	description4 := getLabelCentered("To avoid sharing information, you can hide some or all of your genetic information.")
	description5 := getLabelCentered("Linking your genome person will enable you to view offspring analyses when viewing matches.")

	myGenomePersonIdentifierExists, currentGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (myGenomePersonIdentifierExists == true){
		personFound, _, _, _, err := myPeople.GetPersonInfo(currentGenomePersonIdentifier)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}
		if (personFound == false){
			// Genome person was deleted
			// We will delete the missing person and refresh the page

			// We show a loading screen so the user can tell if this wrongfully keeps happening
			setLoadingScreen(window, "Build Mate Profile - Physical", "Deleting old genome person identifier...")

			err := myLocalProfiles.DeleteProfileData("Mate", "GenomePersonIdentifier")
			if (err != nil){
				setErrorEncounteredPage(window, err, previousPage)
				return
			}
			currentPage()
			return
		}
	}

	getCurrentPersonNameLabel := func()(fyne.Widget, error){
		
		if (myGenomePersonIdentifierExists == false){
			result := translate("None")

			noResponseLabel := getBoldItalicLabel(result)
			return noResponseLabel, nil
		}
		
		personFound, personName, _, _, err := myPeople.GetPersonInfo(currentGenomePersonIdentifier)
		if (err != nil){ return nil, err }
		if (personFound == false){
			return nil, errors.New("Genome person not found after being found already.")
		}

		personNameLabel := getBoldLabel(personName)

		return personNameLabel, nil
	}

	currentPersonNameLabel, err := getCurrentPersonNameLabel()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentPersonLabel := widget.NewLabel("Current Person:")

	currentPersonNameRow := container.NewHBox(layout.NewSpacer(), currentPersonLabel, currentPersonNameLabel, layout.NewSpacer())

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

		allMyGenomePeopleMapList, err := myPeople.GetMyGenomePeopleMapList()
		if (err != nil){ return nil, err }

		if (len(allMyGenomePeopleMapList) == 0){

			noPeopleExistLabel := getBoldLabel("No People Exist.")

			createAPersonLabel := getLabelCentered("Create a person and import their genomes on the Genetics page.")		

			selectPersonSection := container.NewVBox(noPeopleExistLabel, createAPersonLabel)	
			
			return selectPersonSection, nil
		}

		// Map Structure: Person Name -> Person Identifier
		allGenomePersonNamesMap := make(map[string]string)

		for _, personMap := range allMyGenomePeopleMapList{

			personName, exists := personMap["PersonName"]
			if (exists == false){
				return nil, errors.New("MyGenomePeople map list is malformed: Item missing PersonName")
			}

			personIdentifier, exists := personMap["PersonIdentifier"]
			if (exists == false){
				return nil, errors.New("MyGenomePeople map list is malformed: Item missing PersonIdentifier")			
			}

			_, exists = allGenomePersonNamesMap[personName]
			if (exists == true){
				return nil, errors.New("MyGenomePeople map list is malformed: Duplicate person names exist.")
			}

			allGenomePersonNamesMap[personName] = personIdentifier
		}

		allGenomePersonNamesList := helpers.GetListOfMapKeys(allGenomePersonNamesMap)

		personSelector := widget.NewSelect(allGenomePersonNamesList, nil)

		if (myGenomePersonIdentifierExists == true){

			personFound, personName, _, _, err := myPeople.GetPersonInfo(currentGenomePersonIdentifier)
			if (err != nil){ return nil, err }
			if (personFound == false){
				return nil, errors.New("Genome person not found after being found already.")
			}

			personSelector.Selected = personName
		} else {
			personSelector.PlaceHolder = translate("Select Person...")
		}

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

				newPersonName := personSelector.Selected

				if (newPersonName == ""){
					dialogTitle := translate("No Person Chosen")
					dialogMessageA := getLabelCentered(translate("No person was chosen."))
					dialogMessageB := getLabelCentered(translate("Select a person from the selector."))
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
					dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
					return
				}

				newPersonIdentifier, exists := allGenomePersonNamesMap[newPersonName]
				if (exists == false){
					setErrorEncounteredPage(window, errors.New("New genome person identifier not found."), currentPage)
					return
				}

				err := myLocalProfiles.SetProfileData("Mate", "GenomePersonIdentifier", newPersonIdentifier)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				nextPage()
			})

		personSelectorWithSubmitButtonRow := container.NewHBox(layout.NewSpacer(), personSelector, submitButton, layout.NewSpacer())

		removePersonButton := getWidgetCentered(widget.NewButtonWithIcon(translate("Remove Person"), theme.CancelIcon(), func(){ 
				err := myLocalProfiles.DeleteProfileData("Mate", "GenomePersonIdentifier")
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				nextPage()
			}))

		selectGenomePersonSection := container.NewVBox(personSelectorWithSubmitButtonRow, removePersonButton)

		return selectGenomePersonSection, nil
	}

	selectGenomePersonSection, err := getSelectGenomePersonSection()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), currentPersonNameRow, widget.NewSeparator(), selectGenomePersonSection)

	setPageContent(page, window)
}

func setBuildMateProfilePage_ChangeGeneticInformationVisibility(window fyne.Window, informationCategory string, previousPage func()){

	if (informationCategory != "MonogenicDiseases" && informationCategory != "PolygenicDiseases" && informationCategory != "Traits"){
		setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_ChangeGeneticInformationVisibility called with invalid informationCategory: " + informationCategory), previousPage)
		return
	}

	currentPage := func(){setBuildMateProfilePage_ChangeGeneticInformationVisibility(window, informationCategory, previousPage)}

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Change Genetic Information Visibility")

	description1 := getLabelCentered("Choose which information from your genome you want to share on your profile.")
	description2 := getLabelCentered("You will still always be able to view offspring analyses for your matches.")

	privacyWarningButton := getWidgetCentered(widget.NewButtonWithIcon("Privacy Warning", theme.WarningIcon(), func(){
			setMateProfileGeneticInformationPrivacyWarningPage(window, currentPage)
		}))

	currentCategoryLabel := getItalicLabelCentered("Current Category:")

	monogenicDiseasesTranslated := translate("Monogenic Diseases")
	polygenicDiseasesTranslated := translate("Polygenic Diseases")
	traitsTranslated := translate("Traits")

	categoriesList := []string{monogenicDiseasesTranslated, polygenicDiseasesTranslated, traitsTranslated}

	handleSelectFunction := func(newChoice string){

			getNewCategory := func()string{

				if (newChoice == monogenicDiseasesTranslated){
					return "MonogenicDiseases"
				}
				if (newChoice == polygenicDiseasesTranslated){
					return "PolygenicDiseases"
				}
				return "Traits"
			}

			newCategory := getNewCategory()

			setBuildMateProfilePage_ChangeGeneticInformationVisibility(window, newCategory, previousPage)
		}

	categorySelector := widget.NewSelect(categoriesList, handleSelectFunction)

	if (informationCategory == "MonogenicDiseases"){
		categorySelector.Selected = monogenicDiseasesTranslated

	} else if (informationCategory == "PolygenicDiseases"){
		categorySelector.Selected = polygenicDiseasesTranslated

	} else {
		categorySelector.Selected = traitsTranslated
	}

	categorySelectorCentered := getWidgetCentered(categorySelector)

	// This returns a list of all MonogenicDiseaseNames, PolygenicDiseaseNames, or TraitNames
	getItemNamesList := func()([]string, error){

		if (informationCategory == "MonogenicDiseases"){

			monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
			if (err != nil) { return nil, err }

			return monogenicDiseaseNamesList, nil
		}
		if (informationCategory == "PolygenicDiseases"){

			polygenicDiseaseNamesList, err := polygenicDiseases.GetPolygenicDiseaseNamesList()
			if (err != nil) { return nil, err }

			return polygenicDiseaseNamesList, nil
		}

		// informationCategory == "Traits"

		traitNamesList, err := traits.GetTraitNamesList()
		if (err != nil) { return nil, err }

		return traitNamesList, nil
	}

	allItemNamesList, err := getItemNamesList()
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	getCategoryTypeShareInfoPrefix := func()string{

		if (informationCategory == "MonogenicDiseases"){
			return "ShareMonogenicDiseaseInfo_"
		}
		if (informationCategory == "PolygenicDiseases"){
			return "SharePolygenicDiseaseInfo_"
		}
		return "ShareTraitInfo_"
	}

	categoryTypeShareInfoPrefix := getCategoryTypeShareInfoPrefix()

	setAllItemShareAttributesToValue := func(yesOrNo string)error{

		if (yesOrNo != "Yes" && yesOrNo != "No"){
			return errors.New("setAllItemShareAttributesToValue called with invalid yesOrNo: " + yesOrNo)
		}

		for _, itemName := range allItemNamesList{

			itemAttributeName := categoryTypeShareInfoPrefix + itemName

			err := myLocalProfiles.SetProfileData("Mate", itemAttributeName, yesOrNo)
			if (err != nil) { return err }
		}

		return nil
	}
	
	shareAllButton := widget.NewButtonWithIcon("Share All", theme.VisibilityIcon(), func(){

			err := setAllItemShareAttributesToValue("Yes")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		})

	hideAllButton := widget.NewButtonWithIcon("Hide All", theme.VisibilityOffIcon(), func(){
			err := setAllItemShareAttributesToValue("No")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		})

	shareAndHideButtons := getContainerCentered(container.NewGridWithRows(1, shareAllButton, hideAllButton))

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

		getItemTypeName := func()string{
			if (informationCategory == "MonogenicDiseases"){
				result := translate("Monogenic Disease")
				return result
			}

			if (informationCategory == "PolygenicDiseases"){
				result := translate("Polygenic Disease")
				return result
			}
			result := translate("Trait")

			return result
		}

		itemTypeName := getItemTypeName()

		itemTypeNameLabel := getItalicLabelCentered(itemTypeName + " " + translate("Name"))

		shareInformationLabel := getItalicLabelCentered(translate("Share Information?"))

		itemNameColumn := container.NewVBox(itemTypeNameLabel, widget.NewSeparator())
		itemChecksColumn := container.NewVBox(shareInformationLabel, widget.NewSeparator())

		for _, itemName := range allItemNamesList{

			itemNameLabel := getBoldLabelCentered(itemName)

			itemAttributeName := categoryTypeShareInfoPrefix + itemName

			itemCheck := widget.NewCheck("", func(newResponse bool){

					newValueString := helpers.ConvertBoolToYesOrNoString(newResponse)

					err := myLocalProfiles.SetProfileData("Mate", itemAttributeName, newValueString)
					if (err != nil) {
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
				})

			currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", itemAttributeName)
			if (err != nil){ return nil, err }

			if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
				itemCheck.Checked = true
			}

			itemCheckCentered := getWidgetCentered(itemCheck)

			itemNameColumn.Add(itemNameLabel)
			itemChecksColumn.Add(itemCheckCentered)

			itemNameColumn.Add(widget.NewSeparator())
			itemChecksColumn.Add(widget.NewSeparator())
		}

		itemsGrid := container.NewHBox(layout.NewSpacer(), itemNameColumn, itemChecksColumn, layout.NewSpacer())

		return itemsGrid, nil
	}

	categoryItemsGrid, err := getCategoryItemsGrid()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, privacyWarningButton, widget.NewSeparator(), currentCategoryLabel, categorySelectorCentered, widget.NewSeparator(), shareAndHideButtons, widget.NewSeparator(), categoryItemsGrid)

	setPageContent(page, window)
}

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Genetic Information Privacy Warning")

	description1 := getLabelCentered("By sharing genome information, users can read an analysis of an offspring created from you and them.")
	description2 := getLabelCentered("When you share Polygenic Disease and Trait information, you are sharing specific locations on your genome.")
	description3 := getLabelCentered("These locations represent a tiny fraction of your entire genome.")
	description4 := getLabelCentered("These locations can still be used to create a unique genetic fingerprint, which can identify you.")
	description5 := getLabelCentered("People will also be able to read your trait and polygenic disease risk information.")
	description6 := getLabelCentered("For example, if you share Breast Cancer, users will know your Breast Cancer risk.")
	description7 := getLabelCentered("When sharing Monogenic Disease information, you do not share specific locations.")
	description8 := getLabelCentered("You instead share the probability of passing a monogenic disease variant to your offspring.")

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

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Choose Genetic Information Genome")

	description1 := getLabelCentered("A single genome from your genetic analysis will be used for genetic calculations with other users.")
	description2 := getLabelCentered("Your profile will also contain information from this genome if you choose to share any information.")
	description3 := getLabelCentered("If you have only imported one genome, that will be the genome whose information is used.")
	description4 := getLabelCentered("If you have multiple genomes, only 1 of the two combined genomes will be used.")
	description5 := getLabelCentered("You can choose below which genome you want to use if you have imported multiple genomes.")

	currentGenomeLabel := widget.NewLabel("Current Genome:")

	myGenomePersonIdentifierExists, myGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (myGenomePersonIdentifierExists == false){
		setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_ChooseGeneticInformationGenome called when genome person is not established."), previousPage)
		return
	}

	currentCombinedGenomeToUse, err := myChosenAnalysis.GetMyCombinedGenomeToUse()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

		myGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(myGenomePersonIdentifier)
		if (err != nil) { return "", err }

		if (len(myGenomesMapList) == 0){
			genomeText := translate("None")
			return genomeText, nil
		}
		if (len(myGenomesMapList) == 1){
			myGenomeMap := myGenomesMapList[0]

			myGenomeCompanyName, exists := myGenomeMap["CompanyName"]
			if (exists == false){
				return "", errors.New("MyGenomesMapList is malformed: Genome map missing CompanyName")
			}

			return myGenomeCompanyName, nil
		}

		result := translate(currentCombinedGenomeToUse)

		return result, nil
	}

	currentGenomeText, err := getCurrentGenomeText()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	currentGenomeTextLabel := getBoldLabel(currentGenomeText)

	currentGenomeRow := container.NewHBox(layout.NewSpacer(), currentGenomeLabel, currentGenomeTextLabel, layout.NewSpacer())

	combinedGenomeToUseLabel := getItalicLabel("Combined Genome To Use:")

	option1Translated := translate("Only Include Shared")
	option2Translated := translate("Only Exclude Conflicts")

	untranslatedOptionsMap := map[string]string{
		option1Translated: "Only Include Shared",
		option2Translated: "Only Exclude Conflicts",
	}

	selectorOptionsList := []string{option1Translated, option2Translated}

	combinedGenomeSelector := widget.NewSelect(selectorOptionsList, func(newSelection string){

			newSelectionUntranslated, exists := untranslatedOptionsMap[newSelection]
			if (exists == false){
				setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing selection: " + newSelection), currentPage)
				return
			}

			err = myChosenAnalysis.SetMyCombinedGenomeToUse(newSelectionUntranslated)
			if (err != nil) {
				setErrorEncounteredPage(window, err, currentPage)
				return
			}

			currentPage()
		})

	combinedGenomeSelector.Selected = translate(currentCombinedGenomeToUse)

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

	combinedGenomeSelectorWithHelpButton := container.NewBorder(nil, nil, nil, combinedGenomeHelpButton, combinedGenomeSelector)

	combinedGenomeSelectorWithLabel := getContainerCentered(container.NewGridWithColumns(1, combinedGenomeToUseLabel, combinedGenomeSelectorWithHelpButton))

	page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), currentGenomeRow, widget.NewSeparator(), combinedGenomeSelectorWithLabel)

	setPageContent(page, window)
}

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

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

	pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("Height"))

	description := getLabelCentered(translate("Enter your height."))

	getCurrentMetricOrImperial := 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
	}

	currentMetricOrImperial, err := getCurrentMetricOrImperial()
	if (err != nil) {
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

	currentUnitsLabel := getItalicLabel(translate("Current Units:"))

	metricOrImperialRow := container.NewHBox(layout.NewSpacer(), currentUnitsLabel, changeMetricOrImperialButton, layout.NewSpacer())

	currentHeightExists, currentHeightCentimeters, err := myLocalProfiles.GetProfileData("Mate", "Height")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

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

		if (currentHeightExists == false){
			labelText := translate("No Response")

			label := getBoldItalicLabel(labelText)
			return label, nil
		}

		myHeightCentimetersFloat64, err := helpers.ConvertStringToFloat64(currentHeightCentimeters)
		if (err != nil){
			return nil, errors.New("MyLocalProfiles malformed: Contains invalid Height")
		}

		if (currentMetricOrImperial == "Metric"){				

			myHeightRounded := helpers.ConvertFloat64ToStringRounded(myHeightCentimetersFloat64, 2)

			centimetersTranslated := translate("centimeters")

			formattedResult := myHeightRounded + " " + centimetersTranslated

			label := getBoldLabel(formattedResult)

			return label, nil
		}

		feetInchesString, err := helpers.ConvertCentimetersToFeetInchesTranslatedString(myHeightCentimetersFloat64)
		if (err != nil) { return nil, err }

		label := getBoldLabel(feetInchesString)

		return label, nil
	}

	currentHeightLabel, err := getCurrentHeightLabel()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	myHeightLabel := widget.NewLabel("My Height:")

	currentHeightRow := container.NewHBox(layout.NewSpacer(), myHeightLabel, currentHeightLabel, layout.NewSpacer())

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

		if (currentMetricOrImperial == "Metric"){
	
			centimetersEntry := widget.NewEntry()

			if (currentHeightExists == false){
				centimetersEntry.SetPlaceHolder(translate("Enter Centimeters"))
			} else {
				centimetersEntry.SetText(currentHeightCentimeters)
			}

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

					newHeightCentimeters := centimetersEntry.Text

					isValid, err := helpers.VerifyStringIsFloatWithinRange(newHeightCentimeters, 30, 400)
					if (err != nil) {
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					if (isValid == false){

						centimetersEntry.SetText("")
						centimetersEntry.SetPlaceHolder(translate("Enter Centimeters"))

						title := translate("Invalid Height")
						dialogMessageA := getLabelCentered(translate("Invalid height entered."))
						dialogMessageB := getLabelCentered(translate("Height must be between 30 and 400 centimeters."))
						dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
						dialog.ShowCustom(title, translate("Close"), dialogContent, window)
						return
					}

					err = myLocalProfiles.SetProfileData("Mate", "Height", newHeightCentimeters)
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
				})

			centimetersLabel := widget.NewLabel(translate("Centimeters"))

			centimetersEntryWithLabel := container.NewGridWithRows(1, centimetersEntry, centimetersLabel)

			enterHeightRow := container.NewHBox(layout.NewSpacer(), centimetersEntryWithLabel, centimetersSubmitButton, layout.NewSpacer())

			return enterHeightRow, nil
		}

		// MetricOrImperial == "Imperial"

		/// Feet + Inches
		feetLabel := widget.NewLabel(translate("Feet"))
		inchesLabel := widget.NewLabel(translate("Inches"))

		feetEntry := widget.NewEntry()
		inchesEntry := widget.NewEntry()

		if (currentHeightExists == false){
			feetEntry.SetPlaceHolder(translate("Enter Feet"))
			inchesEntry.SetPlaceHolder(translate("Enter Inches"))
		} else {

			isValid, err := helpers.VerifyStringIsFloatWithinRange(currentHeightCentimeters, 30, 400)
			if (err != nil) { return nil, err }
			if (isValid == false){ return nil, errors.New("MyLocalProfiles is malformed: Contains invalid height.") }

			currentHeightCentimetersFloat64, err := helpers.ConvertStringToFloat64(currentHeightCentimeters)
			if (err != nil) { return nil, err }
			
			currentHeightFeet, currentHeightInches, err := helpers.ConvertCentimetersToFeetInches(currentHeightCentimetersFloat64)
			if (err != nil) { return nil, err }

			currentHeightFeetString := helpers.ConvertIntToString(currentHeightFeet)
			currentHeightInchesString := helpers.ConvertFloat64ToStringRounded(currentHeightInches, 1)

			feetEntry.SetText(currentHeightFeetString)
			inchesEntry.SetText(currentHeightInchesString)
		}

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

				newHeightFeet := feetEntry.Text
				newHeightInches := inchesEntry.Text

				newHeightFeetInt, err := helpers.ConvertStringToInt(newHeightFeet)
				if (err != nil){
					title := translate("Invalid Height")
					dialogMessageA := getLabelCentered(translate("Invalid feet entered."))
					dialogMessageB := getLabelCentered(translate("Feet must be a number."))
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				newHeightInchesFloat64, err := helpers.ConvertStringToFloat64(newHeightInches)
				if (err != nil){
					title := translate("Invalid Height")
					dialogMessageA := getLabelCentered(translate("Invalid inches entered."))
					dialogMessageB := getLabelCentered(translate("Inches must be a number."))
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				newHeightCentimeters, err := helpers.ConvertFeetInchesToCentimeters(newHeightFeetInt, newHeightInchesFloat64)
				if (err != nil){
					title := translate("Invalid Height")
					dialogMessageA := getLabelCentered(translate("Invalid height entered."))
					dialogMessageB := getLabelCentered(translate("Height must be between 30 and 400 centimeters."))
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				if (newHeightCentimeters < 30 || newHeightCentimeters > 400){
					title := translate("Invalid Height")
					dialogMessageA := getLabelCentered(translate("Invalid height entered."))
					dialogMessageB := getLabelCentered(translate("Height must be between 30 and 400 centimeters."))
					dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				newHeightCentimetersString := helpers.ConvertFloat64ToString(newHeightCentimeters)

				err = myLocalProfiles.SetProfileData("Mate", "Height", newHeightCentimetersString)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
			})

		feetEntryWithLabel := container.NewGridWithRows(1, feetEntry, feetLabel)
		inchesEntryWithLabel := container.NewGridWithRows(1, inchesEntry, inchesLabel)

		feetInchesEntryRow := getContainerCentered(container.NewHBox(layout.NewSpacer(), feetEntryWithLabel, inchesEntryWithLabel, feetInchesSubmitButton, layout.NewSpacer()))

		return feetInchesEntryRow, nil
	}

	enterHeightRow, err := getEnterHeightRow()
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
			err := myLocalProfiles.DeleteProfileData("Mate", "Height")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}))

	page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description, widget.NewSeparator(), metricOrImperialRow, widget.NewSeparator(), currentHeightRow, widget.NewSeparator(), enterHeightRow, noResponseButton)

	setPageContent(page, window)
}


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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	subtitle := getPageSubtitleCentered("Body")

	description1 := getLabelCentered("Describe your body.")
	description2 := getLabelCentered("Choose a value between 1 and 4 to describe each characteristic.")
	description3 := getLabelCentered("1 = least fat/muscular human, 4 = most fat/muscular human.")

	fatLabel := getBoldLabelCentered("Fat")

	fatSelector	:= widget.NewSelect([]string{"1", "2", "3", "4"}, func(newChoice string){
			err := myLocalProfiles.SetProfileData("Mate", "BodyFat", newChoice)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
		})
	fatSelector.PlaceHolder = "Select one..."

	fatNoResponseButton := widget.NewButtonWithIcon("No Response", theme.CancelIcon(), func(){

			err := myLocalProfiles.DeleteProfileData("Mate", "BodyFat")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		})

	fatColumn := container.NewVBox(fatLabel, fatSelector, fatNoResponseButton)

	currentFatValueExists, currentFatValue, err := myLocalProfiles.GetProfileData("Mate", "BodyFat")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (currentFatValueExists == true){
		fatSelector.Selected = currentFatValue
	}

	muscleLabel := getBoldLabelCentered("Muscle")
	muscleSelector := widget.NewSelect([]string{"1", "2", "3", "4"}, func(newChoice string){
			err := myLocalProfiles.SetProfileData("Mate", "BodyMuscle", newChoice)
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
		})
	muscleSelector.PlaceHolder = "Select one..."

	muscleNoResponseButton := widget.NewButtonWithIcon("No Response", theme.CancelIcon(), func(){

			err := myLocalProfiles.DeleteProfileData("Mate", "BodyMuscle")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		})

	muscleColumn := container.NewVBox(muscleLabel, muscleSelector, muscleNoResponseButton)

	currentMuscleValueExists, currentMuscleValue, err := myLocalProfiles.GetProfileData("Mate", "BodyMuscle")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (currentMuscleValueExists == true){
		muscleSelector.Selected = currentMuscleValue
	}

	pageColumns := container.NewHBox(layout.NewSpacer(), widget.NewSeparator(), fatColumn, widget.NewSeparator(), muscleColumn, widget.NewSeparator(), layout.NewSpacer())

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

	setPageContent(page, window)
}


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

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

	pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("Eye Color"))

	description1 := getLabelCentered(translate("Select your eye color."))
	description2 := getLabelCentered(translate("Select more than 1 color if your eyes contain multiple colors."))

	eyeColorExists, currentEyeColorAttribute, err := myLocalProfiles.GetProfileData("Mate", "EyeColor")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	getCurrentEyeColorList := func()[]string{

		if (eyeColorExists == false){
			emptyList := make([]string, 0)
			return emptyList
		}

		currentEyeColorList := strings.Split(currentEyeColorAttribute, "+")

		return currentEyeColorList
	}

	currentEyeColorList := getCurrentEyeColorList()

	if (len(currentEyeColorList) > 4){
		setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid eye color attribute"), previousPage)
		return
	}

	getCurrentEyeColorLabel := func()fyne.Widget{

		if (eyeColorExists == false){
			result := translate("No Response")

			eyeColorLabel := getBoldItalicLabel(result)
			return eyeColorLabel
		}
	
		currentEyeColorFormatted := strings.Join(currentEyeColorList, ", ")

		eyeColorLabel := getBoldLabel(currentEyeColorFormatted)
		return eyeColorLabel
	}

	currentEyeColorLabel := getCurrentEyeColorLabel()

	myEyeColorLabel := widget.NewLabel("My Eye Color:")

	currentEyeColorRow := container.NewHBox(layout.NewSpacer(), myEyeColorLabel, currentEyeColorLabel, layout.NewSpacer())
	
	getEyeColorColumn := func(colorName string, colorsList []string)(*fyne.Container, error){
		
		colorColumn := container.NewGridWithColumns(1)

		for _, colorCode := range colorsList{

			colorSquare, err := getColorSquareAsFyneImage(colorCode)
			if (err != nil){ return nil, err }

			colorSquare.FillMode = canvas.ImageFillStretch

			colorColumn.Add(colorSquare)					
		}

		chooseColorCheck := widget.NewCheck(colorName, func(newChoice bool){

				getNewAttributeList := func()[]string{

					if (newChoice == false){
						newList, _ := helpers.DeleteAllMatchingItemsFromList(currentEyeColorList, colorName)
						return newList
					}

					newList := helpers.AddItemToStringListAndAvoidDuplicate(currentEyeColorList, colorName)
			
					return newList
				}
	
				newAttributeList := getNewAttributeList()

				if (len(newAttributeList) == 0){
					err := myLocalProfiles.DeleteProfileData("Mate", "EyeColor")
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
					return
				}
	
				newEyeColorAttribute := strings.Join(newAttributeList, "+")

				err := myLocalProfiles.SetProfileData("Mate", "EyeColor", newEyeColorAttribute)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
			})

		colorSelected := slices.Contains(currentEyeColorList, colorName)
		if (colorSelected == true){
			chooseColorCheck.Checked = true
		}

		colorColumn.Add(chooseColorCheck)

		return colorColumn, nil
	}

	//TODO: Add Gray

	blueColorsList := []string{"4d71a6", "9fa8a8", "345269"}
	greenColorsList := []string{"333b26", "6d712b", "505216"}
	amberColorsList := []string{"6e5c18", "694c19", "684818"}
	brownColorsList := []string{"522613", "47240f", "2a110c"}	

	blueEyeColorColumn, err := getEyeColorColumn("Blue", blueColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	
	greenEyeColorColumn, err := getEyeColorColumn("Green", greenColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	amberEyeColorColumn, err := getEyeColorColumn("Amber", amberColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	brownEyeColorColumn, err := getEyeColorColumn("Brown", brownColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	selectEyeColorGrid := getContainerCentered(container.NewGridWithColumns(4, blueEyeColorColumn, greenEyeColorColumn, amberEyeColorColumn, brownEyeColorColumn))

	noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
			err := myLocalProfiles.DeleteProfileData("Mate", "EyeColor")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}))

	page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentEyeColorRow, widget.NewSeparator(), selectEyeColorGrid, noResponseButton)
	
	setPageContent(page, window)
}

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

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

	pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("Hair Color"))

	description1 := getLabelCentered(translate("Select your natural hair color."))
	description2 := getLabelCentered(translate("Select 2 colors if your hair color is an average of two colors."))
	//TODO: What if hair is gray/white
	// Users should probably select the color their hair was when they were a young adult. We should add gray or white as an option?

	hairColorExists, currentHairColorAttribute, err := myLocalProfiles.GetProfileData("Mate", "HairColor")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	getCurrentHairColorList := func()[]string{

		if (hairColorExists == false){
			emptyList := make([]string, 0)
			return emptyList
		}

		currentHairColorList := strings.Split(currentHairColorAttribute, "+")

		return currentHairColorList
	}

	currentHairColorList := getCurrentHairColorList()

	if (len(currentHairColorList) > 4){
		setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid hair color attribute: " + currentHairColorAttribute), previousPage)
		return
	}

	getCurrentHairColorLabel := func()fyne.Widget{

		if (hairColorExists == false){
			result := translate("No Response")

			hairColorLabel := getBoldItalicLabel(result)
			return hairColorLabel
		}

		currentHairColorFormatted := strings.Join(currentHairColorList, "-")

		hairColorLabel := getBoldLabel(currentHairColorFormatted)
		return hairColorLabel
	}

	currentHairColorLabel := getCurrentHairColorLabel()

	myHairColorLabel := widget.NewLabel("My Hair Color:")

	currentHairColorRow := container.NewHBox(layout.NewSpacer(), myHairColorLabel, currentHairColorLabel, layout.NewSpacer())

	getHairColorColumn := func(colorName string, colorsList []string)(*fyne.Container, error){
		
		colorColumn := container.NewGridWithColumns(1)

		for _, colorCode := range colorsList{

			colorSquare, err := getColorSquareAsFyneImage(colorCode)
			if (err != nil){ return nil, err }

			colorSquare.FillMode = canvas.ImageFillStretch

			colorColumn.Add(colorSquare)					
		}

		chooseColorCheck := widget.NewCheck(colorName, func(newChoice bool){

				getNewAttributeList := func()[]string{

					if (newChoice == false){
						newList, _ := helpers.DeleteAllMatchingItemsFromList(currentHairColorList, colorName)
						return newList
					}

					newList := helpers.AddItemToStringListAndAvoidDuplicate(currentHairColorList, colorName)
			
					return newList
				}
	
				newAttributeList := getNewAttributeList()

				if (len(newAttributeList) > 2){

					currentPage()

					title := translate("Too Many Colors")
					dialogMessageA := getLabelCentered(translate("You can only select two colors."))
					dialogContent := container.NewVBox(dialogMessageA)
					dialog.ShowCustom(title, translate("Close"), dialogContent, window)
					return
				}

				if (len(newAttributeList) == 0){
					err := myLocalProfiles.DeleteProfileData("Mate", "HairColor")
					if (err != nil){
						setErrorEncounteredPage(window, err, currentPage)
						return
					}
					currentPage()
					return
				}
	
				newHairColorAttribute := strings.Join(newAttributeList, "+")

				err := myLocalProfiles.SetProfileData("Mate", "HairColor", newHairColorAttribute)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
			})

		colorSelected := slices.Contains(currentHairColorList, colorName)
		if (colorSelected == true){
			chooseColorCheck.Checked = true
		}

		colorColumn.Add(chooseColorCheck)

		return colorColumn, nil
	}

	blackColorsList := []string{"242424", "1d1719", "070300"}
	brownColorsList := []string{"5d3629", "362219", "472c24"}
	blondeColorsList := []string{"efd8a6", "edd096", "a57d4d"}
	orangeColorsList := []string{"f5743a", "8c5125", "883713"}	

	blackHairColorColumn, err := getHairColorColumn("Black", blackColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	brownHairColorColumn, err := getHairColorColumn("Brown", brownColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	blondeHairColorColumn, err := getHairColorColumn("Blonde", blondeColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	orangeHairColorColumn, err := getHairColorColumn("Orange", orangeColorsList)
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	selectHairColorGrid := getContainerCentered(container.NewGridWithColumns(4, blackHairColorColumn, brownHairColorColumn, blondeHairColorColumn, orangeHairColorColumn))

	noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
			err := myLocalProfiles.DeleteProfileData("Mate", "HairColor")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}))

	page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentHairColorRow, widget.NewSeparator(), selectHairColorGrid, noResponseButton)
	
	setPageContent(page, window)
}

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

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

	title := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("Hair Texture"))

	description := getLabelCentered(translate("Enter your natural hair texture."))

	option1Translated := translate("1 - Straight Hair")
	option2Translated := translate("2 - Slightly Wavy Hair")
	option3Translated := translate("3 - Wavy Hair")
	option4Translated := translate("4 - Big Curls")
	option5Translated := translate("5 - Small Curls")
	option6Translated := translate("6 - Very Tight Curls")

	hairTextureOptionsMap := map[string]string{
		option1Translated: "1",
		option2Translated: "2",
		option3Translated: "3",
		option4Translated: "4",
		option5Translated: "5",
		option6Translated: "6",
	}

	hairTextureSelectorOptionsList := []string{option1Translated, option2Translated, option3Translated, option4Translated, option5Translated, option6Translated}

	hairTextureSelector := widget.NewRadioGroup(hairTextureSelectorOptionsList, func(response string){

			if (response == ""){
				myLocalProfiles.DeleteProfileData("Mate", "HairTexture")
				return
			}

			attributeValue, exists := hairTextureOptionsMap[response]
			if (exists == false){
				setErrorEncounteredPage(window, errors.New("hairTextureOptionsMap missing translated option: " + response), currentPage)
				return
			}
			myLocalProfiles.SetProfileData("Mate", "HairTexture", attributeValue)
		})

	exists, currentHairTexture, err := myLocalProfiles.GetProfileData("Mate", "HairTexture")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	if (exists == true){
		isValid, err := helpers.VerifyStringIsIntWithinRange(currentHairTexture, 1, 6)
		if (err != nil){
			setErrorEncounteredPage(window, err, previousPage)
			return
		}
		if (isValid == false){
			setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid hair texture: " + currentHairTexture), previousPage)
			return
		}
		if (currentHairTexture == "1"){

			hairTextureSelector.Selected = option1Translated
		} else if (currentHairTexture == "2"){
			hairTextureSelector.Selected = option2Translated
		} else if (currentHairTexture == "3"){
			hairTextureSelector.Selected = option3Translated
		} else if (currentHairTexture == "4"){
			hairTextureSelector.Selected = option4Translated
		} else if (currentHairTexture == "5"){
			hairTextureSelector.Selected = option5Translated
		} else if (currentHairTexture == "6"){
			hairTextureSelector.Selected = option6Translated
		}
	}
	hairTextureSelectorCentered := getWidgetCentered(hairTextureSelector)

	noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
			myLocalProfiles.DeleteProfileData("Mate", "HairTexture")
			currentPage()
		}))

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

	setPageContent(page, window)
}

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

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

	pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("Skin Color"))

	description1 := getLabelCentered(translate("Select your skin color."))
	description2 := getLabelCentered(translate("This may be difficult because skin color changes under different conditions."))
	description3 := getLabelCentered(translate("Try your best to choose the best option."))
	description4 := getLabelCentered(translate("Users are reminded of this when choosing their skin color desires."))

	mySkinColorExists, currentSkinColorAttribute, err := myLocalProfiles.GetProfileData("Mate", "SkinColor")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	if (mySkinColorExists == true){

		currentSkinColorInt, err := helpers.ConvertStringToInt(currentSkinColorAttribute)
		if (err != nil){
			setErrorEncounteredPage(window, errors.New("MyLocalProfiles SkinColor is invalid: " + currentSkinColorAttribute), previousPage)
			return
		}

		if (currentSkinColorInt < 1 || currentSkinColorInt > 6){
			setErrorEncounteredPage(window, errors.New("MyLocalProfiles SkinColor is invalid: " + currentSkinColorAttribute), previousPage)
			return
		}
	}

	getCurrentSkinColorLabel := func()fyne.Widget{

		if (mySkinColorExists == false){
			result := translate("No Response")

			skinColorLabel := getBoldItalicLabel(result)
			return skinColorLabel
		}

		skinColorLabel := getBoldLabel(currentSkinColorAttribute)
		return skinColorLabel
	}

	currentSkinColorLabel := getCurrentSkinColorLabel()

	mySkinColorLabel := widget.NewLabel("My Skin Color:")

	currentSkinColorRow := container.NewHBox(layout.NewSpacer(), mySkinColorLabel, currentSkinColorLabel, layout.NewSpacer())

	getSkinColorColumn := func(colorIdentifier string, colorCode string)(*fyne.Container, error){

		colorSquare, err := getColorSquareAsFyneImage(colorCode)
		if (err != nil){ return nil, err }

		colorSquare.FillMode = canvas.ImageFillStretch

		chooseColorCheck := widget.NewCheck(colorIdentifier, func(newChoice bool){

				err := myLocalProfiles.DeleteProfileData("Mate", "SkinColor")
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}

				err = myLocalProfiles.SetProfileData("Mate", "SkinColor", colorIdentifier)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
			})

		if (colorIdentifier == currentSkinColorAttribute){
			chooseColorCheck.Checked = true
		}

		colorColumn := container.NewGridWithColumns(1, colorSquare, chooseColorCheck)

		return colorColumn, nil
	}

	skinColorColumn_1, err := getSkinColorColumn("1", "f4e3da")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	skinColorColumn_2, err := getSkinColorColumn("2", "f5d6b9")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	skinColorColumn_3, err := getSkinColorColumn("3", "dabe91")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	skinColorColumn_4, err := getSkinColorColumn("4", "ba9175")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	skinColorColumn_5, err := getSkinColorColumn("5", "916244")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	skinColorColumn_6, err := getSkinColorColumn("6", "744d2d")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	selectSkinColorGrid := getContainerCentered(container.NewGridWithColumns(6, skinColorColumn_1, skinColorColumn_2, skinColorColumn_3, skinColorColumn_4, skinColorColumn_5, skinColorColumn_6))

	noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
			err := myLocalProfiles.DeleteProfileData("Mate", "SkinColor")
			if (err != nil){
				setErrorEncounteredPage(window, err, currentPage)
				return
			}
			currentPage()
		}))

	page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), currentSkinColorRow, widget.NewSeparator(), selectSkinColorGrid, noResponseButton)

	setPageContent(page, window)
}


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

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

	pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))

	backButton := getBackButtonCentered(previousPage)

	pageSubtitle := getPageSubtitleCentered(translate("Infections"))
	
	description :=  getLabelCentered(translate("Select the infections that you have."))

	infectionNameColumn := container.NewVBox(widget.NewSeparator())
	radioButtonsColumn := container.NewVBox(widget.NewSeparator())
	noResponseButtonsColumn := container.NewVBox(widget.NewSeparator())

	addInfectionRow := func(infectionName string, infectionAttributeName string)error{

		infectionNameLabel := getBoldLabelCentered(infectionName)

		yesTranslated := translate("Yes")
		noTranslated := translate("No")

		untranslatedOptionsMap := map[string]string{
			yesTranslated: "Yes",
			noTranslated: "No",
		}

		optionsList := []string{yesTranslated, noTranslated}

		yesNoSelector := widget.NewRadioGroup(optionsList, func(response string){

			if (response == ""){

				_ = myLocalProfiles.DeleteProfileData("Mate", infectionAttributeName)

				return
			}

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

			_ = myLocalProfiles.SetProfileData("Mate", infectionAttributeName, responseUntranslated)
		})

		yesNoSelector.Horizontal = true

		myCurrentStatusExists, myCurrentInfectionStatus, err := myLocalProfiles.GetProfileData("Mate", infectionAttributeName)
		if (err != nil){ return err }

		if (myCurrentStatusExists == true){

			yesNoSelector.Selected = translate(myCurrentInfectionStatus)
		}

		noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){ 
				err := myLocalProfiles.DeleteProfileData("Mate", infectionAttributeName)
				if (err != nil){
					setErrorEncounteredPage(window, err, currentPage)
					return
				}
				currentPage()
			}))

		infectionNameColumn.Add(infectionNameLabel)
		radioButtonsColumn.Add(yesNoSelector)
		noResponseButtonsColumn.Add(noResponseButton)

		infectionNameColumn.Add(widget.NewSeparator())
		radioButtonsColumn.Add(widget.NewSeparator())
		noResponseButtonsColumn.Add(widget.NewSeparator())

		return nil
	}

	err := addInfectionRow("HIV", "HasHIV")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}
	err = addInfectionRow("Genital Herpes", "HasGenitalHerpes")
	if (err != nil){
		setErrorEncounteredPage(window, err, previousPage)
		return
	}

	infectionsGrid := container.NewHBox(layout.NewSpacer(), infectionNameColumn, radioButtonsColumn, noResponseButtonsColumn, layout.NewSpacer())	

	page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description, widget.NewSeparator(), infectionsGrid)
	
	setPageContent(page, window)
}


