
// myCouples provides functions to manage a user's genome couples
// A couple is recorded as 2 person identifiers.

package myCouples

import "seekia/internal/myDatastores/myMapList"
import "seekia/internal/genetics/myAnalyses"

import "sync"
import "errors"

// This will be locked anytime Couples are being added/deleted
var updatingMyCouplesMutex sync.Mutex

var myGenomeCouplesMapListDatastore *myMapList.MyMapList

// This function must be called whenever an app user signs in
func InitializeMyGenomeCouplesDatastore()error{

	updatingMyCouplesMutex.Lock()
	defer updatingMyCouplesMutex.Unlock()

	newMyGenomeCouplesMapListDatastore, err := myMapList.CreateNewMapList("MyGenomeCouples")
	if (err != nil) { return err }

	myGenomeCouplesMapListDatastore = newMyGenomeCouplesMapListDatastore

	return nil
}

//Outputs:
//	-[]map[string]string
//		-Person1Identifier -> Person 1 Identifier
//		-Person2Identifier -> Person 2 Identifier
//	-error
func GetMyGenomeCouplesMapList()([]map[string]string, error){

	couplesMapList, err := myGenomeCouplesMapListDatastore.GetMapList()
	if (err != nil) { return nil, err }

	return couplesMapList, nil
}

//Outputs:
//	-bool: Couple already exists
//	-error
func AddCouple(inputPerson1Identifier string, inputPerson2Identifier string)(bool, error){

	person1Identifier, person2Identifier, err := getPeopleIdentifiersSortedForCouple(inputPerson1Identifier, inputPerson2Identifier)
	if (err != nil) { return false, err }

	updatingMyCouplesMutex.Lock()
	defer updatingMyCouplesMutex.Unlock()

	couplesMapList, err := myGenomeCouplesMapListDatastore.GetMapList()
	if (err != nil) { return false, err }

	for _, coupleMap := range couplesMapList{

		currentPerson1Identifier, exists := coupleMap["Person1Identifier"]
		if (exists == false){
			return false, errors.New("MyGenomeCouplesMapList malformed: Contains entry missing Person1Identifier")
		}

		currentPerson2Identifier, exists := coupleMap["Person2Identifier"]
		if (exists == false){
			return false, errors.New("MyGenomeCouplesMapList malformed: Contains entry missing Person2Identifier")
		}

		if (currentPerson1Identifier == person1Identifier && currentPerson2Identifier == person2Identifier){
			return true, nil
		}	
	}

	// Couple does not exist. We add it.

	newPersonMap := map[string]string{
		"Person1Identifier": person1Identifier,
		"Person2Identifier": person2Identifier,
	}

	newCouplesMapList := append(couplesMapList, newPersonMap)

	err = myGenomeCouplesMapListDatastore.OverwriteMapList(newCouplesMapList)
	if (err != nil) { return false, err }

	return false, nil
}

func DeleteCouple(inputPerson1Identifier string, inputPerson2Identifier string)error{

	person1Identifier, person2Identifier, err := getPeopleIdentifiersSortedForCouple(inputPerson1Identifier, inputPerson2Identifier)
	if (err != nil) { return err }

	updatingMyCouplesMutex.Lock()
	defer updatingMyCouplesMutex.Unlock()

	mapToDelete := map[string]string{
		"Person1Identifier": person1Identifier,
		"Person2Identifier": person2Identifier,
	}

	err = myGenomeCouplesMapListDatastore.DeleteMapListItems(mapToDelete)
	if (err != nil) { return err }

	err = myAnalyses.DeleteAllAnalysesForCouple(person1Identifier, person2Identifier)
	if (err != nil) { return err }

	return nil
}

func DeleteAllCouplesForPerson(personIdentifier string)error{

	updatingMyCouplesMutex.Lock()
	defer updatingMyCouplesMutex.Unlock()

	mapToDelete1 := map[string]string{
		"Person1Identifier": personIdentifier,
	}

	err := myGenomeCouplesMapListDatastore.DeleteMapListItems(mapToDelete1)
	if (err != nil) { return err }

	mapToDelete2 := map[string]string{
		"Person2Identifier": personIdentifier,
	}

	err = myGenomeCouplesMapListDatastore.DeleteMapListItems(mapToDelete2)
	if (err != nil) { return err }

	return nil
}

// This is used to show how many couples will be deleted if a user is deleting a person.
func GetNumberOfCouplesForPerson(personIdentifier string)(int, error){

	totalCouples := 0

	lookupMap1 := map[string]string{
		"Person1Identifier": personIdentifier,
	}

	anyItemsFound1, matchingItemsList1, err := myGenomeCouplesMapListDatastore.GetMapListItems(lookupMap1)
	if (err != nil){ return 0, err }
	if (anyItemsFound1 == true){
		totalCouples += len(matchingItemsList1)
	}

	lookupMap2 := map[string]string{
		"Person2Identifier": personIdentifier,
	}

	anyItemsFound2, matchingItemsList2, err := myGenomeCouplesMapListDatastore.GetMapListItems(lookupMap2)
	if (err != nil){ return 0, err }
	if (anyItemsFound2 == true){
		totalCouples += len(matchingItemsList2)
	}

	return totalCouples, nil
}


// This function is used to sort the person identifiers, so that each pair of identifiers will always map to the same couple when added
// The sorting method has no significance
func getPeopleIdentifiersSortedForCouple(person1Identifier string, person2Identifier string)(string, string, error){

	if (person1Identifier == person2Identifier){
		return "", "", errors.New("getPeopleIdentifiersSortedForCouple called with identical person identifiers: " + person1Identifier)
	}

	if (person1Identifier < person2Identifier){
		return person1Identifier, person2Identifier, nil
	}
	return person2Identifier, person1Identifier, nil
}


