
// polygenicDiseases provides information about polygenic diseases and the loci that influence them

package polygenicDiseases

// Polygenic diseases are different from monogenicDiseases
// Monogenic diseases are well understood to be caused by mutations in a single gene, and thus have more accurate risk probabilities.
// Polygenic disease probabilities are less accurate, because individual base pair changes only cause comparatively small changes in the disease risk.
// Polygenic diseases are also more influenced by environmental factors, further decreasing risk accuracy.

import "errors"


type PolygenicDisease struct{

	DiseaseName string

	DiseaseDescription string

	// Is either "Mate"/"Female"/"Both"
	EffectedSex string

	// This is a list of rsIDs which are known to have an effect on this disease
	// We use these loci to predict trait outcomes with neural networks.
	// Map Structure: rsID -> (map[Reference Name]Reference Link)
	LocusReferencesMap map[int64]map[string]string

	// This is a list of all loci used to predict this disease's risk
	// This should be a list of the keys in LocusReferencesMap
	LociList []int64

	// Inputs:
	//	-string: "Mate"/"Female"
	//	-int: Age
	// Output:
	//	-float64: Average probability of having had the disease at that point in person's life
	//	-error
	GetAverageRiskProbabilitiesFunction func(string, int)(float64, error)

	// This map contains scientific resources about this disease
	// Map Structure: Reference name -> Reference link
	References map[string]string
}


var polygenicDiseaseNamesList []string
var polygenicDiseaseObjectsList []PolygenicDisease

// This must be called once during application startup
func InitializePolygenicDiseaseVariables()error{

	breastCancerObject := getBreastCancerDiseaseObject()
	autismObject := getAutismDiseaseObject()

	obesityObject, err := getObesityDiseaseObject()
	if (err != nil) { return err }

	polygenicDiseaseObjectsList = []PolygenicDisease{breastCancerObject, autismObject, obesityObject}

	polygenicDiseaseNamesList = make([]string, 0, len(polygenicDiseaseObjectsList))

	for _, diseaseObject := range polygenicDiseaseObjectsList{

		diseaseName := diseaseObject.DiseaseName

		polygenicDiseaseNamesList = append(polygenicDiseaseNamesList, diseaseName)
	}

	return nil
}

// Be aware that all of these functions are returning original objects/slices, not copies
// Thus, we cannot edit the objects/slices that are returned. We must copy the fields first if we want to edit them.

func GetPolygenicDiseaseNamesList()([]string, error){

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

	return polygenicDiseaseNamesList, nil
}

func GetPolygenicDiseaseObjectsList()([]PolygenicDisease, error){

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

	return polygenicDiseaseObjectsList, nil
}

func GetPolygenicDiseaseObject(diseaseName string)(PolygenicDisease, error){

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

	for _, diseaseObject := range polygenicDiseaseObjectsList{

		currentDiseaseName := diseaseObject.DiseaseName
		if (currentDiseaseName != diseaseName){
			continue
		}

		return diseaseObject, nil
	}

	return PolygenicDisease{}, errors.New("GetPolygenicDiseaseObject called with unknown disease name: " + diseaseName)
}

