uk.ac.ebi.intact.editor.controller.curate.complex.ComplexController.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.ebi.intact.editor.controller.curate.complex.ComplexController.java

Source

/**
 * Copyright 2010 The European Bioinformatics Institute, and others.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.ac.ebi.intact.editor.controller.curate.complex;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.orchestra.conversation.annotations.ConversationName;
import org.joda.time.DateTime;
import org.primefaces.context.RequestContext;
import org.primefaces.event.TabChangeEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import psidev.psi.mi.jami.bridges.exception.BridgeFailedException;
import psidev.psi.mi.jami.model.*;
import psidev.psi.mi.jami.utils.AliasUtils;
import psidev.psi.mi.jami.utils.AnnotationUtils;
import psidev.psi.mi.jami.utils.CvTermUtils;
import psidev.psi.mi.jami.utils.XrefUtils;
import uk.ac.ebi.intact.editor.controller.UserSessionController;
import uk.ac.ebi.intact.editor.controller.curate.AnnotatedObjectController;
import uk.ac.ebi.intact.editor.controller.curate.UnsavedChange;
import uk.ac.ebi.intact.editor.controller.curate.cloner.ComplexCloner;
import uk.ac.ebi.intact.editor.controller.curate.cloner.EditorCloner;
import uk.ac.ebi.intact.editor.controller.curate.cloner.ModelledParticipantCloner;
import uk.ac.ebi.intact.editor.controller.curate.interaction.FeatureWrapper;
import uk.ac.ebi.intact.editor.controller.curate.interaction.ParticipantWrapper;
import uk.ac.ebi.intact.editor.controller.curate.util.ParticipantWrapperCreatedDateComparator;
import uk.ac.ebi.intact.editor.services.curate.complex.ComplexEditorService;
import uk.ac.ebi.intact.editor.services.curate.organism.BioSourceService;
import uk.ac.ebi.intact.jami.ApplicationContextProvider;
import uk.ac.ebi.intact.jami.lifecycle.ComplexBCLifecycleEventListener;
import uk.ac.ebi.intact.jami.lifecycle.IllegalTransitionException;
import uk.ac.ebi.intact.jami.lifecycle.LifeCycleManager;
import uk.ac.ebi.intact.jami.lifecycle.LifecycleEventListener;
import uk.ac.ebi.intact.jami.model.IntactPrimaryObject;
import uk.ac.ebi.intact.jami.model.extension.*;
import uk.ac.ebi.intact.jami.model.lifecycle.LifeCycleEvent;
import uk.ac.ebi.intact.jami.model.lifecycle.LifeCycleEventType;
import uk.ac.ebi.intact.jami.model.lifecycle.LifeCycleStatus;
import uk.ac.ebi.intact.jami.model.lifecycle.Releasable;
import uk.ac.ebi.intact.jami.model.user.User;
import uk.ac.ebi.intact.jami.synchronizer.FinderException;
import uk.ac.ebi.intact.jami.synchronizer.IntactDbSynchronizer;
import uk.ac.ebi.intact.jami.synchronizer.PersisterException;
import uk.ac.ebi.intact.jami.synchronizer.SynchronizerException;
import uk.ac.ebi.intact.jami.utils.IntactUtils;
import uk.ac.ebi.intact.jami.utils.ReleasableUtils;

import javax.annotation.Resource;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.event.ValueChangeEvent;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Bruno Aranda (baranda@ebi.ac.uk)
 * @version $Id$
 */
@Controller
@Scope("conversation.access")
@ConversationName("general")
public class ComplexController extends AnnotatedObjectController {

    private static final Log log = LogFactory.getLog(ComplexController.class);
    private final LifecycleEventListener lifecycleEventListener = new ComplexBCLifecycleEventListener();
    private IntactComplex complex;
    private String ac;
    private LinkedList<ParticipantWrapper> participantWrappers;
    @Autowired
    private UserSessionController userSessionController;
    private boolean isParticipantDisabled;
    private boolean isParameterDisabled;
    private boolean isConfidenceDisabled;
    private boolean isLifeCycleDisabled;
    private boolean assignToMe = true;
    private boolean isComplexReadOnly = false;
    @Resource(name = "jamiLifeCycleManager")
    private transient LifeCycleManager lifecycleManager;
    @Resource(name = "complexEditorService")
    private transient ComplexEditorService complexEditorService;
    @Resource(name = "bioSourceService")
    private transient BioSourceService bioSourceService;
    private String name = null;
    private String toBeReviewed = null;
    private String newToBeReviewed = null;
    private String onHold = null;
    private String obsoleteVersion = null;
    private String correctionComment = null;
    private String cautionMessage = null;
    private String internalRemark = null;
    private String recommendedName = null;
    private String systematicName = null;
    private String description = null;
    private String complexProperties = null;
    private String newXrefPubmed;
    private CvTerm newXrefEvidenceCode;
    private CvTerm newConfidenceType;
    private String newConfidenceValue;
    private CvTerm newParameterType;
    private Double newParameterFactor;
    private CvTerm newParameterUnit;
    private Integer newParameterBase;
    private Integer newParameterExponent;
    private Double newParameterUncertainty;
    private HashMap<String, Integer> dupAuditResult;

    public ComplexController() {
    }

    @Override
    public IntactPrimaryObject getAnnotatedObject() {
        return getComplex();
    }

    @Override
    public void setAnnotatedObject(IntactPrimaryObject annotatedObject) {
        setComplex((IntactComplex) annotatedObject);
    }

    public String getName() {
        return this.name;
    }

    @Override
    protected void initialiseDefaultProperties(IntactPrimaryObject annotatedObject) {
        IntactComplex interaction = (IntactComplex) annotatedObject;
        if (!getComplexEditorService().isComplexFullyLoaded(interaction)) {
            this.complex = getComplexEditorService().reloadFullyInitialisedComplex(interaction);
        }

        refreshParticipants();
        refreshName();

        //Registering listerners
        getLifecycleManager().registerListener(lifecycleEventListener);

    }

    public String getOrganism() {
        return this.complex.getOrganism() != null ? this.complex.getOrganism().getCommonName() : "organism unknown";
    }

    @Override
    protected EditorCloner<Complex, IntactComplex> newClonerInstance() {
        return new ComplexCloner();
    }

    @Override
    public void modifyClone(IntactPrimaryObject clone) {
        super.modifyClone(clone);
        // to be overridden
        IntactComplex complex = (IntactComplex) clone;
        try {
            getLifecycleManager().getStartStatus().create(complex, "Created in Editor", getCurrentUser());

            if (assignToMe) {
                User user = getCurrentUser();
                getLifecycleManager().getNewStatus().claimOwnership(complex, user);
                getLifecycleManager().getAssignedStatus().startCuration(complex, user);
            }

            // Ask to the database for the next available complex accession.
            // It is initialised with version 1. Call this method only for brand new complexes
            String acValue = getComplexEditorService().retrieveNextComplexAc();
            addXref(Xref.COMPLEX_PORTAL, Xref.COMPLEX_PORTAL_MI, acValue, "1", Xref.COMPLEX_PRIMARY,
                    Xref.COMPLEX_PRIMARY_MI, complex.getXrefs());

        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot create complex: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }
    }

    @Override
    public void refreshTabs() {
        super.refreshTabs();
        isParticipantDisabled = false;
        isParameterDisabled = true;
        isConfidenceDisabled = true;
        isLifeCycleDisabled = true;
    }

    @Override
    protected AnnotatedObjectController getParentController() {
        return null;
    }

    @Override
    protected String getPageContext() {
        return "complex";
    }

    @Override
    protected void generalLoadChecks() {
        super.generalLoadChecks();
        generalComplexLoadChecks();
    }

    @Override
    protected void loadCautionMessages() {
        if (this.complex != null) {
            refreshInfoMessages();
        }
    }

    protected void complexElementsRendering() {
        if (complex != null && complex.getAnnotations() != null) {
            for (Annotation annotation : complex.getAnnotations()) {
                if (annotation.getTopic().getShortName().equals("obsolete complex")) {
                    isComplexReadOnly = true;
                    return;
                }
            }

            isComplexReadOnly = false;
        }
    }

    public String getOnHold() {
        return onHold != null ? onHold : "";
    }

    public void setOnHold(String reason) {
        this.onHold = reason;
    }

    public String getCorrectionComment() {
        return correctionComment != null ? correctionComment : null;
    }

    public void setCorrectionComment(String reason) {
        this.correctionComment = reason;
    }

    public void loadData(ComponentSystemEvent event) {
        if (!FacesContext.getCurrentInstance().isPostback()) {

            if (ac != null) {
                if (complex == null || !ac.equals(complex.getAc())) {
                    setComplex(getComplexEditorService().loadComplexByAc(ac));
                }
            } else {
                if (complex != null)
                    ac = complex.getAc();
            }

            if (complex == null) {
                addErrorMessage("No Complex with this AC", ac);
                return;
            }

            refreshTabs();
        }
        generalLoadChecks();
        complexElementsRendering();
    }

    @Override
    protected void postProcessDeletedEvent(UnsavedChange unsaved) {
        super.postProcessDeletedEvent(unsaved);
        if (unsaved.getUnsavedObject() instanceof IntactModelledParticipant) {
            removeParticipant((IntactModelledParticipant) unsaved.getUnsavedObject());
        }
    }

    @Override
    public void doPreSave() {
        // create master proteins from the unsaved manager
        final List<UnsavedChange> transcriptCreated = super.getChangesController()
                .getAllUnsavedProteinTranscripts();
        String currentAc = complex != null ? complex.getAc() : null;

        for (UnsavedChange unsaved : transcriptCreated) {
            IntactInteractor transcript = (IntactInteractor) unsaved.getUnsavedObject();

            // the object to save is different from the current object. Checks that the scope of this object to save is the ac of the current object being saved
            // if the scope is null or different, the object should not be saved at this stage because we only save the current object and changes associated with it
            // if current ac is null, no unsaved event should be associated with it as this object has not been saved yet
            if (unsaved.getScope() != null && unsaved.getScope().equals(currentAc)) {
                try {
                    getEditorService().doSaveMasterProteins(transcript);
                } catch (BridgeFailedException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (SynchronizerException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (FinderException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (PersisterException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (Throwable e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                }

                getChangesController().removeFromHiddenChanges(unsaved);

            } else if (unsaved.getScope() == null && currentAc == null) {
                try {
                    getEditorService().doSaveMasterProteins(transcript);
                } catch (BridgeFailedException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (SynchronizerException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (FinderException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (PersisterException e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                } catch (Throwable e) {
                    addErrorMessage("Cannot save master protein " + transcript.toString(),
                            e.getCause() + ": " + e.getMessage());
                }
                getChangesController().removeFromHiddenChanges(unsaved);
            }
        }
    }

    public void markParticipantToDelete(IntactModelledParticipant component) {
        if (component == null)
            return;

        if (component.getAc() == null) {
            complex.removeParticipant(component);
            refreshParticipants();
        } else {
            Collection<String> parents = collectParentAcsOfCurrentAnnotatedObject();
            if (this.complex.getAc() != null) {
                parents.add(this.complex.getAc());
            }
            getChangesController().markToDelete(component, this.complex,
                    getEditorService().getIntactDao().getSynchronizerContext().getModelledParticipantSynchronizer(),
                    "participant " + component.getAc(), parents);
        }
    }

    public void refreshParticipants() {
        participantWrappers = new LinkedList<ParticipantWrapper>();

        final Collection<ModelledParticipant> components = complex.getParticipants();

        for (ModelledParticipant component : components) {
            participantWrappers.add(new ParticipantWrapper((IntactModelledParticipant) component));
        }

        if (participantWrappers.size() > 0) {
            //We sort the participants for avoiding confusion with the place that a new participant should be appeared.
            Collections.sort(participantWrappers, new ParticipantWrapperCreatedDateComparator());
        }
    }

    public void addParticipant(IntactModelledParticipant component) {
        complex.addParticipant(component);

        participantWrappers.add(new ParticipantWrapper(component));

        if (participantWrappers.size() > 0) {
            Collections.sort(participantWrappers, new ParticipantWrapperCreatedDateComparator());

        }

        setUnsavedChanges(true);
    }

    public String getAc() {
        return ac;
    }

    public void setAc(String ac) {
        this.ac = ac;
    }

    public void cloneParticipant(ParticipantWrapper participantWrapper) {
        ModelledParticipantCloner cloner = new ModelledParticipantCloner();

        IntactModelledParticipant clone = getEditorService()
                .cloneAnnotatedObject((IntactModelledParticipant) participantWrapper.getParticipant(), cloner);
        addParticipant(clone);
        doSave(false);
    }

    public void linkSelectedFeatures(ActionEvent evt) {
        List<AbstractIntactFeature> selected = new ArrayList<AbstractIntactFeature>();

        for (ParticipantWrapper pw : participantWrappers) {
            for (FeatureWrapper fw : pw.getFeatures()) {
                if (fw.isSelected()) {
                    selected.add(fw.getFeature());
                }
            }
        }

        int selectedSize = selected.size();

        Iterator<AbstractIntactFeature> fIterator1 = selected.iterator();
        while (fIterator1.hasNext()) {
            AbstractIntactFeature f1 = fIterator1.next();

            for (AbstractIntactFeature f2 : selected) {
                if (f1.getAc() == null && f1 != f2) {
                    f1.getLinkedFeatures().add(f2);
                    f2.getLinkedFeatures().add(f1);
                } else if (f1.getAc() != null && !f1.getAc().equals(f2.getAc())) {
                    f1.getLinkedFeatures().add(f2);
                    f2.getLinkedFeatures().add(f1);
                }
            }
            fIterator1.remove();
        }

        addInfoMessage("Features linked", "Size of linked features : " + selectedSize);
        setUnsavedChanges(true);
        refreshParticipants();
    }

    public void unlinkFeature(FeatureWrapper wrapper) {
        AbstractIntactFeature feature1 = wrapper.getFeature();
        AbstractIntactFeature feature2 = wrapper.getSelectedLinkedFeature();
        if (feature2 != null) {
            Iterator<Feature> featureIterator = feature1.getLinkedFeatures().iterator();
            Iterator<Feature> feature2Iterator = feature2.getLinkedFeatures().iterator();
            while (featureIterator.hasNext()) {
                AbstractIntactFeature f1 = (AbstractIntactFeature) featureIterator.next();
                if (f1.getAc() == null && f1 == feature2) {
                    featureIterator.remove();
                } else if (f1.getAc() != null && f1.getAc().equals(feature2.getAc())) {
                    featureIterator.remove();
                }
            }
            while (feature2Iterator.hasNext()) {
                AbstractIntactFeature f2 = (AbstractIntactFeature) feature2Iterator.next();
                if (f2.getAc() == null && f2 == feature1) {
                    feature2Iterator.remove();
                } else if (f2.getAc() != null && f2.getAc().equals(feature1.getAc())) {
                    feature2Iterator.remove();
                }
            }

            addInfoMessage("Feature unlinked", feature2.toString());
            setUnsavedChanges(true);
            refreshParticipants();
        }
    }

    public void selectLinkedFeature(FeatureWrapper wrapper, IntactModelledFeature linked) {
        wrapper.setSelectedLinkedFeature(linked);
    }

    public IntactComplex getComplex() {
        return complex;
    }

    public void setComplex(IntactComplex complex) {
        this.complex = complex;
        if (complex != null) {
            this.ac = complex.getAc();
            initialiseDefaultProperties(complex);
        } else {
            this.ac = null;
        }
    }

    private void refreshName() {
        this.name = this.complex.getShortName();
        if (this.complex.getRecommendedName() != null) {
            this.name = this.complex.getRecommendedName();
        } else if (this.complex.getSystematicName() != null) {
            this.name = this.complex.getSystematicName();
        } else if (!this.complex.getAliases().isEmpty()) {
            this.name = this.complex.getAliases().iterator().next().getName();
        }

        this.systematicName = this.complex.getSystematicName();
        this.recommendedName = this.complex.getRecommendedName();
    }

    private void refreshInfoMessages() {
        this.toBeReviewed = this.complex.getToBeReviewedComment();
        this.onHold = this.complex.getOnHoldComment();
        this.correctionComment = this.complex.getCorrectionComment();
        Annotation remark = AnnotationUtils.collectFirstAnnotationWithTopic(this.complex.getAnnotations(), null,
                "remark-internal");
        this.internalRemark = remark != null ? remark.getValue() : null;
        Annotation caution = AnnotationUtils.collectFirstAnnotationWithTopic(this.complex.getAnnotations(),
                Annotation.CAUTION_MI, Annotation.CAUTION);
        this.cautionMessage = caution != null ? caution.getValue() : null;
        Annotation desc = AnnotationUtils.collectFirstAnnotationWithTopic(this.complex.getAnnotations(), null,
                "curated-complex");
        this.description = desc != null ? desc.getValue() : null;
        this.complexProperties = this.complex.getPhysicalProperties();
        this.obsoleteVersion = "";
    }

    public String getComplexProperties() {
        return complexProperties;
    }

    // Confidence
    ///////////////////////////////////////////////

    public void setComplexProperties(String complexProperties) {
        this.complex.setPhysicalProperties(complexProperties);
        this.complexProperties = complexProperties;
    }

    public LinkedList<ParticipantWrapper> getParticipants() {
        return participantWrappers;
    }

    public void newConfidence(ActionEvent evet) {
        if (this.newConfidenceType != null && this.newConfidenceValue != null) {
            ComplexConfidence confidence = new ComplexConfidence(this.newConfidenceType, this.newConfidenceValue);
            complex.getModelledConfidences().add(confidence);
            doSave(false);

            this.newConfidenceValue = null;
            this.newConfidenceType = null;
        } else {
            addErrorMessage("Cannot add new confidence as it does not have any type/value",
                    "Missing confidence type/value");
        }
    }

    public void newParameter(ActionEvent evt) {
        if (this.newParameterType != null && this.newParameterFactor != null && this.newParameterBase != null
                && this.newParameterExponent != null) {
            ComplexParameter param = new ComplexParameter(this.newParameterType,
                    new ParameterValue(new BigDecimal(this.newParameterFactor), this.newParameterBase.shortValue(),
                            this.newParameterExponent.shortValue()));
            if (this.newParameterUncertainty != null) {
                param.setUncertainty(new BigDecimal(this.newParameterUncertainty));
            }
            param.setUnit(this.newParameterUnit);
            complex.getModelledParameters().add(param);
            doSave(false);

            this.newParameterBase = null;
            this.newParameterFactor = null;
            this.newParameterType = null;
            this.newParameterUncertainty = null;
            this.newParameterUnit = null;
            this.newParameterExponent = null;
        } else {
            addErrorMessage("Cannot add new parameter as it does not have any type/value",
                    "Missing parameter type/value");
        }
    }

    public boolean isParticipantDisabled() {
        return isParticipantDisabled;
    }

    public void setParticipantDisabled(boolean participantDisabled) {
        isParticipantDisabled = participantDisabled;
    }

    public boolean isParameterDisabled() {
        return isParameterDisabled;
    }

    public void setParameterDisabled(boolean parameterDisabled) {
        isParameterDisabled = parameterDisabled;
    }

    public boolean isConfidenceDisabled() {
        return isConfidenceDisabled;
    }

    public void setConfidenceDisabled(boolean confidenceDisabled) {
        isConfidenceDisabled = confidenceDisabled;
    }

    public boolean isLifeCycleDisabled() {
        return isLifeCycleDisabled;
    }

    public void setLifeCycleDisabled(boolean advancedDisabled) {
        isLifeCycleDisabled = advancedDisabled;
    }

    public void onTabChanged(TabChangeEvent e) {

        // the xref tab is active
        super.onTabChanged(e);

        // all the tabs selectOneMenu are disabled, we can process the tabs specific to interaction
        if (isAliasDisabled() && isXrefDisabled() && isAnnotationTopicDisabled()) {
            if (e.getTab().getId().equals("participantsTab")) {
                isParticipantDisabled = false;
                isParameterDisabled = true;
                isConfidenceDisabled = true;
                isLifeCycleDisabled = true;
            } else if (e.getTab().getId().equals("parametersTab")) {
                isParticipantDisabled = true;
                isParameterDisabled = false;
                isConfidenceDisabled = true;
                isLifeCycleDisabled = true;
            } else if (e.getTab().getId().equals("confidencesTab")) {
                isParticipantDisabled = true;
                isParameterDisabled = true;
                isConfidenceDisabled = false;
                isLifeCycleDisabled = true;
            } else {
                isParticipantDisabled = true;
                isParameterDisabled = true;
                isConfidenceDisabled = true;
                isLifeCycleDisabled = false;
            }
        } else {
            isParticipantDisabled = true;
            isParameterDisabled = true;
            isConfidenceDisabled = true;
            isLifeCycleDisabled = true;
        }
    }

    @Override
    protected void addNewXref(AbstractIntactXref newRef) {
        if (XrefUtils.isXrefAnIdentifier(newRef)
                || XrefUtils.doesXrefHaveQualifier(newRef, null, "intact-secondary")) {
            this.complex.getIdentifiers().add(newRef);
        } else {
            this.complex.getXrefs().add(newRef);
        }
        this.newXrefPubmed = null;
        this.newXrefEvidenceCode = null;
    }

    @Override
    protected InteractorXref newXref(CvTerm db, String id, String secondaryId, String version, CvTerm qualifier) {
        if (CvTermUtils.isCvTerm(db, Xref.GO_MI, Xref.GO)) {
            ComplexGOXref goRef = new ComplexGOXref(id, version, qualifier);
            goRef.setSecondaryId(secondaryId);
            goRef.setPubmed(this.newXrefPubmed);
            goRef.setEvidenceType(this.newXrefEvidenceCode);
            goRef.setDatabase(getCvService().findCvObject(IntactUtils.DATABASE_OBJCLASS, Xref.GO_MI));
            return goRef;
        } else {
            InteractorXref ref = new InteractorXref(db, id, version, qualifier);
            ref.setSecondaryId(secondaryId);

            if (this.newXrefPubmed != null || this.newXrefEvidenceCode != null) {
                addWarningMessage("Ignored pubmed id and evidence code as they are only added to go references",
                        "Ignored pubmed id and evidence code");
            }
            return ref;
        }
    }

    @Override
    public InteractorXref newXref(String db, String dbMI, String id, String version, String qualifier,
            String qualifierMI) {
        return new InteractorXref(
                getCvService().findCvObject(IntactUtils.DATABASE_OBJCLASS, dbMI != null ? dbMI : db), id, version,
                getCvService().findCvObject(IntactUtils.QUALIFIER_OBJCLASS,
                        qualifierMI != null ? qualifierMI : qualifier));
    }

    @Override
    protected void addNewAnnotation(AbstractIntactAnnotation newAnnot) {
        this.complex.getAnnotations().add(newAnnot);
    }

    @Override
    public InteractorAnnotation newAnnotation(CvTerm annotation, String text) {
        return new InteractorAnnotation(annotation, text);
    }

    @Override
    public InteractorAnnotation newAnnotation(String topic, String topicMI, String text) {
        return new InteractorAnnotation(
                getCvService().findCvObject(IntactUtils.TOPIC_OBJCLASS, topicMI != null ? topicMI : topic), text);
    }

    @Override
    public void removeAnnotation(Annotation annotation) {
        this.complex.getAnnotations().remove(annotation);
    }

    @Override
    public InteractorAlias newAlias(String alias, String aliasMI, String name) {
        return new InteractorAlias(
                getCvService().findCvObject(IntactUtils.ALIAS_TYPE_OBJCLASS, aliasMI != null ? aliasMI : alias),
                name);
    }

    @Override
    public void removeAlias(Alias alias) {
        this.complex.getAliases().remove(alias);
    }

    @Override
    public Collection<String> collectParentAcsOfCurrentAnnotatedObject() {
        return new ArrayList<String>();
    }

    @Override
    public Class<? extends IntactPrimaryObject> getAnnotatedObjectClass() {
        return IntactComplex.class;
    }

    @Override
    public List<Annotation> collectAnnotations() {
        List<Annotation> annotations = new ArrayList<Annotation>(complex.getAnnotations());
        Collections.sort(annotations, new AuditableComparator());
        // annotations are always initialised
        return annotations;
    }

    @Override
    protected void addNewAlias(AbstractIntactAlias newAlias) {
        this.complex.getAliases().add(newAlias);
    }

    @Override
    public InteractorAlias newAlias(CvTerm aliasType, String name) {
        return new InteractorAlias(aliasType, name);
    }

    @Override
    public List<Alias> collectAliases() {
        List<Alias> aliases = new ArrayList<Alias>(complex.getAliases());
        Collections.sort(aliases, new AuditableComparator());
        // annotations are always initialised
        return aliases;
    }

    public boolean isAliasNotEditable(Alias alias) {
        if (AliasUtils.doesAliasHaveType(alias, Alias.COMPLEX_RECOMMENDED_NAME_MI,
                Alias.COMPLEX_RECOMMENDED_NAME)) {
            return true;
        } else
            return AliasUtils.doesAliasHaveType(alias, Alias.COMPLEX_SYSTEMATIC_NAME_MI,
                    Alias.COMPLEX_SYSTEMATIC_NAME);
    }

    public boolean isAnnotationNotEditable(Annotation annot) {
        if (AnnotationUtils.doesAnnotationHaveTopic(annot, null, Releasable.ON_HOLD)) {
            return true;
        } else if (AnnotationUtils.doesAnnotationHaveTopic(annot, Annotation.COMPLEX_PROPERTIES_MI,
                Annotation.COMPLEX_PROPERTIES)) {
            return true;
        } else if (AnnotationUtils.doesAnnotationHaveTopic(annot, null, Releasable.TO_BE_REVIEWED)) {
            return true;
        } else if (AnnotationUtils.doesAnnotationHaveTopic(annot, null, Releasable.CORRECTION_COMMENT)) {
            return true;
        } else
            return AnnotationUtils.doesAnnotationHaveTopic(annot, null, "curated-complex");
    }

    @Override
    public boolean isXrefNotEditable(Xref ref) {
        return XrefUtils.doesXrefHaveQualifier(ref, Xref.COMPLEX_PRIMARY_MI, Xref.COMPLEX_PRIMARY);
    }

    public boolean isComplexGoRef(Xref ref) {
        return ref instanceof ComplexGOXref;
    }

    @Override
    public List<Xref> collectXrefs() {
        List<Xref> xrefs = new ArrayList<Xref>(this.complex.getDbXrefs());
        //  Collections.sort(xrefs, new AuditableComparator());
        Collections.sort(xrefs, new XrefComparator());
        return xrefs;
    }

    // This was for finding duplications

    /*public void auditList(ActionEvent evt) {
        
    HashMap<String, Integer> dupAuditHM = new HashMap<String, Integer>();
    this.setDupAuditResult(null);
    this.setDupAuditResult(new HashMap<String, Integer>());
        
    if (this.complex != null && this.complex.getDbXrefs() != null) {
        for (Xref xref : this.complex.getDbXrefs()) {
        
            if (dupAuditHM.containsKey(xref.getId())) {
                Integer increment = dupAuditHM.get(xref.getId()) + 1;
                dupAuditHM.put(xref.getId(), increment);
            } else {
                dupAuditHM.put(xref.getId(), 1);
            }
        
        
        }
        for (String identifier : dupAuditHM.keySet()) {
            if (dupAuditHM.get(identifier) > 1) {
                dupAuditResult.put(identifier,dupAuditHM.get(identifier));
            }
        }
    } else {
        addErrorMessage("No List To Audit", "No List To Audit");
    }
        
    System.out.println("HashMap is" + dupAuditResult);
    }
        
    public List<Map.Entry<String, BigDecimal>> getDupAuditResultList() {
    if(dupAuditResult!=null) {
        return new ArrayList(dupAuditResult.entrySet());
    }else{
        return null;
    }
    }*/

    @Override
    public void removeXref(Xref xref) {
        // we need to be careful as curators can add complexGoRef which can be identical to other normal refs
        if (XrefUtils.isXrefFromDatabase(xref, Xref.GO_MI, Xref.GO)) {
            Iterator<Xref> refIterator = complex.getXrefs().iterator();
            boolean hasRemoved = false;
            while (refIterator.hasNext()) {
                InteractorXref next = (InteractorXref) refIterator.next();
                if (xref == next) {
                    hasRemoved = true;
                    refIterator.remove();
                } else if (next.getAc() != null && next.getAc().equals(xref)) {
                    hasRemoved = true;
                    refIterator.remove();
                }
            }
            if (!hasRemoved) {
                refIterator = complex.getIdentifiers().iterator();
                while (refIterator.hasNext()) {
                    InteractorXref next = (InteractorXref) refIterator.next();
                    if (xref == next) {
                        hasRemoved = true;
                        refIterator.remove();
                    } else if (next.getAc() != null && next.getAc().equals(xref)) {
                        hasRemoved = true;
                        refIterator.remove();
                    }
                }
            }
        } else {
            this.complex.getXrefs().remove(xref);
            this.complex.getIdentifiers().remove(xref);
        }
    }

    public boolean isNewPublication() {
        return complex.getStatus() == LifeCycleStatus.NEW;
    }

    public boolean isAssigned() {
        return complex.getStatus() == LifeCycleStatus.ASSIGNED;
    }

    public boolean isCurationInProgress() {
        return complex.getStatus() == LifeCycleStatus.CURATION_IN_PROGRESS;
    }

    public boolean isReadyForChecking() {
        return complex.getStatus() == LifeCycleStatus.READY_FOR_CHECKING;
    }

    public boolean isReadyForRelease() {
        return complex.getStatus() == LifeCycleStatus.READY_FOR_RELEASE;
    }

    public boolean isAcceptedOnHold() {
        return complex.getStatus() == LifeCycleStatus.ACCEPTED_ON_HOLD;
    }

    public boolean isReleased() {
        return complex.getStatus() == LifeCycleStatus.RELEASED;
    }

    public void claimOwnership(ActionEvent evt) {

        try {
            getEditorService().claimOwnership(complex, getCurrentUser(), isAssigned());

            // automatically set as curation in progress if no one was assigned before
            if (isAssigned()) {
                addInfoMessage("Curation started", "Curation is now in progress");
            }

            addInfoMessage("Claimed complex ownership", "You are now the owner of this complex");
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot claim ownership: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }
    }

    public void markAsAssignedToMe(ActionEvent evt) {
        try {
            getEditorService().markAsAssignedToMe(complex, getCurrentUser());

            addInfoMessage("Ownership claimed", "The complex has been assigned to you");

            addInfoMessage("Curation started", "Curation is now in progress");

        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot assign complex: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }
    }

    public void markAsCurationInProgress(ActionEvent evt) {

        if (!userSessionController.isItMe(complex.getCurrentOwner())) {
            addErrorMessage("Cannot mark as curation in progress", "You are not the owner of this complex");
            return;
        }
        try {
            getEditorService().markAsCurationInProgress(complex, getCurrentUser());

            addInfoMessage("Curation started", "Curation is now in progress");
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot mark as curation in progress: " + e.getMessage(),
                    ExceptionUtils.getFullStackTrace(e));
        }
    }

    public void markAsReadyForChecking(ActionEvent evt) {
        if (!userSessionController.isItMe(complex.getCurrentOwner())) {
            addErrorMessage("Cannot mark as Ready for checking", "You are not the owner of this complex");
            return;
        }

        try {
            getEditorService().markAsReadyForChecking(complex, getCurrentUser(), correctionComment);

            addInfoMessage("Complex ready for checking",
                    "Assigned to reviewer: " + complex.getCurrentReviewer().getLogin());
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot mark as ready for checking: " + e.getMessage(),
                    ExceptionUtils.getFullStackTrace(e));
        }
    }

    public void revertReadyForChecking(ActionEvent evt) {
        try {
            getEditorService().revertReadyForChecking(this.complex, getCurrentUser());
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot revert ready for checking: " + e.getMessage(),
                    ExceptionUtils.getFullStackTrace(e));
        }
    }

    public void revertAccepted(ActionEvent evt) {
        try {
            getEditorService().revertAccepted(complex, getCurrentUser(), isReadyForRelease());
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot revert accepted: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }
    }

    public void removeOnHold(ActionEvent evt) {

        this.complex.removeOnHold();
    }

    public void removeToBeReviewed(ActionEvent evt) {

        this.complex.removeToBeReviewed();
    }

    public void putOnHold(ActionEvent evt) {
        try {
            getEditorService().putOnHold(complex, getCurrentUser(), onHold, isReadyForRelease(), isReleased());

            if (isReadyForRelease()) {
                addInfoMessage("On-hold added to complex",
                        "Complex won't be released until the 'on hold' is removed");
            } else if (isReleased()) {
                addInfoMessage("On-hold added to released complex",
                        "Data will be publicly visible until the next release");
            }
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot put on-hold: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }
    }

    /*    public void putObsoleteOnHold(ActionEvent evt) {
    try {
        getEditorService().putOnHold(complex, getCurrentUser(), obsoleteVersion, isReadyForRelease(), isReleased());
    } catch (IllegalTransitionException e) {
        addErrorMessage("Error updating old version, Could not mark it 'On Hold' " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
    }
        }*/

    public void readyForReleaseFromOnHold(ActionEvent evt) {
        setOnHold(null);
        try {
            getEditorService().readyForReleaseFromOnHold(complex, getCurrentUser());

        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot mark as ready for release: " + e.getMessage(),
                    ExceptionUtils.getFullStackTrace(e));
        }
    }

    public void onHoldChanged(ValueChangeEvent evt) {
        String newValue = (String) evt.getNewValue();
        if (newValue != null && newValue.length() > 0) {
            setUnsavedChanges(true);
            this.complex.onHold(newValue);
            this.onHold = newValue;
        }
    }

    public void onToBeReviewedChanged(ValueChangeEvent evt) {
        String newValue = (String) evt.getNewValue();
        if (newValue != null && newValue.length() > 0) {
            setUnsavedChanges(true);
            this.complex.onToBeReviewed(newValue);
            this.toBeReviewed = newValue;
        }
    }

    public void onCorrectionCommentChanged(ValueChangeEvent evt) {
        String newValue = (String) evt.getNewValue();
        if (newValue != null && newValue.length() > 0) {
            setUnsavedChanges(true);
            this.complex.onCorrectionComment(newValue);
            this.correctionComment = newValue;
        }
    }

    public String getRecommendedName() {
        return recommendedName;
    }

    public void setRecommendedName(String recommendedName) {
        this.recommendedName = recommendedName;
    }

    public String getSystematicName() {
        return systematicName;
    }

    public void setSystematicName(String systematicName) {
        this.systematicName = systematicName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void onRecommendedNameChanged(ValueChangeEvent evt) {
        String newValue = (String) evt.getNewValue();
        if (newValue == null || newValue.length() == 0) {
            this.complex.setRecommendedName(null);
            this.recommendedName = null;
            setUnsavedChanges(true);
        } else {
            this.complex.setRecommendedName(newValue);
            this.recommendedName = newValue;
            setUnsavedChanges(true);
        }
    }

    public void onSystematicNameChanged(ValueChangeEvent evt) {

        String newValue = (String) evt.getNewValue();
        if (newValue == null || newValue.length() == 0) {
            this.complex.setSystematicName(null);
            this.systematicName = null;
            setUnsavedChanges(true);
        } else {
            this.complex.setSystematicName(newValue);
            this.systematicName = newValue;
            setUnsavedChanges(true);
        }
    }

    public void onDescriptionChanged(ValueChangeEvent evt) {
        setUnsavedChanges(true);

        this.description = (String) evt.getNewValue();

        Annotation curatedComplex = AnnotationUtils.collectFirstAnnotationWithTopic(this.complex.getAnnotations(),
                null, "curated-complex");
        if (curatedComplex != null) {
            curatedComplex.setValue(this.description);
        } else {
            this.complex.getAnnotations().add(
                    new InteractorAnnotation(IntactUtils.createMITopic("curated-complex", null), this.description));
        }
    }

    public void onComplexPropertiesChanged(ValueChangeEvent evt) {

        String newValue = (String) evt.getNewValue();
        if (newValue == null || newValue.length() == 0) {
            this.complex.setPhysicalProperties(null);
            this.complexProperties = null;
            setUnsavedChanges(true);
        } else {
            this.complex.setPhysicalProperties(newValue);
            this.complexProperties = newValue;
            setUnsavedChanges(true);
        }
    }

    public boolean isAccepted() {
        if (complex == null || complex.getStatus() == null) {
            return false;
        }

        return complex.getStatus() == LifeCycleStatus.ACCEPTED
                || complex.getStatus() == LifeCycleStatus.ACCEPTED_ON_HOLD
                || complex.getStatus() == LifeCycleStatus.READY_FOR_RELEASE
                || complex.getStatus() == LifeCycleStatus.RELEASED;
    }

    public boolean isToBeReviewed(IntactComplex pub) {
        return pub.isToBeReviewed();
    }

    public boolean isOnHold(IntactComplex pub) {
        return pub.isOnHold();
    }

    public boolean isCorrectionComment(IntactComplex pub) {
        return pub.hasCorrectionComment();
    }

    public boolean isComplexToBeReviewed() {
        return this.complex.isToBeReviewed();
    }

    public boolean isComplexOnHold() {
        return this.complex.isOnHold();
    }

    public boolean isComplexWithCorrectionComment() {
        return this.complex.hasCorrectionComment();
    }

    public void acceptComplex(ActionEvent evt) {
        try {
            String accepted = "Accepted " + new SimpleDateFormat("yyyy-MMM-dd").format(new Date()).toUpperCase()
                    + " by " + userSessionController.getCurrentUser().getLogin().toUpperCase();

            getEditorService().accept(complex, userSessionController.getCurrentUser(), accepted);

        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot accept complex: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }
    }

    //    public void rejectComplex(ActionEvent evt) {
    //
    //        rejectComplex(toBeReviewed);
    //
    //    }

    public void rejectComplex(ActionEvent evt) {
        if (evt.getComponent().getId().equals("rejectComplex")) {
            try {
                getEditorService().reject(complex, getCurrentUser(), this.toBeReviewed);

                addInfoMessage("Complex rejected", "");
            } catch (IllegalTransitionException e) {
                addErrorMessage("Cannot reject complex: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
            }
        } else {
            String date = "Rejected " + new SimpleDateFormat("yyyy-MMM-dd").format(new Date()).toUpperCase()
                    + " by " + userSessionController.getCurrentUser().getLogin().toUpperCase();

            if (toBeReviewed == null) {
                setToBeReviewed(date + ". " + newToBeReviewed);
            } else if (newToBeReviewed != null) {
                setToBeReviewed(toBeReviewed + " " + date + ". " + newToBeReviewed);
            } else {
                setToBeReviewed(toBeReviewed);
            }

            this.newToBeReviewed = null;
            updateAnnotation(Releasable.TO_BE_REVIEWED, null, this.toBeReviewed, complex.getAnnotations());
            removeAnnotation(Releasable.ACCEPTED, null, complex.getAnnotations());

            RequestContext requestContext = RequestContext.getCurrentInstance();
            requestContext.execute("complexActionDlg.show()");

            addInfoMessage("Added review message", complex.getShortName() + ": " + toBeReviewed);
        }
    }

    public boolean isBeenRejectedBefore() {
        for (LifeCycleEvent evt : complex.getLifecycleEvents()) {
            if (LifeCycleEventType.REJECTED.equals(evt.getEvent())) {
                return true;
            }
        }

        return false;
    }

    public String getToBeReviewed() {
        return toBeReviewed != null ? toBeReviewed : "";
    }

    public void setToBeReviewed(String reason) {
        this.toBeReviewed = reason;
    }

    public void clearToBeReviewed(ActionEvent evt) {
        this.complex.removeToBeReviewed();
        toBeReviewed = null;
    }

    public boolean isAssignToMe() {
        return assignToMe;
    }

    public void setAssignToMe(boolean assignToMe) {
        this.assignToMe = assignToMe;
    }

    public boolean isNewComplex() {
        return complex.getStatus().equals(LifeCycleStatus.NEW);
    }

    public String newComplex(IntactInteractionEvidence interactionEvidence) {
        if (interactionEvidence == null || interactionEvidence.getAc() == null) {
            addErrorMessage("Cannot create biological complex", "Interaction evidence is empty or not saved");
            return null;
        }
        CvTerm type = getCvService().findCvObject(IntactUtils.INTERACTOR_TYPE_OBJCLASS, Complex.COMPLEX_MI);
        User user = getCurrentUser();
        // the interaction evidence is loaded with jami
        if (interactionEvidence != null) {
            try {
                IntactComplex complex = getComplexEditorService().cloneInteractionEvidence(interactionEvidence,
                        new ComplexCloner());
                setComplex(complex);

                // Ask to the database for the next available complex accession.
                // It is initialised with version 1. Call this method only for brand new complexes
                String acValue = getComplexEditorService().retrieveNextComplexAc();
                addXref(Xref.COMPLEX_PORTAL, Xref.COMPLEX_PORTAL_MI, acValue, "1", Xref.COMPLEX_PRIMARY,
                        Xref.COMPLEX_PRIMARY_MI, complex.getXrefs());

            } catch (SynchronizerException e) {
                addErrorMessage("Cannot clone the interaction evidence as a complex: " + e.getMessage(),
                        ExceptionUtils.getFullStackTrace(e));
            } catch (FinderException e) {
                addErrorMessage("Cannot clone the interaction evidence as a complex: " + e.getMessage(),
                        ExceptionUtils.getFullStackTrace(e));
            } catch (PersisterException e) {
                addErrorMessage("Cannot clone the interaction evidence as a complex: " + e.getMessage(),
                        ExceptionUtils.getFullStackTrace(e));
            }
        }

        this.complex.setInteractorType(type);

        try {
            getLifecycleManager().getStartStatus().create(this.complex, "Created in Editor", user);

            if (assignToMe) {
                getLifecycleManager().getNewStatus().claimOwnership(this.complex, user);
                getLifecycleManager().getAssignedStatus().startCuration(this.complex, user);
            }
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot create new complex: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }

        return "/curate/complex?faces-redirect=true";
    }

    public String newComplex() {

        CvTerm type = getCvService().findCvObject(IntactUtils.INTERACTOR_TYPE_OBJCLASS, Complex.COMPLEX_MI);
        User user = getCurrentUser();

        setComplex(new IntactComplex("name to specify"));
        UserSessionController userSessionController = ApplicationContextProvider.getBean("userSessionController");
        this.complex.setSource(userSessionController.getUserInstitution());
        this.complex.setCreatedDate(new Date());
        this.complex.setUpdatedDate(this.complex.getCreatedDate());
        this.complex.setCreator(user.getLogin());
        this.complex.setUpdator(user.getLogin());
        this.complex.setInteractorType(type);

        // Ask to the database for the next available complex accession.
        // It is initialised with version 1. Call this method only for brand new complexes
        String acValue = getComplexEditorService().retrieveNextComplexAc();
        addXref(Xref.COMPLEX_PORTAL, Xref.COMPLEX_PORTAL_MI, acValue, "1", Xref.COMPLEX_PRIMARY,
                Xref.COMPLEX_PRIMARY_MI, complex.getXrefs());

        try {
            getLifecycleManager().getStartStatus().create(this.complex, "Created in Editor", user);

            if (assignToMe) {
                getLifecycleManager().getNewStatus().claimOwnership(this.complex, user);
                getLifecycleManager().getAssignedStatus().startCuration(this.complex, user);
            }
        } catch (IllegalTransitionException e) {
            addErrorMessage("Cannot create new complex: " + e.getMessage(), ExceptionUtils.getFullStackTrace(e));
        }

        return "/curate/complex?faces-redirect=true";
    }

    public String createNewVersion() {
        return processVersioningAndSave();
    }

    /*
     * Create New Version of the current complex
     * # Annotate current complex as obsolete.
     * # Move the current complex to "On Hold" status.
     * # Clone the current complex for new version of complex.
     * # Increase the Version of complex-primary xref in new version created above.
     * # Add secondary-ac xref with old version complex ac to the new versioned complex.
     * */
    private String processVersioningAndSave() {
        boolean previousVersionSaved = false;
        String oldVersionAc = null;
        Xref complex_primaryXref = null;
        try {

            /* Assign New Version to the complex-primary xref to the cloned version and save clone - Start */
            if (getAnnotatedObject() != null) {

                /* Extract Complex Primary Xref - Start */
                Collection<Xref> currentComplexXrefs = this.complex.getXrefs();
                for (Xref xref : currentComplexXrefs) {
                    if (XrefUtils.isXrefFromDatabase(xref, Xref.COMPLEX_PORTAL_MI, Xref.COMPLEX_PORTAL) && XrefUtils
                            .doesXrefHaveQualifier(xref, Xref.COMPLEX_PRIMARY_MI, Xref.COMPLEX_PRIMARY)) {
                        complex_primaryXref = xref;
                        break;
                    }

                }
                /* Extract Complex Primary Xref - End */

                /* Mark previous version as obsolete - Start */
                Collection<Annotation> annots = this.complex.getAnnotations();
                Annotation annotation = newAnnotation("obsolete complex", null, this.obsoleteVersion);
                annots.add(annotation);
                /* Mark previous version as obsolete - End */

                // Collects intact secondary acs from previous versions of the same complex and previous primary
                Collection<Xref> oldVersionAcs = XrefUtils.collectAllXrefsHavingDatabaseAndQualifier(
                        this.complex.getIdentifiers(), "MI:0469", "intact", Xref.SECONDARY_MI, Xref.SECONDARY);
                oldVersionAc = this.complex.getAc();

                /* Put the previous version on hold - Start */
                getEditorService().putOnHold(this.complex, getCurrentUser(), "Newer Version Created",
                        isReadyForRelease(), isReleased());
                /* Put the previous version on hold  - End */

                doSave(false);// save previous version
                previousVersionSaved = true;

                IntactComplex clone = cloneAnnotatedObject(complex, newClonerInstance());
                if (clone == null)
                    return null;

                setAnnotatedObject(clone);
                Collection<Xref> clonedComplexXrefs = clone.getXrefs();

                /* We have to add 'complex_primaryXref' here with updated version because it would be removed while cloning */
                assert complex_primaryXref != null; //It is a requirement because the new version is based in a previous complex
                String complexVersion = complex_primaryXref.getVersion();
                int versionNumber = Integer.parseInt(complexVersion);
                versionNumber++;
                String newVersionNumber = "" + versionNumber;

                //Internally removes the xref created by the cloner and replaces it with the new version
                addXref(Xref.COMPLEX_PORTAL, Xref.COMPLEX_PORTAL_MI, complex_primaryXref.getId(), newVersionNumber,
                        Xref.COMPLEX_PRIMARY, Xref.COMPLEX_PRIMARY_MI, clonedComplexXrefs);

                //add intact secondary acs for storing previous version accessions and the current primary
                //ToDo Have hard coded values in some constants
                for (Xref versionAc : oldVersionAcs) {
                    addXref(versionAc, clonedComplexXrefs);
                }
                addXref("intact", "MI:0469", oldVersionAc, null, Xref.SECONDARY, Xref.SECONDARY_MI,
                        clonedComplexXrefs);

                //removes the obsolete complex annotation
                removeAnnotation(annotation);

                setUnsavedChanges(true);
                doSave(); //We decided to save because it is part of the same unit (together with turing the previous one to read only)
                /* Assign New Version to the complex-primary xref to the cloned version and save clone - End */

                return getCurateController().edit(clone);// navigate to new complex
            }
        } catch (Exception e) {
            String previousVersionAnnotated = null;
            if (previousVersionSaved) {
                previousVersionAnnotated = "Previous Version(" + oldVersionAc + ") is marked as old version"
                        + " , contact intact developers 'intact-help@ebi.ac.uk' for revert";
            }
            addErrorMessage("Could not create new version ", previousVersionAnnotated);
            e.printStackTrace();
        }
        return null;

    }

    @Override
    public IntactDbSynchronizer getDbSynchronizer() {
        return getEditorService().getIntactDao().getSynchronizerContext().getComplexSynchronizer();
    }

    @Override
    public String getObjectName() {
        return getName();
    }

    /**
     * No transactional as it should always be initialised when loaded recommended name and systematic name when loading the page
     *
     * @return
     */
    public int getAliasesSize() {
        if (this.complex == null) {
            return 0;
        } else {
            return this.complex.getAliases().size();
        }
    }

    /**
     * No transactional as it should always be initialised when loaded recommended name and systematic name when loading the page
     *
     * @return
     */
    public int getAnnotationsSize() {
        if (this.complex == null) {
            return 0;
        } else {
            return this.complex.getAnnotations().size();
        }
    }

    public int getConfidencesSize() {
        if (this.complex == null) {
            return 0;
        } else {
            return this.complex.getModelledConfidences().size();
        }
    }

    public int getParametersSize() {
        if (this.complex == null) {
            return 0;
        } else {
            return this.complex.getModelledParameters().size();
        }
    }

    public int getXrefsSize() {
        if (this.complex == null) {
            return 0;
        } else {
            return this.complex.getDbXrefs().size();
        }
    }

    public List<Confidence> collectConfidences() {
        List<Confidence> confidences = new ArrayList<Confidence>(this.complex.getModelledConfidences());
        Collections.sort(confidences, new AuditableComparator());
        return confidences;
    }

    public List<Parameter> collectParameters() {
        List<Parameter> params = new ArrayList<Parameter>(this.complex.getModelledParameters());
        Collections.sort(params, new AuditableComparator());
        return params;
    }

    public void removeConfidence(ModelledConfidence conf) {
        this.complex.getModelledConfidences().remove(conf);
    }

    public void removeParameter(ModelledParameter param) {
        this.complex.getModelledParameters().remove(param);
    }

    public Collection<LifeCycleEvent> collectLifecycleEvents() {
        return new ArrayList<LifeCycleEvent>(complex.getLifecycleEvents());
    }

    public LifeCycleManager getLifecycleManager() {
        if (lifecycleManager == null) {
            lifecycleManager = ApplicationContextProvider.getBean("jamiLifeCycleManager");
        }
        return lifecycleManager;
    }

    public void addCorrectionComment(ActionEvent evt) {
        addInfoMessage("Added correction comment", correctionComment);
        this.complex.onCorrectionComment(correctionComment);
    }

    public void removeCorrectionComment(ActionEvent evt) {
        addInfoMessage("Removed correction comment", correctionComment);
        this.complex.removeCorrectionComment();
    }

    public void reloadSingleParticipant(IntactModelledParticipant f) {
        Iterator<ModelledParticipant> evIterator = complex.getParticipants().iterator();
        boolean add = true;
        while (evIterator.hasNext()) {
            IntactModelledParticipant intactEv = (IntactModelledParticipant) evIterator.next();
            if (intactEv.getAc() == null && f == intactEv) {
                add = false;
            } else if (intactEv.getAc() != null && intactEv.getAc().equals(f.getAc())) {
                evIterator.remove();
            }
        }

        if (add) {
            complex.getParticipants().add(f);
        }

        refreshParticipants();
    }

    public void removeParticipant(IntactModelledParticipant f) {
        Iterator<ModelledParticipant> evIterator = complex.getParticipants().iterator();
        while (evIterator.hasNext()) {
            IntactModelledParticipant intactEv = (IntactModelledParticipant) evIterator.next();
            if (intactEv.getAc() == null && f == intactEv) {
                evIterator.remove();
            } else if (intactEv.getAc() != null && intactEv.getAc().equals(f.getAc())) {
                evIterator.remove();
            }
        }

        refreshParticipants();
    }

    public boolean isBackToCurationButtonRendered() {
        return isButtonRendered(LifeCycleEventType.READY_FOR_CHECKING);
    }

    public boolean isBackToCheckingButtonRendered() {
        boolean render = isButtonRendered(LifeCycleEventType.READY_FOR_RELEASE);

        if (!render) {
            render = isButtonRendered(LifeCycleEventType.ACCEPTED);
        }

        return render;
    }

    private boolean isButtonRendered(LifeCycleEventType eventType) {
        LifeCycleEvent event = ReleasableUtils.getLastEventOfType(complex, eventType);

        if (event == null) {
            return false;
        }

        DateTime eventTime = new DateTime(event.getWhen());

        return new DateTime().isBefore(eventTime.plusMinutes(getEditorConfig().getRevertDecisionTime()));
    }

    public ComplexEditorService getComplexEditorService() {
        if (this.complexEditorService == null) {
            this.complexEditorService = ApplicationContextProvider.getBean("complexEditorService");
        }
        return complexEditorService;
    }

    public BioSourceService getBioSourceService() {
        if (this.bioSourceService == null) {
            this.bioSourceService = ApplicationContextProvider.getBean("bioSourceService");
        }
        return bioSourceService;
    }

    public CvTerm getNewXrefEvidenceCode() {
        return newXrefEvidenceCode;
    }

    public void setNewXrefEvidenceCode(CvTerm newXrefEvidenceCode) {
        this.newXrefEvidenceCode = newXrefEvidenceCode;
    }

    public String getNewXrefPubmed() {
        return newXrefPubmed;
    }

    public void setNewXrefPubmed(String newXrefPubmed) {
        this.newXrefPubmed = newXrefPubmed;
    }

    public String getNewConfidenceValue() {
        return newConfidenceValue;
    }

    public void setNewConfidenceValue(String newConfidenceValue) {
        this.newConfidenceValue = newConfidenceValue;
    }

    public CvTerm getNewConfidenceType() {
        return newConfidenceType;
    }

    public void setNewConfidenceType(CvTerm newConfidenceType) {
        this.newConfidenceType = newConfidenceType;
    }

    public Double getNewParameterUncertainty() {
        return newParameterUncertainty;
    }

    public void setNewParameterUncertainty(Double newParameterUncertainty) {
        this.newParameterUncertainty = newParameterUncertainty;
    }

    public Integer getNewParameterExponent() {
        return newParameterExponent;
    }

    public void setNewParameterExponent(Integer newParameterExponent) {
        this.newParameterExponent = newParameterExponent;
    }

    public Integer getNewParameterBase() {
        return newParameterBase;
    }

    public void setNewParameterBase(Integer newParameterBase) {
        this.newParameterBase = newParameterBase;
    }

    public CvTerm getNewParameterUnit() {
        return newParameterUnit;
    }

    public void setNewParameterUnit(CvTerm newParameterUnit) {
        this.newParameterUnit = newParameterUnit;
    }

    public Double getNewParameterFactor() {
        return newParameterFactor;
    }

    public void setNewParameterFactor(Double newParameterFactor) {
        this.newParameterFactor = newParameterFactor;
    }

    public CvTerm getNewParameterType() {
        return newParameterType;
    }

    public void setNewParameterType(CvTerm newParameterType) {
        this.newParameterType = newParameterType;
    }

    public String getShortName() {
        return complex != null && !"name to specify".equals(complex.getShortName()) ? complex.getShortName() : null;
    }

    public void setShortName(String name) {
        this.complex.setShortName(name);
    }

    public String getNewToBeReviewed() {
        return newToBeReviewed;
    }

    public void setNewToBeReviewed(String newToBeReviewed) {
        this.newToBeReviewed = newToBeReviewed;
    }

    public HashMap<String, Integer> getDupAuditResult() {
        return dupAuditResult;
    }

    public void setDupAuditResult(HashMap<String, Integer> dupAuditResult) {
        this.dupAuditResult = dupAuditResult;
    }

    public boolean isComplexReadOnly() {
        return isComplexReadOnly;
    }

    public void setComplexReadOnly(boolean complexReadOnly) {
        isComplexReadOnly = complexReadOnly;
    }

    public String getObsoleteVersion() {
        return obsoleteVersion != null ? obsoleteVersion : "";
    }

    public void setObsoleteVersion(String reason) {
        this.obsoleteVersion = reason;
    }
}