package org.nextprot.api.core.service.impl;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.nextprot.api.commons.constants.AnnotationCategory;
import org.nextprot.api.commons.service.MasterIdentifierService;
import org.nextprot.api.core.domain.Entry;
import org.nextprot.api.core.domain.EntryUtils;
import org.nextprot.api.core.domain.annotation.Annotation;
import org.nextprot.api.core.service.AnnotationService;
import org.nextprot.api.core.service.AntibodyMappingService;
import org.nextprot.api.core.service.DbXrefService;
import org.nextprot.api.core.service.EntryBuilderService;
import org.nextprot.api.core.service.EntryPropertiesService;
import org.nextprot.api.core.service.ExperimentalContextService;
import org.nextprot.api.core.service.GeneService;
import org.nextprot.api.core.service.GenomicMappingService;
import org.nextprot.api.core.service.IdentifierService;
import org.nextprot.api.core.service.InteractionService;
import org.nextprot.api.core.service.IsoformService;
import org.nextprot.api.core.service.OverviewService;
import org.nextprot.api.core.service.PeptideMappingService;
import org.nextprot.api.core.service.PublicationService;
import org.nextprot.api.core.service.TerminologyService;
import org.nextprot.api.core.service.fluent.EntryConfig;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
class EntryBuilderServiceImpl implements EntryBuilderService, InitializingBean{
@Autowired private OverviewService overviewService;
@Autowired private PublicationService publicationService;
@Autowired private DbXrefService xrefService;
@Autowired private IdentifierService identifierService;
@Autowired private GeneService geneService;
@Autowired private GenomicMappingService genomicMappingService;
@Autowired private IsoformService isoformService;
@Autowired private MasterIdentifierService masterIdentifierService;
@Autowired private AnnotationService annotationService;
@Autowired private PeptideMappingService peptideMappingService;
@Autowired private AntibodyMappingService antibodyMappingService;
@Autowired private InteractionService interactionService;
@Autowired private ExperimentalContextService expCtxService;
@Autowired private TerminologyService terminologyService; //TODO shouldn't we have method in entry to get the enzymes based on the EC names???
@Autowired private EntryPropertiesService entryPropertiesService;
private static Map<String, Object> objectLocks = new ConcurrentHashMap<>();
@Override
public Entry build(EntryConfig entryConfig) {
String entryName = EntryUtils.getEntryName(entryConfig.getEntryName());
Entry entry = new Entry(entryName);
//Lock per entry in case the cache is not set yet (should be quite) fast thougth
synchronized (getOrPutSynchronizer(entryName)){
//Always set properties about the entry, unless it was explicitly said not to set them
if(!entryConfig.hasNoProperties()){
entry.setProperties(entryPropertiesService.findEntryProperties(entryName));
}
if(entryConfig.hasOverview()){
entry.setOverview(this.overviewService.findOverviewByEntry(entryName));
}
if(entryConfig.hasPublications()){
entry.setPublications(this.publicationService.findPublicationsByMasterUniqueName(entryName));
}
if(entryConfig.hasXrefs()){
entry.setXrefs(this.xrefService.findDbXrefsByMaster(entryName));
}
if(entryConfig.hasIdentifiers()){
entry.setIdentifiers(this.identifierService.findIdentifiersByMaster(entryName));
}
if(entryConfig.hasChromosomalLocations()){
entry.setChromosomalLocations(this.geneService.findChromosomalLocationsByEntry(entryName));
}
if(entryConfig.hasGenomicMappings()){
entry.setGenomicMappings(this.genomicMappingService.findGenomicMappingsByEntryName(entryName));
}
if(entryConfig.hasTargetIsoforms()){
entry.setIsoforms(this.isoformService.findIsoformsByEntryName(entryName));
}
if(entryConfig.hasGeneralAnnotations()){
if (entryConfig.hasBed()) {
entry.setAnnotations(
this.annotationService.findAnnotations(entryName));
} else {
entry.setAnnotations(
this.annotationService.findAnnotationsExcludingBed(entryName));
}
}
//This will be deprecated in the future
if(entryConfig.hasSubPart(AnnotationCategory.PEPTIDE_MAPPING)){
entry.setPeptideMappings(this.peptideMappingService.findNaturalPeptideMappingByMasterUniqueName(entryName));
}
if(entryConfig.hasSubPart(AnnotationCategory.SRM_PEPTIDE_MAPPING)){
entry.setSrmPeptideMappings(this.peptideMappingService.findSyntheticPeptideMappingByMasterUniqueName(entryName));
}
///////
if(entryConfig.hasExperimentalContext()){
List<Annotation> annotations = entry.getAnnotations();
//In case we did't set annotations but we need them to find experimental contexts
if(annotations == null) {
annotations = this.annotationService.findAnnotations(entryName);
}
Set<Long> ecIds = EntryUtils.getExperimentalContextIds(annotations);
entry.setExperimentalContexts(expCtxService.findExperimentalContextsByIds(ecIds));
}
if(entryConfig.hasInteractions()){
entry.setInteractions(this.interactionService.findInteractionsByEntry(entryName));
}
if(entryConfig.hasEnzymes()){
entry.setEnzymes(terminologyService.findEnzymeByMaster(entryName));
}
if((entryConfig.hasGeneralAnnotations() || entryConfig.hasSubPart())){ //TODO should be added in annotation list
setEntryAdditionalInformation(entry, entryConfig); //adds isoforms, publications, xrefs and experimental contexts
}
}
//CPU Intensive
if(entryConfig.hasSubPart() || entryConfig.hasGoldOnly()){ //TODO should be added in annotation list
return EntryUtils.filterEntryBySubPart(entry, entryConfig);
} else {
return entry;
}
}
private static Object getOrPutSynchronizer(String entryName) {
if(objectLocks.containsKey(entryName)){
return objectLocks.get(entryName);
}else {
Object o = new Object();
objectLocks.put(entryName, o);
return o;
}
}
private void setEntryAdditionalInformation(Entry entry, EntryConfig config){
if(entry.getAnnotations() == null || entry.getAnnotations().isEmpty()){
if (config.hasBed()) {
entry.setAnnotations(
this.annotationService.findAnnotations(entry.getUniqueName()));
} else {
entry.setAnnotations(
this.annotationService.findAnnotationsExcludingBed(entry.getUniqueName()));
}
}
if(!config.hasNoAdditionalReferences()){
if(entry.getIsoforms() == null || entry.getIsoforms().isEmpty()){
entry.setIsoforms(this.isoformService.findIsoformsByEntryName(entry.getUniqueName()));
}
if(entry.getPublications() == null || entry.getPublications().isEmpty()){
entry.setPublications(this.publicationService.findPublicationsByMasterUniqueName(entry.getUniqueName()));
}
if(entry.getXrefs() == null || entry.getXrefs().isEmpty()){
entry.setXrefs(this.xrefService.findDbXrefsByMaster(entry.getUniqueName()));
}
if(entry.getExperimentalContexts() == null || entry.getExperimentalContexts().isEmpty()){
Set<Long> ecIds = EntryUtils.getExperimentalContextIds(entry.getAnnotations());
entry.setExperimentalContexts(expCtxService.findExperimentalContextsByIds(ecIds));
}
}
}
@Override
public Entry buildWithEverything(String entryName) {
return this.build(EntryConfig.newConfig(entryName).withEverything());
}
@Override
public void afterPropertiesSet() throws Exception {
for(String uniqueName : masterIdentifierService.findUniqueNames()){
objectLocks.put(uniqueName, new Object());
}
}
}