
// importLocusMetadata.go provides a function to import locus metadata from raw genome files.
// It uses a 23andMe raw genome file to find the chromosomes and positions for new rsIDs.
// The 23andMe file only contains Chromosome and Position information.
// This utility creates a NewLocusMetadata.gob file, which must be renamed to LocusMetadata.gob and placed in the /resources/geneticReferences/locusMetadata folder
// TODO: Instead of using 23andMe files, use a better full-genome reference which has gene names.


package main

import "seekia/internal/genetics/geneticReferences/locusMetadata"
import "seekia/internal/genetics/geneticReferences/modifyLocusMetadata"
import "seekia/internal/genetics/readRawGenomes"
import "seekia/internal/helpers"
import "seekia/internal/localFilesystem"

import "errors"
import "strings"
import "bytes"

import "log"


func main(){

	importLocusMetadataFunction := func()error{

		fileExists, fileBytes, err := localFilesystem.GetFileContents("./23andMeRawGenome.txt")
		if (err != nil){ return err }
		if (fileExists == false){
			return errors.New("Error: 23AndMeRawGenome.txt does not exist. You must add a 23andMe raw genome file to the importLocusMetadata folder so we can retrieve locus metadata from the file.")
		}

		fileReader := bytes.NewReader(fileBytes)

		ableToReadFile, locusLocationsMap, err := readRawGenomes.ReadRawGenomeFileLocusLocations(fileReader)
		if (err != nil){ return err }
		if (ableToReadFile == false){
			return errors.New("Unable to read 23andMe file.")
		}

		// This is a list of rsIDs whose metadata we should add to the locus metadata
		lociToAddList := []int64{}

		containsDuplicates, _ := helpers.CheckIfListContainsDuplicates(lociToAddList)
		if (containsDuplicates == true){
			return errors.New("lociToAddList contains duplicates.")
		}

		// This list will store the loci for which no metadata existed
		missingLociList := make([]int64, 0)

		// This is a list of locus metadata objects to add
		locusMetadatasToAddList := make([]locusMetadata.LocusMetadata, 0)

		for _, rsID := range lociToAddList{

			locusLocationObject, exists := locusLocationsMap[rsID]
			if (exists == false){
				// The 23andMe file does not contain metadata for this locus
				missingLociList = append(missingLociList, rsID)
				continue
			}

			locusChromosome := locusLocationObject.Chromosome
			locusPosition := locusLocationObject.Position

			newLocusMetadataObject := locusMetadata.LocusMetadata{
				RSIDsList: []int64{rsID},
				Chromosome: locusChromosome,
				Position: locusPosition,
				GeneInfoIsKnown: false,
				GeneExists: false,
				GeneNamesList: make([]string, 0),
				CompanyAliases: make(map[locusMetadata.GeneticsCompany][]string),
				References: make(map[string]string),
			}

			locusMetadatasToAddList = append(locusMetadatasToAddList, newLocusMetadataObject)
		}

		quantityOfAddedLoci, newLocusMetadataFileBytes, err := modifyLocusMetadata.AddLocusMetadata(locusMetadatasToAddList)
		if (err != nil) { return err }

		err = localFilesystem.CreateOrOverwriteFile(newLocusMetadataFileBytes, "./", "NewLocusMetadata.gob")
		if (err != nil){ return err }

		totalLociToAdd := len(lociToAddList)
		totalLociToAddString := helpers.ConvertIntToString(totalLociToAdd)

		numberOfImportedLociString := helpers.ConvertIntToString(quantityOfAddedLoci)

		log.Println("Successfully imported " + numberOfImportedLociString + "/" + totalLociToAddString + " locus metadatas!")

		numberOfMissingLoci := len(missingLociList)
		numberOfMissingLociString := helpers.ConvertIntToString(numberOfMissingLoci)

		log.Println(numberOfMissingLociString + " loci contained no metadata in the 23andMe genome file.")

		if (len(missingLociList) > 0){

			missingLociStringsList := make([]string, 0, len(missingLociList))

			for _, rsID := range missingLociList{

				rsIDString := helpers.ConvertInt64ToString(rsID)

				missingLociStringsList = append(missingLociStringsList, rsIDString)
			}

			missingLociListFormatted := strings.Join(missingLociStringsList, ", ")

			log.Println("Missing loci list: " + missingLociListFormatted)
		}

		return nil
	}

	err := importLocusMetadataFunction()
	if (err != nil){
		log.Println("ERROR: " + err.Error())
		return
	}
}


