<commit_before>package sbol;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.prefs.Preferences;

import javax.swing.JOptionPane;

import main.Gui;

import org.sbml.libsbml.Model;
import org.sbolstandard.core.*;
import org.sbolstandard.core.impl.*;
import org.sbolstandard.core.impl.AggregatingResolver.UseFirstFound;
import org.sbolstandard.core.util.SBOLDeepEquality;
import org.sbolstandard.core.util.SequenceOntology;

import biomodel.annotation.AnnotationUtility;
import biomodel.annotation.SBOLAnnotation;
import biomodel.parser.BioModel;

import biomodel.util.Utility;

public class SBOLSynthesizer {
	
	private SBOLSynthesisGraph synGraph;
	private SequenceTypeValidator constructValidator;
	
	public SBOLSynthesizer(SBOLSynthesisGraph synGraph, SequenceTypeValidator constructValidator) {
		this.synGraph = synGraph;
		this.constructValidator = constructValidator;
	}
	
	public DnaComponent exportDnaComponent(String exportFilePath, String saveDirectory) {
		DnaComponent synthComp = null;
		SBOLDocument sbolDoc = SBOLFactory.createDocument();
		SBOLUtility.addDNAComponent(synthComp, sbolDoc);
		SBOLUtility.writeSBOLDocument(exportFilePath, sbolDoc);
		return synthComp;
	}
	
	// Synthesizes new composite DNA component from graph of annotated model elements, loads/constructs component descriptors and identifiers, 
	// saves component to local SBOL files, and uses component to annotate model itself 
//	public DnaComponent saveDnaComponent(String saveDirectory, boolean saveModel) {
//		DnaComponent synthComp = null;
//		// Synthesize DNA component
//		synthComp = synthesizeDNAComponent();
//		if (synthComp != null) {
//			// Load/construct component descriptors and identifiers
//			URI existingBioSimURI = loadSBOLDescriptors(synthComp);
//			if (existingBioSimURI.toString().endsWith("iBioSimNull") || existingBioSimURI.toString().endsWith("iBioSim")
//					|| existingBioSimURI.toString().endsWith("iBioSimPlaceHolder"))
//				constructURIs(synthComp, existingBioSimURI);
//			// Save component to local SBOL files
//			for (String sbolFile : sbolManager.getSBOLFiles()) {
//				if (existingBioSimURI.toString().endsWith("iBioSim") || sbolFile.equals(targetFile)) {
//					SBOLDocument sbolDoc = SBOLUtility.loadSBOLFile(saveDirectory + File.separator + sbolFile);
//					if (existingBioSimURI.toString().endsWith("iBioSim"))
//						SBOLUtility.mergeDNAComponent(existingBioSimURI, synthComp, sbolDoc);
//					if (sbolFile.equals(targetFile))
//						SBOLUtility.addDNAComponent(synthComp, sbolDoc);
//					SBOLUtility.writeSBOLDocument(saveDirectory + File.separator + sbolFile, sbolDoc);
//				}
//			}
//			// Use component to annotate model itself
//			Model sbmlModel = bioModel.getSBMLDocument().getModel();
//			SBOLAnnotation sbolAnnot = new SBOLAnnotation(sbmlModel.getMetaId(), modelURIs);
//			AnnotationUtility.setSBOLAnnotation(sbmlModel, sbolAnnot);
//			bioModel.setModelSBOLAnnotationFlag(true);
//			if (saveModel)
//				bioModel.save(saveDirectory + File.separator + sbmlModel.getId() + ".gcm");
//
//		}
//		return synthComp;
//	}
	
	public DnaComponent synthesizeDNAComponent() {	
		// Orders list of subcomponents (to be assembled into composite component) 
		// by walking synthesis nodes
//		String regex = Preferences.userRoot().get("biosim.synthesis.regex", "");
//		SequenceTypeValidator validator = new SequenceTypeValidator(regex);
//		Set<String> startTypes = new HashSet<String>();
//		if (validator.getStartTypes().size() > 0)
//			startTypes.addAll(validator.getStartTypes());
//		else
//			startTypes.add("promoter");
//		
		List<DnaComponent> subComps = orderSubComponents();
		if (subComps == null)
			return null;
		// Create composite component and its sequence
		DnaComponent synthComp = new DnaComponentImpl();	
		DnaSequence synthSeq = new DnaSequenceImpl();
		synthSeq.setNucleotides("");
		synthComp.setDnaSequence(synthSeq);

		int position = 1;
		int addCount = 0;
		LinkedList<String> types = new LinkedList<String>();
		for (DnaComponent subComp : subComps) {
			position = addSubComponent(position, subComp, synthComp, addCount);
			if (position == -1)
				return null;
			addCount++;
			//				types.add(SBOLUtility.uriToSOTypeConverter(subComp.getTypes().iterator().next()));
			types.addAll(SBOLUtility.loadLowestSOTypes(subComp));
		}

		if (constructValidator != null && !constructValidator.validate(types)) {
			Object[] options = { "OK", "Cancel" };
			int choice = JOptionPane.showOptionDialog(null, 
					"Ordering of SBOL DNA components associated to SBML does not match preferred regular expression for a complete genetic construct.  Proceed with synthesis?", 
					"Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
			if (choice != JOptionPane.OK_OPTION)
				return null;
		}
		return synthComp;
//		}
	}
	
	private int addSubComponent(int position, DnaComponent subComp, DnaComponent synthComp, int addCount) {	
		if (subComp.getDnaSequence() != null && subComp.getDnaSequence().getNucleotides() != null 
				&& subComp.getDnaSequence().getNucleotides().length() >= 1) {
			SequenceAnnotation annot = new SequenceAnnotationImpl();
			annot.setBioStart(position);
			position += subComp.getDnaSequence().getNucleotides().length() - 1;
			annot.setBioEnd(position);
			annot.setStrand(StrandType.POSITIVE);
			annot.setSubComponent(subComp);
			synthComp.addAnnotation(annot);
			position++;
//			try {
//				annot.setURI(new URI(uriAuthority + "#anno" + addCount + time + "_iBioSim"));
//			} catch (URISyntaxException e) {
//				e.printStackTrace();
//			}
			synthComp.getDnaSequence().setNucleotides(synthComp.getDnaSequence().getNucleotides() + subComp.getDnaSequence().getNucleotides());
		} else {
			JOptionPane.showMessageDialog(Gui.frame, "DNA Component " + subComp.getDisplayId() + " has no DNA sequence.", 
					"Invalid DNA Sequence", JOptionPane.ERROR_MESSAGE);
			return -1;
		}	
		return position;
	}
	
	private List<DnaComponent> orderSubComponents() {
		List<DnaComponent> subComps = new LinkedList<DnaComponent>();
		List<DnaComponent> subCompsWithoutTerminal = new LinkedList<DnaComponent>();
		List<DnaComponent> subCompsWithoutStart = new LinkedList<DnaComponent>();
		List<DnaComponent> subCompsWithoutStartOrTerminal = new LinkedList<DnaComponent>();
		String p = "promoter";
		String r = "ribosome entry site";
		String c = "coding sequence";
		String t = "terminator";
		SequenceTypeValidator serialValidator = new SequenceTypeValidator("(("+p+"(("+r+","+c+")+"+t+"+"+p+")*("+r+","+c+")*("+r+"("+c+","+t+"*)?)?)" +
				"|("+r+"(("+c+","+r+")*"+c+","+t+"+"+p+","+r+")*("+c+","+r+")*("+c+"("+t+"+"+p+"?)?)?)" +
				"|("+c+"(("+r+","+c+")*"+t+"+"+p+","+r+","+c+")*("+r+","+c+")*("+r+"|("+t+"+("+p+","+r+"?)?))?)" +
				"|("+t+"+("+p+"("+r+","+c+")+"+t+"+)*("+p+"("+r+","+c+")*"+r+"?)?))?");
//		SequenceTypeValidator serialValidator = new SequenceTypeValidator("p");
		Set<String> startTypes = constructValidator.getStartTypes();
		Set<String> terminalTypes = constructValidator.getTerminalTypes();
		for (SBOLSynthesisNode startNode : synGraph.getStartNodes()) {
			List<DnaComponent> dnaComps = gatherDNAComponents(startNode, serialValidator, terminalTypes);<commit_msg>Fixed bug involving the need to reset the SequenceTypeValidator before gathering DNA components from each start node.<commit_after>package sbol;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.prefs.Preferences;

import javax.swing.JOptionPane;

import main.Gui;

import org.sbml.libsbml.Model;
import org.sbolstandard.core.*;
import org.sbolstandard.core.impl.*;
import org.sbolstandard.core.impl.AggregatingResolver.UseFirstFound;
import org.sbolstandard.core.util.SBOLDeepEquality;
import org.sbolstandard.core.util.SequenceOntology;

import biomodel.annotation.AnnotationUtility;
import biomodel.annotation.SBOLAnnotation;
import biomodel.parser.BioModel;

import biomodel.util.Utility;

public class SBOLSynthesizer {
	
	private SBOLSynthesisGraph synGraph;
	private SequenceTypeValidator constructValidator;
	
	public SBOLSynthesizer(SBOLSynthesisGraph synGraph, SequenceTypeValidator constructValidator) {
		this.synGraph = synGraph;
		this.constructValidator = constructValidator;
	}
	
	public DnaComponent exportDnaComponent(String exportFilePath, String saveDirectory) {
		DnaComponent synthComp = null;
		SBOLDocument sbolDoc = SBOLFactory.createDocument();
		SBOLUtility.addDNAComponent(synthComp, sbolDoc);
		SBOLUtility.writeSBOLDocument(exportFilePath, sbolDoc);
		return synthComp;
	}
	
	// Synthesizes new composite DNA component from graph of annotated model elements, loads/constructs component descriptors and identifiers, 
	// saves component to local SBOL files, and uses component to annotate model itself 
//	public DnaComponent saveDnaComponent(String saveDirectory, boolean saveModel) {
//		DnaComponent synthComp = null;
//		// Synthesize DNA component
//		synthComp = synthesizeDNAComponent();
//		if (synthComp != null) {
//			// Load/construct component descriptors and identifiers
//			URI existingBioSimURI = loadSBOLDescriptors(synthComp);
//			if (existingBioSimURI.toString().endsWith("iBioSimNull") || existingBioSimURI.toString().endsWith("iBioSim")
//					|| existingBioSimURI.toString().endsWith("iBioSimPlaceHolder"))
//				constructURIs(synthComp, existingBioSimURI);
//			// Save component to local SBOL files
//			for (String sbolFile : sbolManager.getSBOLFiles()) {
//				if (existingBioSimURI.toString().endsWith("iBioSim") || sbolFile.equals(targetFile)) {
//					SBOLDocument sbolDoc = SBOLUtility.loadSBOLFile(saveDirectory + File.separator + sbolFile);
//					if (existingBioSimURI.toString().endsWith("iBioSim"))
//						SBOLUtility.mergeDNAComponent(existingBioSimURI, synthComp, sbolDoc);
//					if (sbolFile.equals(targetFile))
//						SBOLUtility.addDNAComponent(synthComp, sbolDoc);
//					SBOLUtility.writeSBOLDocument(saveDirectory + File.separator + sbolFile, sbolDoc);
//				}
//			}
//			// Use component to annotate model itself
//			Model sbmlModel = bioModel.getSBMLDocument().getModel();
//			SBOLAnnotation sbolAnnot = new SBOLAnnotation(sbmlModel.getMetaId(), modelURIs);
//			AnnotationUtility.setSBOLAnnotation(sbmlModel, sbolAnnot);
//			bioModel.setModelSBOLAnnotationFlag(true);
//			if (saveModel)
//				bioModel.save(saveDirectory + File.separator + sbmlModel.getId() + ".gcm");
//
//		}
//		return synthComp;
//	}
	
	public DnaComponent synthesizeDNAComponent() {	
		// Orders list of subcomponents (to be assembled into composite component) 
		// by walking synthesis nodes
//		String regex = Preferences.userRoot().get("biosim.synthesis.regex", "");
//		SequenceTypeValidator validator = new SequenceTypeValidator(regex);
//		Set<String> startTypes = new HashSet<String>();
//		if (validator.getStartTypes().size() > 0)
//			startTypes.addAll(validator.getStartTypes());
//		else
//			startTypes.add("promoter");
//		
		List<DnaComponent> subComps = orderSubComponents();
		if (subComps == null)
			return null;
		// Create composite component and its sequence
		DnaComponent synthComp = new DnaComponentImpl();	
		DnaSequence synthSeq = new DnaSequenceImpl();
		synthSeq.setNucleotides("");
		synthComp.setDnaSequence(synthSeq);

		int position = 1;
		int addCount = 0;
		LinkedList<String> types = new LinkedList<String>();
		for (DnaComponent subComp : subComps) {
			position = addSubComponent(position, subComp, synthComp, addCount);
			if (position == -1)
				return null;
			addCount++;
			//				types.add(SBOLUtility.uriToSOTypeConverter(subComp.getTypes().iterator().next()));
			types.addAll(SBOLUtility.loadLowestSOTypes(subComp));
		}

		if (constructValidator != null && !constructValidator.validate(types)) {
			Object[] options = { "OK", "Cancel" };
			int choice = JOptionPane.showOptionDialog(null, 
					"Ordering of SBOL DNA components associated to SBML does not match preferred regular expression for a complete genetic construct.  Proceed with synthesis?", 
					"Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
			if (choice != JOptionPane.OK_OPTION)
				return null;
		}
		return synthComp;
//		}
	}
	
	private int addSubComponent(int position, DnaComponent subComp, DnaComponent synthComp, int addCount) {	
		if (subComp.getDnaSequence() != null && subComp.getDnaSequence().getNucleotides() != null 
				&& subComp.getDnaSequence().getNucleotides().length() >= 1) {
			SequenceAnnotation annot = new SequenceAnnotationImpl();
			annot.setBioStart(position);
			position += subComp.getDnaSequence().getNucleotides().length() - 1;
			annot.setBioEnd(position);
			annot.setStrand(StrandType.POSITIVE);
			annot.setSubComponent(subComp);
			synthComp.addAnnotation(annot);
			position++;
//			try {
//				annot.setURI(new URI(uriAuthority + "#anno" + addCount + time + "_iBioSim"));
//			} catch (URISyntaxException e) {
//				e.printStackTrace();
//			}
			synthComp.getDnaSequence().setNucleotides(synthComp.getDnaSequence().getNucleotides() + subComp.getDnaSequence().getNucleotides());
		} else {
			JOptionPane.showMessageDialog(Gui.frame, "DNA Component " + subComp.getDisplayId() + " has no DNA sequence.", 
					"Invalid DNA Sequence", JOptionPane.ERROR_MESSAGE);
			return -1;
		}	
		return position;
	}
	
	private List<DnaComponent> orderSubComponents() {
		List<DnaComponent> subComps = new LinkedList<DnaComponent>();
		List<DnaComponent> subCompsWithoutTerminal = new LinkedList<DnaComponent>();
		List<DnaComponent> subCompsWithoutStart = new LinkedList<DnaComponent>();
		List<DnaComponent> subCompsWithoutStartOrTerminal = new LinkedList<DnaComponent>();
		String p = "promoter";
		String r = "ribosome entry site";
		String c = "coding sequence";
		String t = "terminator";
		SequenceTypeValidator serialValidator = new SequenceTypeValidator("(("+p+"(("+r+","+c+")+"+t+"+"+p+")*("+r+","+c+")*("+r+"("+c+","+t+"*)?)?)" +
				"|("+r+"(("+c+","+r+")*"+c+","+t+"+"+p+","+r+")*("+c+","+r+")*("+c+"("+t+"+"+p+"?)?)?)" +
				"|("+c+"(("+r+","+c+")*"+t+"+"+p+","+r+","+c+")*("+r+","+c+")*("+r+"|("+t+"+("+p+","+r+"?)?))?)" +
				"|("+t+"+("+p+"("+r+","+c+")+"+t+"+)*("+p+"("+r+","+c+")*"+r+"?)?))?");
//		SequenceTypeValidator serialValidator = new SequenceTypeValidator("p");
		Set<String> startTypes = constructValidator.getStartTypes();
		Set<String> terminalTypes = constructValidator.getTerminalTypes();
		for (SBOLSynthesisNode startNode : synGraph.getStartNodes()) {
			serialValidator.reset();
			List<DnaComponent> dnaComps = gatherDNAComponents(startNode, serialValidator, terminalTypes);
{'fraction_non_alphanumeric': 0.14997360781208763, 'fraction_numerical': 0.0010556875164951175, 'mean_word_length': 5.158878504672897, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7200168', 'n_tokens_mistral': 5395, 'n_tokens_neox': 4871, 'n_words': 926}