
// profileFormat provides a specification of user profile format and syntax
// It is used by readProfiles to verify profiles

package profileFormat

//TODO: Add Host and Moderator attributes

//TODO: Change all attribute identifiers so they are in ascending order
// The order was tarnished after I added and removed some attributes

import "seekia/internal/currencies"
import "seekia/internal/imageFiles"
import "seekia/internal/worldLanguages"
import "seekia/internal/worldLocations"
import "seekia/internal/allowedText"
import "seekia/internal/cryptography/csidh"
import "seekia/internal/cryptography/mlkem"
import "seekia/internal/cryptography/nacl"
import "seekia/internal/encoding"
import "seekia/internal/genetics/companyAnalysis"
import "seekia/internal/genetics/geneticReferences/traits"
import "seekia/internal/genetics/geneticReferences/polygenicDiseases"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/imagery"
import "seekia/internal/mateQuestionnaire"

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

func VerifyProfileType(profileType string)bool{

	if (profileType == "Mate" || profileType == "Host" || profileType == "Moderator"){
		return true
	}

	return false
}

func GetSupportedVersionsList()[]int{

	supportedVersionsList := []int{1}

	return supportedVersionsList
}

type AttributeObject struct{

	// A list of the profile versions that this attribute is allowed for
	ProfileVersions []int

	// This is an integer that is used as the key for the entry in the raw profile
	// We do this to save space. 16 (1 byte encoded MessagePack) is smaller than "SecondaryLocationCountry" (24 bytes).
	// It will always be the same for all profile versions
	// It must be a number between 0 and 4294967295
	AttributeIdentifier int

	// The name will always be the same across all profile versions
	// We can change what is stored in the attribute for a new profile version, so we never need to worry about "using up" a name
	AttributeName string

	// Is true if this attribute is required for all profileTypes returned by GetProfileTypes
	// Example: "CreationTime" and "ProfileType" are required attributes for all profiles
	// Input: Profile Version
	// Output: Attribute is required, error
	GetIsRequired func(int)(bool, error)

	// List of attributes that must come accompanied with this attribute
	// An example is PrimaryLocationCountry, which must be accompanied by PrimaryLocationLatitude and PrimaryLocationLongitude
	// If isRequired == true, this will be an empty list. All of the IsRequired==true attributes are part of the same mandatory group
	// Input: Profile Version
	// Output: Attribute mandatory attributes, error
	GetMandatoryAttributes func(int)([]string, error)

	// List of profileTypes that the attribute is allowed to exist for
	// Example: "Height" is only permitted for Mate profiles
	// Input: Profile Version
	// Output: Attribute profile types, error
	GetProfileTypes func(int)([]string, error)

	// Returns "Always"/"Sometimes"/"Never"
	// Example: "Age" is always canonical (a number), "GenderIdentity" is sometimes canonical, "Description" is never canonical.
	// Input: Profile Version
	// Output: Attribute Is Canonical, error
	GetIsCanonical func(int)(string, error)

	// This function is used to check if profile values are valid
	// Input: Profile Version, ProfileType, Attribute Name
	// Output: IsValid, IsCanonical, error
	CheckValueFunction func(int, string, string)(bool, bool, error) 
}

// This must be run once upon application startup
func InitializeProfileFormatVariables()error{

	err := initializeProfileAttributeObjectsList()
	if (err != nil) { return err }

	profileAttributeObjectsList, err := GetProfileAttributeObjectsList()
	if (err != nil) { return err }

	// Map Structure: Attribute name -> Attribute Object
	profileAttributeObjectsByIdentifierMap = make(map[int]AttributeObject)
	
	// Map Structure: Attribute name -> Attribute Object
	profileAttributeObjectsByNameMap = make(map[string]AttributeObject)

	// Map Structure: Attribute Identifier -> Attribute Name
	profileAttributeNamesByIdentifierMap = make(map[int]string)

	// Map Structure: Attribute Name -> Attribute Identifier
	profileAttributeIdentifiersByNameMap = make(map[string]int)

	for _, attributeObject := range profileAttributeObjectsList{

		attributeIdentifier := attributeObject.AttributeIdentifier
		attributeName := attributeObject.AttributeName

		profileAttributeObjectsByIdentifierMap[attributeIdentifier] = attributeObject
		profileAttributeObjectsByNameMap[attributeName] = attributeObject

		profileAttributeNamesByIdentifierMap[attributeIdentifier] = attributeName
		profileAttributeIdentifiersByNameMap[attributeName] = attributeIdentifier
	}

	return nil
}

func GetAttributeNameFromAttributeIdentifier(attributeIdentifier int)(string, error){

	if (profileAttributeNamesByIdentifierMap == nil){
		return "", errors.New("GetAttributeNameFromAttributeIdentifier called when map is not initialized.")
	}

	attributeName, exists := profileAttributeNamesByIdentifierMap[attributeIdentifier]
	if (exists == false){
		attributeIdentifierString := helpers.ConvertIntToString(attributeIdentifier)
		return "", errors.New("GetAttributeNameFromAttributeIdentifier called with unknown attributeIdentifier: " + attributeIdentifierString)
	}

	return attributeName, nil
}

func GetAttributeIdentifierFromAttributeName(attributeName string)(int, error){

	if (profileAttributeIdentifiersByNameMap == nil){
		return 0, errors.New("GetAttributeIdentifierFromAttributeName called when map is not initialized.")
	}

	attributeIdentifier, exists := profileAttributeIdentifiersByNameMap[attributeName]
	if (exists == false){
		return 0, errors.New("GetAttributeIdentifierFromAttributeName called with unknown attributeName: " + attributeName)
	}

	return attributeIdentifier, nil
}

func GetAttributeObjectFromAttributeIdentifier(attributeIdentifier int)(AttributeObject, error){

	profileAttributeObjectsMap, err := GetProfileAttributeObjectsByIdentifierMap()
	if (err != nil) { return AttributeObject{}, err }

	attributeObject, exists := profileAttributeObjectsMap[attributeIdentifier]
	if (exists == false){
		attributeIdentifierString := helpers.ConvertIntToString(attributeIdentifier)
		return AttributeObject{}, errors.New("GetAttributeObjectFromAttributeIdentifier called with unknown attribute identifier: " + attributeIdentifierString)
	}

	return attributeObject, nil
}



// We read data into these variables to make retrieval faster

// Map Structure: Attribute Identifier -> Attribute Name
var profileAttributeNamesByIdentifierMap map[int]string

// Map Structure: Attribute Name -> Attribute Identifier
var profileAttributeIdentifiersByNameMap map[string]int

// Map Structure: Attribute Identifier -> Attribute Object
var profileAttributeObjectsByIdentifierMap map[int]AttributeObject

// Map Structure: Attribute Name -> Attribute Object
var profileAttributeObjectsByNameMap map[string]AttributeObject

var profileAttributeObjectsList []AttributeObject



// Outputs:
//	-map[int]AttributeObject: Attribute Identifier -> Attribute Object
func GetProfileAttributeObjectsByIdentifierMap()(map[int]AttributeObject, error){

	if (profileAttributeObjectsByIdentifierMap == nil){
		return nil, errors.New("GetProfileAttributeObjectsByIdentifierMap called when map is not initialized.")
	}

	return profileAttributeObjectsByIdentifierMap, nil
}

// Outputs:
//	-map[string]AttributeObject: Attribute name -> Attribute Object
func GetProfileAttributeObjectsByNameMap()(map[string]AttributeObject, error){

	if (profileAttributeObjectsByNameMap == nil){
		return nil, errors.New("GetProfileAttributeObjectsByNameMap called when map is not initialized.")
	}

	return profileAttributeObjectsByNameMap, nil
}

func GetProfileAttributeObjectsList()([]AttributeObject, error){

	if (profileAttributeObjectsList == nil){
		return nil, errors.New("GetProfileAttributeObjectsList called when list is not initialized.")
	}

	return profileAttributeObjectsList, nil
}

func initializeProfileAttributeObjectsList()error{

	// Below are some standard getAttribute functions

	getIsRequired_Yes := func(profileVersion int)(bool, error){
		if (profileVersion != 1){
			return false, errors.New("Trying to retrieve isRequired status for unknown profile version.")
		}
		return true, nil
	}

	getIsRequired_No := func(profileVersion int)(bool, error){
		if (profileVersion != 1){
			return false, errors.New("Trying to retrieve isRequired status for unknown profile version.")
		}
		return false, nil
	}

	getMandatoryAttributes_None := func(profileVersion int)([]string, error){
		if (profileVersion != 1){
			return nil, errors.New("Trying to retrieve mandatory attributes for unknown profile version.")
		}
		emptyList := make([]string, 0)
		return emptyList, nil
	}

	getProfileTypes_All := func(profileVersion int)([]string, error){
		if (profileVersion != 1){
			return nil, errors.New("Trying to retrieve profileTypes for unknown profile version.")
		}
		profileTypesList := []string{"Mate", "Host", "Moderator"}
		return profileTypesList, nil
	}

	getProfileTypes_Mate := func(profileVersion int)([]string, error){
		if (profileVersion != 1){
			return nil, errors.New("Trying to retrieve profileTypes for unknown profile version.")
		}
		profileTypesList := []string{"Mate"}
		return profileTypesList, nil
	}

	getProfileTypes_MateOrModerator := func(profileVersion int)([]string, error){
		if (profileVersion != 1){
			return nil, errors.New("Trying to retrieve profileTypes for unknown profile version.")
		}
		profileTypesList := []string{"Mate", "Moderator"}
		return profileTypesList, nil
	}

	getIsCanonical_Always := func(profileVersion int)(string, error){
		if (profileVersion != 1){
			return "", errors.New("Trying to retrieve IsCanonical for unknown profile version.")
		}
		return "Always", nil
	}

	getIsCanonical_Sometimes := func(profileVersion int)(string, error){
		if (profileVersion != 1){
			return "", errors.New("Trying to retrieve IsCanonical for unknown profile version.")
		}
		return "Sometimes", nil
	}

	getIsCanonical_Never := func(profileVersion int)(string, error){
		if (profileVersion != 1){
			return "", errors.New("Trying to retrieve IsCanonical for unknown profile version.")
		}
		return "Never", nil
	}

	checkValueFunction_Mate1To10Rating := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Mate 1to10 rating: " + profileType)
		}
		
		isValid, err := helpers.VerifyStringIsIntWithinRange(input, 1, 10)
		if (err != nil) { return false, false, err }
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	checkValueFunction_MateYesOrNo := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify MateYesOrNo: " + profileType)
		}

		if (input != "Yes" && input != "No"){
			return false, false, nil
		}

		return true, true, nil
	}


	attributeObjectsList := make([]AttributeObject, 0, 322)

	checkValueFunction_ProfileVersion := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to check ProfileVersion: " + profileType)
		}

		if (input != "1"){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_ProfileVersion := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 1,
		AttributeName: "ProfileVersion",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_ProfileVersion,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_ProfileVersion)

	checkValueFunction_NetworkType := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to check NetworkType: " + profileType)
		}

		if (input != "1" && input != "2"){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_NetworkType := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 51,
		AttributeName: "NetworkType",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_NetworkType,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_NetworkType)

	checkValueFunction_IdentityKey := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to check IdentityKey: " + profileType)
		}

		isValid := identity.VerifyIdentityKeyHex(input)
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_IdentityKey := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 2,
		AttributeName: "IdentityKey",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_IdentityKey,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_IdentityKey)

	checkValueFunction_ProfileType := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to check ProfileType: " + profileType)
		}

		if (input != profileType){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_ProfileType := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 3,
		AttributeName: "ProfileType",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_ProfileType,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_ProfileType)

	checkValueFunction_CreationTime := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to check CreationTime: " + profileType)
		}

		_, err := helpers.ConvertCreationTimeStringToInt64(input)
		if (err != nil){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_CreationTime := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 4,
		AttributeName: "CreationTime",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_CreationTime,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_CreationTime)

	checkValueFunction_Disabled := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to check attribute value: " + profileType)
		}

		if (input != "Yes"){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_Disabled := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 5,
		AttributeName: "Disabled",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Disabled,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Disabled)

	checkValueFunction_ProfileLanguage := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to check ProfileLanguage: " + profileType)
		}

		languageIdentifier, err := helpers.ConvertStringToInt(input)
		if (err != nil){
			return false, false, nil
		}

		isValid := worldLanguages.VerifyLanguageIdentifier(languageIdentifier)
		if (isValid == false){
			return false, false, nil	
		}

		return true, true, nil
	}

	attributeObject_ProfileLanguage := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 107,
		AttributeName: "ProfileLanguage",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_ProfileLanguage,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_ProfileLanguage)

	checkValueFunction_Height := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Trying to check if Height is valid for non-mate profileType: " + profileType)
		}

		isValid, err := helpers.VerifyStringIsFloatWithinRange(input, 30, 400)
		if (err != nil) { return false, false, err }
		if (isValid == true){
			return true, true, nil
		}

		return false, false, nil
	}

	attributeObject_Height := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 6,
		AttributeName: "Height",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Height,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Height)

	checkValueFunction_Sex := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Trying to check if Sex is valid for non-mate profileType: " + profileType)
		}

		if (input == "Male" || input == "Female" || input == "Intersex Male" || input == "Intersex Female" || input == "Intersex"){
			return true, true, nil
		}

		return false, false, nil
	}

	attributeObject_Sex := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 7,
		AttributeName: "Sex",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Sex,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Sex)

	checkValueFunction_Age := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Trying to check if age is valid for non-mate profileType: " + profileType)
		}

		isValid, err := helpers.VerifyStringIsIntWithinRange(input, 18, 150)
		if (err != nil) { return false, false, err }
		if (isValid == true){
			return true, true, nil
		}

		return false, false, nil
	}

	attributeObject_Age := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 8,
		AttributeName: "Age",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Age,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Age)

	checkValueFunction_Description := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify Description: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		isAllowed := allowedText.VerifyStringIsAllowed(input)
		if (isAllowed == false){
			return false, false, nil
		}

		descriptionLength := len(input)

		if (profileType == "Mate" && descriptionLength <= 3000){
			return true, false, nil
		}
		if (profileType == "Host" && descriptionLength <= 300){
			return true, false, nil
		}
		if (profileType == "Moderator" && descriptionLength <= 500){
			return true, false, nil
		}

		return false, false, nil
	}

	attributeObject_Description := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 9,
		AttributeName: "Description",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Description,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Description)

	checkValueFunction_Username := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify Username: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		isAllowed := allowedText.VerifyStringIsAllowed(input)
		if (isAllowed == false){
			return false, false, nil
		}

		containsTabsOrNewlines := helpers.CheckIfStringContainsTabsOrNewlines(input)
		if (containsTabsOrNewlines == true){
			return false, false, nil
		}

		usernameByteLength := len(input)

		if (usernameByteLength <= 25){
			return true, false, nil
		}

		return false, false, nil
	}

	attributeObject_Username := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 10,
		AttributeName: "Username",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Username,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Username)

	checkValueFunction_LocationLatitude := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify LocationLatitude: " + profileType)
		}

		latitudeFloat64, err := helpers.ConvertStringToFloat64(input)
		if (err != nil){
			return false, false, nil
		}

		isValid := helpers.VerifyLatitude(latitudeFloat64)
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	getMandatoryAttributes_PrimaryLocationLatitude := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"PrimaryLocationLongitude"}
		return mandatoryAttributesList, nil
	}

	attributeObject_PrimaryLocationLatitude := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 11,
		AttributeName: "PrimaryLocationLatitude",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_PrimaryLocationLatitude,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_LocationLatitude,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_PrimaryLocationLatitude)

	getMandatoryAttributes_PrimaryLocationLongitude := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"PrimaryLocationLatitude"}
		return mandatoryAttributesList, nil
	}

	checkValueFunction_LocationLongitude := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify LocationLongitude: " + profileType)
		}

		longitudeFloat64, err := helpers.ConvertStringToFloat64(input)
		if (err != nil){
			return false, false, nil
		}

		isValid := helpers.VerifyLongitude(longitudeFloat64)
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_PrimaryLocationLongitude := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 12,
		AttributeName: "PrimaryLocationLongitude",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_PrimaryLocationLongitude,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_LocationLongitude,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_PrimaryLocationLongitude)

	getMandatoryAttributes_PrimaryLocationCountry := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"PrimaryLocationLatitude", "PrimaryLocationLongitude"}
		return mandatoryAttributesList, nil
	}

	checkValueFunction_LocationCountry := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify LocationCountry: " + profileType)
		}

		countryIdentifier, err := helpers.ConvertStringToInt(input)
		if (err != nil){
			return false, false, nil
		}

		isValid := worldLocations.VerifyCountryIdentifier(countryIdentifier)	
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_PrimaryLocationCountry := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 13,
		AttributeName: "PrimaryLocationCountry",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_PrimaryLocationCountry,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_LocationCountry,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_PrimaryLocationCountry)

	getMandatoryAttributes_SecondaryLocationLatitude := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"PrimaryLocationLatitude", "PrimaryLocationLongitude", "SecondaryLocationLongitude"}
		return mandatoryAttributesList, nil
	}

	attributeObject_SecondaryLocationLatitude := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 14,
		AttributeName: "SecondaryLocationLatitude",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_SecondaryLocationLatitude,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_LocationLatitude,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_SecondaryLocationLatitude)

	getMandatoryAttributes_SecondaryLocationLongitude := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"PrimaryLocationLatitude", "PrimaryLocationLongitude", "SecondaryLocationLatitude"}
		return mandatoryAttributesList, nil
	}

	attributeObject_SecondaryLocationLongitude := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 15,
		AttributeName: "SecondaryLocationLongitude",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_SecondaryLocationLongitude,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_LocationLongitude,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_SecondaryLocationLongitude)

	getMandatoryAttributes_SecondaryLocationCountry := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"PrimaryLocationLatitude", "PrimaryLocationLongitude", "SecondaryLocationLatitude", "SecondaryLocationLongitude"}
		return mandatoryAttributesList, nil
	}

	attributeObject_SecondaryLocationCountry := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 16,
		AttributeName: "SecondaryLocationCountry",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_SecondaryLocationCountry,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_LocationCountry,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_SecondaryLocationCountry)

	checkValueFunction_Tags := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Tags: " + profileType)
		}

		tagsList := strings.Split(input, "+&")

		if (len(tagsList) > 30){
			return false, false, nil
		}

		// We use this map to detect duplicates
		allTagsMap := make(map[string]struct{})

		totalTagByteLength := 0

		for _, tagString := range tagsList{

			if (tagString == ""){
				return false, false, nil
			}

			_, exists := allTagsMap[tagString]
			if (exists == true){
				// Duplicate exists
				return false, false, nil
			}
			allTagsMap[tagString] = struct{}{}

			isAllowed := allowedText.VerifyStringIsAllowed(tagString)
			if (isAllowed == false){
				return false, false, nil
			}

			containsTabOrNewline := helpers.CheckIfStringContainsTabsOrNewlines(tagString)
			if (containsTabOrNewline == true){
				return false, false, nil
			}

			tagByteLength := len(tagString)

			if (tagByteLength > 40){
				return false, false, nil
			}
			totalTagByteLength += tagByteLength			
		}

		if (totalTagByteLength > 500){
			return false, false, nil
		}

		return true, false, nil
	}

	attributeObject_Tags := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 17,
		AttributeName: "Tags",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Tags,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Tags)

	checkValueFunction_Photos := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Photos: " + profileType)
		}

		base64PhotosList := strings.Split(input, "+")

		if (len(base64PhotosList) > 5){
			return false, false, nil
		}

		for _, base64Photo := range base64PhotosList{

			photoBytes, err := encoding.DecodeBase64StringToBytes(base64Photo)
			if (err != nil){
				return false, false, nil
			}

			if (base64Photo == ""){
				return false, false, nil
			}

			isValid, err := imagery.VerifyStandardImageBytes(photoBytes)
			if (err != nil){
				return false, false, err
			}

			if (isValid == false){
				return false, false, nil
			}
		}

		return true, false, nil
	}

	attributeObject_Photos := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 18,
		AttributeName: "Photos",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Photos,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Photos)

	checkValueFunction_Questionnaire := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Questionnaire: " + profileType)
		}

		_, err := mateQuestionnaire.ReadQuestionnaireString(input)
		if (err != nil){
			return false, false, nil
		}
		return true, false, nil
	}

	attributeObject_Questionnaire := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 19,
		AttributeName: "Questionnaire",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Questionnaire,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Questionnaire)

	checkValueFunction_Avatar := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify Avatar: " + profileType)
		}

		emojiIdentifier, err := helpers.ConvertStringToInt(input)
		if (err != nil){
			return false, false, nil
		}

		isValid := imageFiles.VerifyEmojiIdentifier(emojiIdentifier)
		if (isValid == false){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_Avatar := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 20,
		AttributeName: "Avatar",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_All,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Avatar,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Avatar)

	checkValueFunction_Sexuality := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Sexuality: " + profileType)
		}

		if (input != "Male" && input != "Female" && input != "Male And Female"){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_Sexuality := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 21,
		AttributeName: "Sexuality",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Sexuality,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Sexuality)

	checkValueFunction_23andMe_AncestryComposition := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify 23andMe_AncestryComposition: " + profileType)
		}

		isValid, _, _, _, err := companyAnalysis.ReadAncestryCompositionAttribute_23andMe(true, input)
		if (err != nil) { return false, false, err }
		if (isValid == false){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_23andMe_AncestryComposition := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 22,
		AttributeName: "23andMe_AncestryComposition",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_23andMe_AncestryComposition,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_23andMe_AncestryComposition)

	checkValueFunction_23andMe_NeanderthalVariants := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify 23andMe_NeanderthalVariants: " + profileType)
		}

		neanderthalVariantsInt, err := helpers.ConvertStringToInt(input)
		if (err != nil){
			return false, false, nil
		}

		isValid := companyAnalysis.VerifyNeanderthalVariants_23andMe(neanderthalVariantsInt)
		if (isValid == false){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_23andMe_NeanderthalVariants := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 23,
		AttributeName: "23andMe_NeanderthalVariants",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_23andMe_NeanderthalVariants,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_23andMe_NeanderthalVariants)

	checkValueFunction_23andMe_MaternalHaplogroup := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify 23andMe_MaternalHaplogroup: " + profileType)
		}

		isValid, isCanonical := companyAnalysis.VerifyMaternalHaplogroup_23AndMe(input)
		
		return isValid, isCanonical, nil
	}

	attributeObject_23andMe_MaternalHaplogroup := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 24,
		AttributeName: "23andMe_MaternalHaplogroup",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Sometimes,
		CheckValueFunction: checkValueFunction_23andMe_MaternalHaplogroup,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_23andMe_MaternalHaplogroup)

	checkValueFunction_23andMe_PaternalHaplogroup := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify 23andMe_PaternalHaplogroup: " + profileType)
		}

		isValid, isCanonical := companyAnalysis.VerifyPaternalHaplogroup_23AndMe(input)
		
		return isValid, isCanonical, nil
	}

	attributeObject_23andMe_PaternalHaplogroup := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 25,
		AttributeName: "23andMe_PaternalHaplogroup",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Sometimes,
		CheckValueFunction: checkValueFunction_23andMe_PaternalHaplogroup,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_23andMe_PaternalHaplogroup)

	checkValueFunction_BodyFat := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify BodyFat: " + profileType)
		}

		isValid, err := helpers.VerifyStringIsIntWithinRange(input, 1, 4)
		if (err != nil) { return false, false, err }		
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_BodyFat := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 26,
		AttributeName: "BodyFat",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_BodyFat,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_BodyFat)

	checkValueFunction_BodyMuscle := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify BodyMuscle: " + profileType)
		}

		isValid, err := helpers.VerifyStringIsIntWithinRange(input, 1, 4)
		if (err != nil) { return false, false, err }
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_BodyMuscle := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 27,
		AttributeName: "BodyMuscle",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_BodyMuscle,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_BodyMuscle)

	checkValueFunction_EyeColor := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify EyeColor: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		eyeColorsList := strings.Split(input, "+")

		if (len(eyeColorsList) > 4){
			return false, false, nil
		}

		// We use this map to check for duplicates
		addedColorsMap := make(map[string]struct{})

		for _, colorName := range eyeColorsList{

			if (colorName != "Blue" && colorName != "Green" && colorName != "Amber" && colorName != "Brown"){
				return false, false, nil
			}

			_, exists := addedColorsMap[colorName]
			if (exists == true){
				return false, false, nil
			}
			addedColorsMap[colorName] = struct{}{}
		}

		return true, true, nil
	}

	attributeObject_EyeColor := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 28,
		AttributeName: "EyeColor",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_EyeColor,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_EyeColor)

	checkValueFunction_HairColor := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify HairColor: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		hairColorsList := strings.Split(input, "+")

		if (len(hairColorsList) > 2){
			return false, false, nil
		}

		// We use this map to check for duplicates
		addedColorsMap := make(map[string]struct{})

		for _, colorName := range hairColorsList{

			if (colorName != "Black" && colorName != "Brown" && colorName != "Blonde" && colorName != "Orange"){
				return false, false, nil
			}

			_, exists := addedColorsMap[colorName]
			if (exists == true){
				return false, false, nil
			}
			addedColorsMap[colorName] = struct{}{}
		}

		return true, true, nil
	}

	attributeObject_HairColor := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 29,
		AttributeName: "HairColor",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_HairColor,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_HairColor)

	checkValueFunction_HairTexture := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify HairTexture: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		// 1 == Straight, 2 == Slightly Wavy, 3 == Wavy, 4 == Big Curls, 5 == Small Curls, 6 == Very Tight Curls
		// These descriptions are taken from 23andMe.

		if (input == "1" || input == "2" || input == "3" || input == "4" || input == "5" || input == "6"){
			return true, true, nil
		}

		return false, false, nil
	}

	attributeObject_HairTexture := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 63,
		AttributeName: "HairTexture",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_HairTexture,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_HairTexture)

	checkValueFunction_SkinColor := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify SkinColor: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		if (input == "1" || input == "2" || input == "3" || input == "4" || input == "5" || input == "6"){
			return true, true, nil
		}

		return false, false, nil
	}

	attributeObject_SkinColor := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 108,
		AttributeName: "SkinColor",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_SkinColor,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_SkinColor)

	attributeObject_HasHIV := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 30,
		AttributeName: "HasHIV",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_MateYesOrNo,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_HasHIV)

	attributeObject_HasGenitalHerpes := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 31,
		AttributeName: "HasGenitalHerpes",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_MateYesOrNo,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_HasGenitalHerpes)

	checkValueFunction_Hobbies := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Hobbies: " + profileType)
		}
	
		if (input == ""){
			return false, false, nil
		}

		isAllowed := allowedText.VerifyStringIsAllowed(input)
		if (isAllowed == false){
			return false, false, nil
		}

		if (len(input) <= 1000){
			return true, false, nil
		}

		return false, false, nil
	}

	attributeObject_Hobbies := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 32,
		AttributeName: "Hobbies",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Hobbies,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Hobbies)

	getMandatoryAttributes_Wealth := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"WealthCurrency", "WealthIsLowerBound"}
		return mandatoryAttributesList, nil
	}

	checkValueFunction_Wealth := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Wealth: " + profileType)
		}
	
		isValid, err := helpers.VerifyStringIsIntWithinRange(input, 0, 9223372036854775807)
		if (err != nil) { return false, false, err }

		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_Wealth := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 33,
		AttributeName: "Wealth",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_Wealth,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Wealth,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Wealth)

	getMandatoryAttributes_WealthCurrency := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"Wealth", "WealthIsLowerBound"}
		return mandatoryAttributesList, nil
	}

	checkValueFunction_WealthCurrency := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify WealthCurrency: " + profileType)
		}
	
		isValid, err := currencies.VerifyCurrencyCode(input)
		if (err != nil) { return false, false, err }
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_WealthCurrency := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 34,
		AttributeName: "WealthCurrency",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_WealthCurrency,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_WealthCurrency,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_WealthCurrency)

	getMandatoryAttributes_WealthIsLowerBound := func(profileVersion int)([]string, error){

		if (profileVersion != 1){
			return nil, errors.New("Invalid profile version when trying to get mandatory attributes.")
		}
		mandatoryAttributesList := []string{"Wealth", "WealthCurrency"}
		return mandatoryAttributesList, nil
	}

	attributeObject_WealthIsLowerBound := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 35,
		AttributeName: "WealthIsLowerBound",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_WealthIsLowerBound,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_MateYesOrNo,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_WealthIsLowerBound)

	checkValueFunction_Job := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Job: " + profileType)
		}
	
		if (input == ""){
			return false, false, nil
		}

		isAllowed := allowedText.VerifyStringIsAllowed(input)
		if (isAllowed == false){
			return false, false, nil
		}

		if (len(input) <= 100){
			return true, false, nil
		}

		return false, false, nil
	}

	attributeObject_Job := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 36,
		AttributeName: "Job",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Job,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Job)


	addFoodRatingAttributeObject := func(attributeIdentifier int, attributeName string){

		attributeObject_FoodRating := AttributeObject{
			ProfileVersions: []int{1},
			AttributeIdentifier: attributeIdentifier,
			AttributeName: attributeName,
			GetIsRequired: getIsRequired_No,
			GetMandatoryAttributes: getMandatoryAttributes_None,
			GetProfileTypes: getProfileTypes_Mate,
			GetIsCanonical: getIsCanonical_Always,
			CheckValueFunction: checkValueFunction_Mate1To10Rating,
		}

		attributeObjectsList = append(attributeObjectsList, attributeObject_FoodRating)
	}

	addFoodRatingAttributeObject(37, "FruitRating")
	addFoodRatingAttributeObject(38, "VegetablesRating")
	addFoodRatingAttributeObject(39, "NutsRating")
	addFoodRatingAttributeObject(40, "GrainsRating")
	addFoodRatingAttributeObject(41, "DairyRating")
	addFoodRatingAttributeObject(42, "SeafoodRating")
	addFoodRatingAttributeObject(43, "BeefRating")
	addFoodRatingAttributeObject(44, "PorkRating")
	addFoodRatingAttributeObject(45, "PoultryRating")
	addFoodRatingAttributeObject(46, "EggsRating")
	addFoodRatingAttributeObject(47, "BeansRating")

	//TODO: Add Potatoes?


	attributeObject_Fame := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 48,
		AttributeName: "Fame",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Mate1To10Rating,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Fame)


	attributeObject_AlcoholFrequency := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 49,
		AttributeName: "AlcoholFrequency",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Mate1To10Rating,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_AlcoholFrequency)

	attributeObject_TobaccoFrequency := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 50,
		AttributeName: "TobaccoFrequency",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Mate1To10Rating,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_TobaccoFrequency)

	attributeObject_CannabisFrequency := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 52,
		AttributeName: "CannabisFrequency",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Mate1To10Rating,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_CannabisFrequency)

	checkValueFunction_Language := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Language: " + profileType)
		}

		languageItemsList := strings.Split(input, "+&")

		if (len(languageItemsList) > 100){
			return false, false, nil
		}

		allLanguageObjectsMap, err := worldLanguages.GetWorldLanguageObjectsMap()
		if (err != nil) { return false, false, err }

		// We use this map to detect duplicates
		languageNamesMap := make(map[string]struct{})

		customLanguageExists := false

		for _, languageItem := range languageItemsList{

			languageName, languageRating, delimiterFound := strings.Cut(languageItem, "$")
			if (delimiterFound == false){
				return false, false, nil
			}

			_, exists := languageNamesMap[languageName]
			if (exists == true){
				return false, false, nil
			}
			languageNamesMap[languageName] = struct{}{}
			
			ratingIsValid, err := helpers.VerifyStringIsIntWithinRange(languageRating, 1, 5)
			if (err != nil) { return false, false, err }
			if (ratingIsValid == false){
				return false, false, nil
			}

			_, exists = allLanguageObjectsMap[languageName]
			if (exists == false){

				// Language must be custom

				customLanguageExists = true

				if (languageName == ""){
					return false, false, nil
				}

				isAllowed := allowedText.VerifyStringIsAllowed(languageName)
				if (isAllowed == false){
					return false, false, nil
				}

				containsTabsOrNewlines := helpers.CheckIfStringContainsTabsOrNewlines(languageName)
				if (containsTabsOrNewlines == true){
					return false, false, nil
				}

				if (len(languageName) > 30){
					return false, false, nil
				}
			}
		}

		if (customLanguageExists == false){
			return true, true, nil
		}

		return true, false, nil
	}

	attributeObject_Language := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 53,
		AttributeName: "Language",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Sometimes,
		CheckValueFunction: checkValueFunction_Language,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Language)

	checkValueFunction_Beliefs := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify Beliefs: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		isAllowed := allowedText.VerifyStringIsAllowed(input)
		if (isAllowed == false){
			return false, false, nil
		}

		if (len(input) <= 1000){
			return true, false, nil
		}

		return false, false, nil
	}

	attributeObject_Beliefs := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 54,
		AttributeName: "Beliefs",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Never,
		CheckValueFunction: checkValueFunction_Beliefs,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_Beliefs)

	checkValueFunction_GenderIdentity := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify GenderIdentity: " + profileType)
		}

		if (input == ""){
			return false, false, nil
		}

		isAllowed := allowedText.VerifyStringIsAllowed(input)
		if (isAllowed == false){
			return false, false, nil
		}

		containsTabsOrNewlines := helpers.CheckIfStringContainsTabsOrNewlines(input)
		if (containsTabsOrNewlines == true){
			return false, false, nil
		}

		if (input == "Man" || input == "Woman"){
			return true, true, nil
		}

		if (len(input) <= 50){
			return true, false, nil
		}

		return false, false, nil
	}

	attributeObject_GenderIdentity := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 55,
		AttributeName: "GenderIdentity",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Sometimes,
		CheckValueFunction: checkValueFunction_GenderIdentity,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_GenderIdentity)

	attributeObject_PetsRating := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 56,
		AttributeName: "PetsRating",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Mate1To10Rating,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_PetsRating)

	attributeObject_DogsRating := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 57,
		AttributeName: "DogsRating",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Mate1To10Rating,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_DogsRating)

	attributeObject_CatsRating := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 58,
		AttributeName: "CatsRating",
		GetIsRequired: getIsRequired_No,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_Mate,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_Mate1To10Rating,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_CatsRating)

	checkValueFunction_NaclKey := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify NaclKey: " + profileType)
		}

		isValid := nacl.VerifyNaclPublicKeyString(input)
		if (isValid == false){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_NaclKey := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 103,
		AttributeName: "NaclKey",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_MateOrModerator,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_NaclKey,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_NaclKey)

	checkValueFunction_MlkemKey := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify MlkemKey: " + profileType)
		}

		isValid := mlkem.VerifyMlkemPublicKeyString(input)
		if (isValid == false){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_MlkemKey := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 104,
		AttributeName: "MlkemKey",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_MateOrModerator,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_MlkemKey,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_MlkemKey)

	checkValueFunction_CsidhKey := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify CsidhKey: " + profileType)
		}

		isValid := csidh.VerifyCsidhPublicKeyString(input)
		if (isValid == false){
			return false, false, nil
		}
		return true, true, nil
	}

	attributeObject_CsidhKey := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 109,
		AttributeName: "CsidhKey",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_MateOrModerator,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_CsidhKey,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_CsidhKey)

	checkValueFunction_DeviceIdentifier := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify DeviceIdentifier: " + profileType)
		}

		isValid := helpers.VerifyHexString(11, input)
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_DeviceIdentifier := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 105,
		AttributeName: "DeviceIdentifier",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_MateOrModerator,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_DeviceIdentifier,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_DeviceIdentifier)

	checkValueFunction_ChatKeysLatestUpdateTime := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate" && profileType != "Moderator"){
			return false, false, errors.New("Invalid profile type when trying to verify ChatKeysLatestUpdateTime: " + profileType)
		}

		_, err := helpers.ConvertCreationTimeStringToInt64(input)
		if (err != nil){
			return false, false, nil
		}

		return true, true, nil
	}

	attributeObject_ChatKeysLatestUpdateTime := AttributeObject{
		ProfileVersions: []int{1},
		AttributeIdentifier: 106,
		AttributeName: "ChatKeysLatestUpdateTime",
		GetIsRequired: getIsRequired_Yes,
		GetMandatoryAttributes: getMandatoryAttributes_None,
		GetProfileTypes: getProfileTypes_MateOrModerator,
		GetIsCanonical: getIsCanonical_Always,
		CheckValueFunction: checkValueFunction_ChatKeysLatestUpdateTime,
	}
	attributeObjectsList = append(attributeObjectsList, attributeObject_ChatKeysLatestUpdateTime)

	checkValueFunction_MonogenicDiseaseVariantProbability := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify MonogenicDiseaseVariantProbability: " + profileType)
		}

		isValid, err := helpers.VerifyStringIsIntWithinRange(input, 0, 100)
		if (err != nil) { return false, false, err }
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	addMonogenicDiseaseVariantProbabilityAttribute := func(attributeIdentifier int, attributeName string){

		attributePrefix := strings.TrimSuffix(attributeName, "ProbabilityOfPassingAVariant")

		getMandatoryAttributes_MonogenicDisease := func(profileVersion int)([]string, error){
			if (profileVersion != 1){
				return nil, errors.New("Trying to retrieve mandatory attributes for unknown profile version.")
			}

			mandatoryAttributeName := attributePrefix + "NumberOfVariantsTested"
			mandatoryAttributesList := []string{mandatoryAttributeName}

			return mandatoryAttributesList, nil
		}

		attributeObject_MonogenicDiseaseVariantProbability := AttributeObject{
			ProfileVersions: []int{1},
			AttributeIdentifier: attributeIdentifier,
			AttributeName: attributeName,
			GetIsRequired: getIsRequired_No,
			GetMandatoryAttributes: getMandatoryAttributes_MonogenicDisease,
			GetProfileTypes: getProfileTypes_Mate,
			GetIsCanonical: getIsCanonical_Always,
			CheckValueFunction: checkValueFunction_MonogenicDiseaseVariantProbability,
		}
		attributeObjectsList = append(attributeObjectsList, attributeObject_MonogenicDiseaseVariantProbability)	
	}

	checkValueFunction_MonogenicDiseaseNumberOfVariantsTested := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify MonogenicDiseaseNumberOfVariantsTested: " + profileType)
		}
		
		isValid, err := helpers.VerifyStringIsIntWithinRange(input, 1, 31)
		if (err != nil) { return false, false, err }
		if (isValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	addMonogenicDiseaseNumberOfVariantsTestedAttribute := func(attributeIdentifier int, attributeName string){

		attributePrefix := strings.TrimSuffix(attributeName, "NumberOfVariantsTested")

		getMandatoryAttributes_MonogenicDisease := func(profileVersion int)([]string, error){
			if (profileVersion != 1){
				return nil, errors.New("Trying to retrieve mandatory attributes for unknown profile version.")
			}

			mandatoryAttributeName := attributePrefix + "ProbabilityOfPassingAVariant"
			mandatoryAttributesList := []string{mandatoryAttributeName}
			return mandatoryAttributesList, nil
		}

		attributeObject_MonogenicDiseaseVariantsTested := AttributeObject{
			ProfileVersions: []int{1},
			AttributeIdentifier: attributeIdentifier,
			AttributeName: attributeName,
			GetIsRequired: getIsRequired_No,
			GetMandatoryAttributes: getMandatoryAttributes_MonogenicDisease,
			GetProfileTypes: getProfileTypes_Mate,
			GetIsCanonical: getIsCanonical_Always,
			CheckValueFunction: checkValueFunction_MonogenicDiseaseNumberOfVariantsTested,
		}

		attributeObjectsList = append(attributeObjectsList, attributeObject_MonogenicDiseaseVariantsTested)
	}

	addMonogenicDiseaseNumberOfVariantsTestedAttribute(59, "MonogenicDisease_Cystic_Fibrosis_NumberOfVariantsTested")
	addMonogenicDiseaseVariantProbabilityAttribute(60, "MonogenicDisease_Cystic_Fibrosis_ProbabilityOfPassingAVariant")

	addMonogenicDiseaseNumberOfVariantsTestedAttribute(61, "MonogenicDisease_Sickle_Cell_Anemia_NumberOfVariantsTested")
	addMonogenicDiseaseVariantProbabilityAttribute(62, "MonogenicDisease_Sickle_Cell_Anemia_ProbabilityOfPassingAVariant")

	// TODO: Change attributeIdentifiers so:
	//	-Polygenic diseases are allotted the range: 1000 - 1999
	//	-Monogenic diseases are allotted the range: 2000 - 9,999
	//	-rsIDs are allotted the range: 10,000 - 3,000,000 (profiles will probably never share more than 500,000 loci)

	// We build the profile from the traits/polygenic diseases objects list
	// This approach is temporary
	// Once we have profile versions on a testnet/mainnet, we have to keep the loci static for each profile version
	// For now, profile encodings will change whenever we add/remove locus metadata

	// This map will store all rsIDs for traits and polygenic diseases
	shareableRSIDsMap := make(map[int64]struct{})

	traitObjectsList, err := traits.GetTraitObjectsList()
	if (err != nil){ return err }

	for _, traitObject := range traitObjectsList{

		traitLociList := traitObject.LociList

		for _, rsID  := range traitLociList{

			shareableRSIDsMap[rsID] = struct{}{}
		}
	}

	polygenicDiseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList()
	if (err != nil) { return err }

	for _, diseaseObject := range polygenicDiseaseObjectsList{

		diseaseLociList := diseaseObject.LociList

		for _, rsID := range diseaseLociList{

			shareableRSIDsMap[rsID] = struct{}{}
		}
	}

	shareableRSIDsList := helpers.GetListOfMapKeys(shareableRSIDsMap)

	// We sort rsIDs so they are always in the same order

	slices.Sort(shareableRSIDsList)


	validBasesList := []string{"C", "A", "T", "G", "I", "D"}

	checkValueFunction_GenomeBasePair := func(profileVersion int, profileType string, input string)(bool, bool, error){

		if (profileVersion != 1){
			return false, false, errors.New("Trying to check profile value for unknown profile version.")
		}

		if (profileType != "Mate"){
			return false, false, errors.New("Invalid profile type when trying to verify MonogenicDiseaseNumberOfVariantsTested: " + profileType)
		}

		base1, base2, delimiterFound := strings.Cut(input, ";")
		if (delimiterFound == false){
			return false, false, nil
		}

		baseIsValid := slices.Contains(validBasesList, base1)
		if (baseIsValid == false){
			return false, false, nil
		}

		baseIsValid = slices.Contains(validBasesList, base2)
		if (baseIsValid == false){
			return false, false, nil
		}

		return true, true, nil
	}

	addLocusValueAttributeObject := func(attributeIdentifier int, attributeName string, mandatoryAttributeName string){

		getMandatoryAttributeFunction := func(profileVersion int)([]string, error){
			if (profileVersion != 1){
				return nil, errors.New("Trying to retrieve mandatory attributes for unknown profile version.")
			}

			mandatoryAttributesList := []string{mandatoryAttributeName}
			return mandatoryAttributesList, nil
		}

		attributeObject_LocusValueBasePair := AttributeObject{
			ProfileVersions: []int{1},
			AttributeIdentifier: attributeIdentifier,
			AttributeName: attributeName,
			GetIsRequired: getIsRequired_No,
			GetMandatoryAttributes: getMandatoryAttributeFunction,
			GetProfileTypes: getProfileTypes_Mate,
			GetIsCanonical: getIsCanonical_Always,
			CheckValueFunction: checkValueFunction_GenomeBasePair,
		}

		attributeObjectsList = append(attributeObjectsList, attributeObject_LocusValueBasePair)
	}

	addLocusIsPhasedAttributeObject := func(attributeIdentifier int, attributeName string, mandatoryAttributeName string){

		getMandatoryAttributeFunction := func(profileVersion int)([]string, error){
			if (profileVersion != 1){
				return nil, errors.New("Trying to retrieve mandatory attributes for unknown profile version.")
			}

			mandatoryAttributesList := []string{mandatoryAttributeName}
			return mandatoryAttributesList, nil
		}

		attributeObject_LocusIsPhased := AttributeObject{
			ProfileVersions: []int{1},
			AttributeIdentifier: attributeIdentifier,
			AttributeName: attributeName,
			GetIsRequired: getIsRequired_No,
			GetMandatoryAttributes: getMandatoryAttributeFunction,
			GetProfileTypes: getProfileTypes_Mate,
			GetIsCanonical: getIsCanonical_Always,
			CheckValueFunction: checkValueFunction_MateYesOrNo,
		}

		attributeObjectsList = append(attributeObjectsList, attributeObject_LocusIsPhased)
	}

	index := 10000

	for _, rsID := range shareableRSIDsList{

		rsIDString := helpers.ConvertInt64ToString(rsID)

		locusValueAttributeName := "LocusValue_rs" + rsIDString
		locusIsPhasedAttributeName := "LocusIsPhased_rs" + rsIDString

		addLocusValueAttributeObject(index, locusValueAttributeName, locusIsPhasedAttributeName)

		index += 1

		addLocusIsPhasedAttributeObject(index, locusIsPhasedAttributeName, locusValueAttributeName)

		index += 1
	}

	profileAttributeObjectsList = attributeObjectsList

	return nil
}




