seekia/internal/genetics/myChosenAnalysis/myChosenAnalysis.go

183 lines
7.4 KiB
Go

// myChosenAnalysis provides a function to get a mate user's chosen genetic analysis
// Mate users choose a genome person and genome in the Build Profile gui.
// The genome person's analysis is used for calculating genetic attributes with other users and for sharing on their profile
// The user can choose to not share any of the genetic analysis information on their profile, in which case
// the analysis is only used when calculating attributes with other users
// An example of one of these calculated attributes is "OffspringProbabilityOfAnyMonogenicDisease"
package myChosenAnalysis
import "seekia/internal/genetics/myAnalyses"
import "seekia/internal/genetics/myPeople"
import "seekia/internal/genetics/readGeneticAnalysis"
import "seekia/internal/helpers"
import "seekia/internal/profiles/myLocalProfiles"
import "errors"
import "sync"
// We use this mutex whenever we update the cacheChosenGeneticAnalysis global variables
var myCacheChosenGeneticAnalysisMutex sync.RWMutex
// We use this identifier to keep track of which analysis we have stored in the cache
// Whenever we update our genome person's analysis, we will update our cache analysis
var myCacheChosenGeneticAnalysisIdentifier string
// We use this variable to store the analysis in memory
// This prevents us from having to read and unmarshal the json file each time we want to retrieve the analysis
// TODO: Read attributes from the analysis into maps for faster retrieval
var myCacheChosenGeneticAnalysis []map[string]string
// These variables store metadata about the cache genetic analysis
var myCacheChosenGeneticAnalysis_GenomeIdentifierToUse string
// This variable tells us if the current cache chosen genetic analysis contains multiple genomes
var myCacheChosenGeneticAnalysis_MultipleGenomesExist bool
// This function is used to retrieve the user's chosen person genetic analysis
// The user must choose a person to link to their mate profile/identity
// This genetic analysis is not shared on the person's profile publicly.
// Portions of the analysis may be shared if the user opts in.
//Outputs:
// -bool: Person identifier chosen
// -bool: Any genomes exist
// -bool: Person analysis is ready
// -[]map[string]string: Genetic analysis map list
// -string: Genome identifier to use
// -bool: Multiple genomes exist
// -error
func GetMyChosenMateGeneticAnalysis()(bool, bool, bool, []map[string]string, string, bool, error){
// We check if the user has added a genome person, and add their genome info if necessary
myGenomePersonIdentifierExists, myGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier")
if (err != nil){ return false, false, false, nil, "", false, err }
if (myGenomePersonIdentifierExists == false){
return false, false, false, nil, "", false, nil
}
anyGenomesExist, personAnalysisIsReady, personAnalysisIdentifier, err := myPeople.CheckIfPersonAnalysisIsReady(myGenomePersonIdentifier)
if (err != nil){ return false, false, false, nil, "", false, err }
if (anyGenomesExist == false){
return true, false, false, nil, "", false, nil
}
if (personAnalysisIsReady == false){
return true, true, false, nil, "", false, nil
}
myCacheChosenGeneticAnalysisMutex.RLock()
myCacheChosenGeneticAnalysisIdentifierCopy := myCacheChosenGeneticAnalysisIdentifier
myCacheChosenGeneticAnalysisMutex.RUnlock()
if (myCacheChosenGeneticAnalysisIdentifierCopy == personAnalysisIdentifier){
// The analysis exists in cache
// We copy it and return it
myCacheChosenGeneticAnalysisMutex.RLock()
myCacheChosenGeneticAnalysisCopy := helpers.DeepCopyStringToStringMapList(myCacheChosenGeneticAnalysis)
myCacheChosenGeneticAnalysis_GenomeIdentifierToUseCopy := myCacheChosenGeneticAnalysis_GenomeIdentifierToUse
myCacheChosenGeneticAnalysis_MultipleGenomesExistCopy := myCacheChosenGeneticAnalysis_MultipleGenomesExist
myCacheChosenGeneticAnalysisMutex.RUnlock()
return true, true, true, myCacheChosenGeneticAnalysisCopy, myCacheChosenGeneticAnalysis_GenomeIdentifierToUseCopy, myCacheChosenGeneticAnalysis_MultipleGenomesExistCopy, nil
}
// The analysis and its metadata have not been read into the cache yet
// We will retrieve it from its .json file
myAnalysisFound, myGeneticAnalysisMapList, err := myAnalyses.GetGeneticAnalysis(personAnalysisIdentifier)
if (err != nil){ return false, false, false, nil, "", false, err }
if (myAnalysisFound == false){
return false, false, false, nil, "", false, errors.New("CheckIfPersonAnalysisIsReady returning missing genetic analysis.")
}
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisMapList)
if (err != nil) { return false, false, false, nil, "", false, err }
getGenomeIdentifierToUse := func()(string, error){
if (multipleGenomesExist == false){
// The analysis only has 1 genome identifier.
analysisOnlyRawGenomeIdentifier := allRawGenomeIdentifiersList[0]
return analysisOnlyRawGenomeIdentifier, nil
}
currentCombinedGenomeToUse, err := GetMyCombinedGenomeToUse()
if (err != nil){ return "", err }
if (currentCombinedGenomeToUse == "Only Exclude Conflicts"){
return onlyExcludeConflictsGenomeIdentifier, nil
}
// currentCombinedGenomeToUse == "Only Include Shared"
return onlyIncludeSharedGenomeIdentifier, nil
}
genomeIdentifierToUse, err := getGenomeIdentifierToUse()
if (err != nil) { return false, false, false, nil, "", false, err }
myCacheChosenGeneticAnalysisMutex.Lock()
myCacheChosenGeneticAnalysisIdentifier = personAnalysisIdentifier
myCacheChosenGeneticAnalysis = myGeneticAnalysisMapList
myCacheChosenGeneticAnalysis_GenomeIdentifierToUse = genomeIdentifierToUse
myCacheChosenGeneticAnalysis_MultipleGenomesExist = multipleGenomesExist
myChosenGeneticAnalysisCopy := helpers.DeepCopyStringToStringMapList(myGeneticAnalysisMapList)
myCacheChosenGeneticAnalysisMutex.Unlock()
return true, true, true, myChosenGeneticAnalysisCopy, genomeIdentifierToUse, multipleGenomesExist, nil
}
//Outputs:
// -string: "Only Include Shared", "Only Exclude Conflicts"
// -error
func GetMyCombinedGenomeToUse()(string, error){
combinedGenomeToUseExists, combinedGenomeToUse, err := myLocalProfiles.GetProfileData("Mate", "CombinedGenomeToUse")
if (err != nil){ return "", err }
if (combinedGenomeToUseExists == false){
return "Only Exclude Conflicts", nil
}
if (combinedGenomeToUse != "Only Include Shared" && combinedGenomeToUse != "Only Exclude Conflicts"){
return "", errors.New("myLocalProfiles is malformed: Contains invalid combinedGenomeToUse: " + combinedGenomeToUse)
}
return combinedGenomeToUse, nil
}
func SetMyCombinedGenomeToUse(combinedGenomeToUse string)error{
if (combinedGenomeToUse != "Only Include Shared" && combinedGenomeToUse != "Only Exclude Conflicts"){
return errors.New("SetCombinedGenomeToUse called with invalid combinedGenomeToUse: " + combinedGenomeToUse)
}
err := myLocalProfiles.SetProfileData("Mate", "CombinedGenomeToUse", combinedGenomeToUse)
if (err != nil) { return err }
// We reset the global variables so the new analysis GenomeIdentifierToUse global variable will be updated
myCacheChosenGeneticAnalysisMutex.Lock()
myCacheChosenGeneticAnalysisIdentifier = ""
myCacheChosenGeneticAnalysis = nil
myCacheChosenGeneticAnalysis_GenomeIdentifierToUse = ""
myCacheChosenGeneticAnalysis_MultipleGenomesExist = false
myCacheChosenGeneticAnalysisMutex.Unlock()
return nil
}