/*
 * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.eis.mappings;

import java.util.List;

import org.eclipse.persistence.eis.EISCollectionChangeRecord;
import org.eclipse.persistence.eis.EISOrderedCollectionChangeRecord;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.ChangeRecord;
import org.eclipse.persistence.internal.sessions.MergeManager;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.mappings.DatabaseMapping;

/**
 * INTERNAL:
 * Helper class to consolidate all the heinous comparing
 * and merging code for the EIS one to many mappings.
 */
public class EISOneToManyMappingHelper {

    /** The mapping that needs help comparing and merging. */
    private EISOneToManyMapping mapping;
    private static Object XXX = new Object();// object used to marked cleared out slots when comparing

    /**
     * Constructor.
     */
    public EISOneToManyMappingHelper(EISOneToManyMapping mapping) {
        super();
        this.mapping = mapping;
    }

    /**
     * Convenience method.
     */
    private Object buildAddedElementFromChangeSet(Object changeSet, MergeManager mergeManager, AbstractSession targetSession) {
        return this.getMapping().buildAddedElementFromChangeSet(changeSet, mergeManager, targetSession);
    }

    /**
     * Convenience method.
     */
    private Object buildChangeSet(Object element, ObjectChangeSet owner, AbstractSession session) {
        return this.getMapping().buildChangeSet(element, owner, session);
    }

    /**
     * Convenience method.
     */
    private Object buildElementFromElement(Object element, MergeManager mergeManager, AbstractSession targetSession) {
        return this.getMapping().buildElementFromElement(element, mergeManager, targetSession);
    }

    /**
     * Convenience method.
     */
    private Object buildRemovedElementFromChangeSet(Object changeSet, MergeManager mergeManager, AbstractSession targetSession) {
        return this.getMapping().buildRemovedElementFromChangeSet(changeSet, mergeManager, targetSession);
    }

    /**
     * Compare the attributes. Return true if they are alike.
     * Assume the passed-in attributes are non-null.
     */
    private boolean compareAttributeValues(Object collection1, Object collection2, AbstractSession session) {
        ContainerPolicy cp = this.getContainerPolicy();

        if (cp.sizeFor(collection1) != cp.sizeFor(collection2)) {
            return false;
        }

        // if they are both empty, go no further...
        if (cp.sizeFor(collection1) == 0) {
            return true;
        }

        if (cp.hasOrder()) {
            return this.compareAttributeValuesWithOrder(collection1, collection2, session);
        } else {
            return this.compareAttributeValuesWithoutOrder(collection1, collection2, session);
        }
    }

    /**
     * Build and return the change record that results
     * from comparing the two collection attributes.
     * The order of the elements is significant.
     */
    private ChangeRecord compareAttributeValuesForChangeWithOrder(Object cloneCollection, Object backupCollection, ObjectChangeSet owner, AbstractSession session) {
        ContainerPolicy cp = this.getContainerPolicy();

        List cloneVector = cp.vectorFor(cloneCollection, session);// convert it to a Vector so we can preserve the order and use indexes
        List backupVector = cp.vectorFor(backupCollection, session);// "clone" it so we can clear out the slots

        EISOrderedCollectionChangeRecord changeRecord = new EISOrderedCollectionChangeRecord(owner, this.getAttributeName(), this.getDatabaseMapping());

        for (int i = 0; i < cloneVector.size(); i++) {
            Object cloneElement = cloneVector.get(i);
            boolean found = false;
            for (int j = 0; j < backupVector.size(); j++) {
                if (this.compareElementsForChange(cloneElement, backupVector.get(j), session)) {
                    // the clone element was found in the backup collection
                    found = true;
                    backupVector.set(j, XXX);// clear out the matching backup element

                    changeRecord.addMovedChangeSet(this.buildChangeSet(cloneElement, owner, session), j, i);
                    break;// matching backup element found - skip the rest of them
                }
            }
            if (!found) {
                // the clone element was not found, so it must have been added
                changeRecord.addAddedChangeSet(this.buildChangeSet(cloneElement, owner, session), i);
            }
        }

        for (int i = 0; i < backupVector.size(); i++) {
            Object backupElement = backupVector.get(i);
            if (backupElement != XXX) {
                // the backup element was not in the clone collection, so it must have been removed
                changeRecord.addRemovedChangeSet(this.buildChangeSet(backupElement, owner, session), i);
            }
        }

        if (changeRecord.hasChanges()) {
            return changeRecord;
        } else {
            return null;
        }
    }

    /**
     * Build and return the change record that results
     * from comparing the two collection attributes.
     * Ignore the order of the elements.
     */
    private ChangeRecord compareAttributeValuesForChangeWithoutOrder(Object cloneCollection, Object backupCollection, ObjectChangeSet owner, AbstractSession session) {
        ContainerPolicy cp = this.getContainerPolicy();

        List backupVector = cp.vectorFor(backupCollection, session);// "clone" it so we can clear out the slots

        EISCollectionChangeRecord changeRecord = new EISCollectionChangeRecord(owner, this.getAttributeName(), this.getDatabaseMapping());
        for (Object cloneIter = cp.iteratorFor(cloneCollection); cp.hasNext(cloneIter);) {
            Object cloneElement = cp.next(cloneIter, session);

            boolean found = false;
            for (int i = 0; i < backupVector.size(); i++) {
                if (this.compareElementsForChange(cloneElement, backupVector.get(i), session)) {
                    // the clone element was found in the backup collection
                    found = true;
                    backupVector.set(i, XXX);// clear out the matching backup element
                    if (this.mapKeyHasChanged(cloneElement, session)) {
                        changeRecord.addChangedMapKeyChangeSet(this.buildChangeSet(cloneElement, owner, session));
                    }
                    break;// matching backup element found - skip the rest of them
                }
            }
            if (!found) {
                // the clone element was not found, so it must have been added
                changeRecord.addAddedChangeSet(this.buildChangeSet(cloneElement, owner, session));
            }
        }

        for (int i = 0; i < backupVector.size(); i++) {
            Object backupElement = backupVector.get(i);
            if (backupElement != XXX) {
                // the backup element was not in the clone collection, so it must have been removed
                changeRecord.addRemovedChangeSet(this.buildChangeSet(backupElement, owner, session));
            }
        }

        if (changeRecord.hasChanges()) {
            return changeRecord;
        } else {
            return null;
        }
    }

    /**
     * Compare the attributes. Return true if they are alike.
     * The order of the elements is significant.
     */
    private boolean compareAttributeValuesWithOrder(Object collection1, Object collection2, AbstractSession session) {
        ContainerPolicy cp = this.getContainerPolicy();

        Object iter1 = cp.iteratorFor(collection1);
        Object iter2 = cp.iteratorFor(collection2);

        while (cp.hasNext(iter1)) {
            if (!this.compareElements(cp.next(iter1, session), cp.next(iter2, session), session)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Compare the attributes. Return true if they are alike.
     * Ignore the order of the elements.
     */
    private boolean compareAttributeValuesWithoutOrder(Object collection1, Object collection2, AbstractSession session) {
        ContainerPolicy cp = this.getContainerPolicy();

        List vector2 = cp.vectorFor(collection2, session);// "clone" it so we can clear out the slots

        for (Object iter1 = cp.iteratorFor(collection1); cp.hasNext(iter1);) {
            Object element1 = cp.next(iter1, session);

            boolean found = false;
            for (int i = 0; i < vector2.size(); i++) {
                if (this.compareElements(element1, vector2.get(i), session)) {
                    found = true;
                    vector2.set(i, XXX);// clear out the matching element
                    break;// matching element found - skip the rest of them
                }
            }
            if (!found) {
                return false;
            }
        }

        // look for elements that were not in collection1
        for (Object value : vector2) {
            if (value != XXX) {
                return false;
            }
        }
        return true;
    }

    /**
     * Convenience method.
     * Check for null values before delegating to the mapping.
     */
    private boolean compareElements(Object element1, Object element2, AbstractSession session) {
        if ((element1 == null) && (element2 == null)) {
            return true;
        }
        if ((element1 == null) || (element2 == null)) {
            return false;
        }
        if (element2 == XXX) {// if element2 was marked as cleared out, it is not a match
            return false;
        }
        return this.getMapping().compareElements(element1, element2, session);
    }

    /**
     * Convenience method.
     * Check for null values before delegating to the mapping.
     */
    private boolean compareElementsForChange(Object element1, Object element2, AbstractSession session) {
        if ((element1 == null) && (element2 == null)) {
            return true;
        }
        if ((element1 == null) || (element2 == null)) {
            return false;
        }
        if (element2 == XXX) {// if element2 was marked as cleared out, it is not a match
            return false;
        }
        return this.getMapping().compareElementsForChange(element1, element2, session);
    }

    /**
     * INTERNAL:
     * Build and return the change record that results
     * from comparing the two collection attributes.
     */
    public ChangeRecord compareForChange(Object clone, Object backup, ObjectChangeSet owner, AbstractSession session) {
        ContainerPolicy cp = this.getContainerPolicy();
        Object cloneCollection = this.getRealCollectionAttributeValueFromObject(clone, session);

        Object backupCollection = null;
        if (owner.isNew()) {
            backupCollection = cp.containerInstance(1);
        } else {
            backupCollection = this.getRealCollectionAttributeValueFromObject(backup, session);
        }

        if (cp.hasOrder()) {
            return this.compareAttributeValuesForChangeWithOrder(cloneCollection, backupCollection, owner, session);
        } else {
            return this.compareAttributeValuesForChangeWithoutOrder(cloneCollection, backupCollection, owner, session);
        }
    }

    /**
     * INTERNAL:
     * Compare the attributes belonging to this mapping for the objects.
     */
    public boolean compareObjects(Object object1, Object object2, AbstractSession session) {
        return this.compareAttributeValues(this.getRealCollectionAttributeValueFromObject(object1, session), this.getRealCollectionAttributeValueFromObject(object2, session), session);
    }

    /**
     * Convenience method.
     */
    private String getAttributeName() {
        return this.getMapping().getAttributeName();
    }

    /**
     * Convenience method.
     */
    private ContainerPolicy getContainerPolicy() {
        return this.getMapping().getContainerPolicy();
    }

    /**
     * INTERNAL:
     * Return the mapping, casted a bit more generally.
     */
    public DatabaseMapping getDatabaseMapping() {
        return this.getMapping();
    }

    /**
     * INTERNAL:
     * Return the mapping.
     */
    public EISOneToManyMapping getMapping() {
        return mapping;
    }

    /**
     * Convenience method.
     */
    private Object getRealCollectionAttributeValueFromObject(Object object, AbstractSession session) {
        return this.getMapping().getRealCollectionAttributeValueFromObject(object, session);
    }

    /**
     * Convenience method.
     */
    private boolean mapKeyHasChanged(Object element, AbstractSession session) {
        return this.getMapping().mapKeyHasChanged(element, session);
    }

    /**
     * INTERNAL:
     * Merge changes from the source to the target object.
     */
    public void mergeChangesIntoObject(Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession) {
        if (this.getContainerPolicy().hasOrder()) {
            this.mergeChangesIntoObjectWithOrder(target, changeRecord, source, mergeManager, targetSession);
        } else {
            this.mergeChangesIntoObjectWithoutOrder(target, changeRecord, source, mergeManager, targetSession);
        }
    }

    /**
     * Merge changes from the source to the target object.
     * Simply replace the entire target collection.
     */
    private void mergeChangesIntoObjectWithOrder(Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession) {
        ContainerPolicy cp = this.getContainerPolicy();
        AbstractSession session = mergeManager.getSession();

        List changes = ((EISOrderedCollectionChangeRecord)changeRecord).getNewCollection();
        Object targetCollection = cp.containerInstance(changes.size());

        for (Object changed : changes) {
            Object targetElement = buildAddedElementFromChangeSet(changed, mergeManager, targetSession);
            cp.addInto(targetElement, targetCollection, session);
        }

        // reset the attribute to allow for set method to re-morph changes if the collection is not being stored directly
        this.setRealAttributeValueInObject(target, targetCollection);
    }

    /**
     * Merge changes from the source to the target object.
     * Make the necessary removals and adds and map key modifications.
     */
    private void mergeChangesIntoObjectWithoutOrder(Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession) {
        EISCollectionChangeRecord sdkChangeRecord = (EISCollectionChangeRecord)changeRecord;
        ContainerPolicy cp = this.getContainerPolicy();
        AbstractSession session = mergeManager.getSession();

        Object targetCollection = null;
        if (sdkChangeRecord.getOwner().isNew()) {
            targetCollection = cp.containerInstance(sdkChangeRecord.getAdds().size());
        } else {
            targetCollection = this.getRealCollectionAttributeValueFromObject(target, session);
        }

        List removes = sdkChangeRecord.getRemoves();
        List adds = sdkChangeRecord.getAdds();
        List changedMapKeys = sdkChangeRecord.getChangedMapKeys();

        synchronized (targetCollection) {
            for (Object removed : removes) {
                Object removeElement = buildRemovedElementFromChangeSet(removed, mergeManager, targetSession);

                Object targetElement = null;
                for (Object iter = cp.iteratorFor(targetCollection); cp.hasNext(iter);) {
                    targetElement = cp.next(iter, session);
                    if (this.compareElements(targetElement, removeElement, session)) {
                        break;// matching element found - skip the rest of them
                    }
                }
                if (targetElement != null) {
                    // a matching element was found, remove it
                    cp.removeFrom(targetElement, targetCollection, session);
                }
            }

            for (Object added : adds) {
                Object addElement = buildAddedElementFromChangeSet(added, mergeManager, targetSession);
                cp.addInto(addElement, targetCollection, session);
            }

            for (Object changed : changedMapKeys) {
                Object changedMapKeyElement = buildAddedElementFromChangeSet(changed, mergeManager, targetSession);
                Object originalElement = ((UnitOfWorkImpl)session).getOriginalVersionOfObject(changedMapKeyElement);
                cp.removeFrom(originalElement, targetCollection, session);
                cp.addInto(changedMapKeyElement, targetCollection, session);
            }
        }

        // reset the attribute to allow for set method to re-morph changes if the collection is not being stored directly
        setRealAttributeValueInObject(target, targetCollection);
    }

    /**
     * INTERNAL:
     * Merge changes from the source to the target object.
     * Simply replace the entire target collection.
     */
    public void mergeIntoObject(Object target, boolean isTargetUnInitialized, Object source, MergeManager mergeManager, AbstractSession targetSession) {
        ContainerPolicy cp = this.getContainerPolicy();
        AbstractSession session = mergeManager.getSession();

        Object sourceCollection = this.getRealCollectionAttributeValueFromObject(source, session);
        Object targetCollection = cp.containerInstance(cp.sizeFor(sourceCollection));

        for (Object iter = cp.iteratorFor(sourceCollection); cp.hasNext(iter);) {
            Object targetElement = this.buildElementFromElement(cp.next(iter, session), mergeManager, targetSession);
            cp.addInto(targetElement, targetCollection, session);
        }

        // reset the attribute to allow for set method to re-morph changes if the collection is not being stored directly
        setRealAttributeValueInObject(target, targetCollection);
    }

    /**
     * Convenience method.
     */
    private void setRealAttributeValueInObject(Object object, Object attributeValue) {
        getMapping().setRealAttributeValueInObject(object, attributeValue);
    }

    /**
     * ADVANCED:
     * This method is used to add an object to a collection once the changeSet is applied.
     * The referenceKey parameter should only be used for direct Maps.
     */
    public void simpleAddToCollectionChangeRecord(Object referenceKey, Object changeSetToAdd, ObjectChangeSet changeSet, AbstractSession session) {
        if (this.getContainerPolicy().hasOrder()) {
            this.simpleAddToCollectionChangeRecordWithOrder(referenceKey, changeSetToAdd, changeSet, session);
        } else {
            this.simpleAddToCollectionChangeRecordWithoutOrder(referenceKey, changeSetToAdd, changeSet, session);
        }
    }

    /**
     * Add stuff to an ordered collection.
     */
    private void simpleAddToCollectionChangeRecordWithOrder(Object referenceKey, Object changeSetToAdd, ObjectChangeSet changeSet, AbstractSession session) {
        EISOrderedCollectionChangeRecord changeRecord = (EISOrderedCollectionChangeRecord)changeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (changeRecord == null) {
            changeRecord = new EISOrderedCollectionChangeRecord(changeSet, this.getAttributeName(), this.getDatabaseMapping());
            changeSet.addChange(changeRecord);
        }
        changeRecord.simpleAddChangeSet(changeSetToAdd);
    }

    /**
     * Add stuff to an unordered collection.
     */
    private void simpleAddToCollectionChangeRecordWithoutOrder(Object referenceKey, Object changeSetToAdd, ObjectChangeSet changeSet, AbstractSession session) {
        EISCollectionChangeRecord changeRecord = (EISCollectionChangeRecord)changeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (changeRecord == null) {
            changeRecord = new EISCollectionChangeRecord(changeSet, this.getAttributeName(), this.getDatabaseMapping());
            changeSet.addChange(changeRecord);
        }
        changeRecord.simpleAddChangeSet(changeSetToAdd);
    }

    /**
     * ADVANCED:
     * This method is used to remove an object from a collection once the changeSet is applied.
     * The referenceKey parameter should only be used for direct Maps.
     */
    public void simpleRemoveFromCollectionChangeRecord(Object referenceKey, Object changeSetToRemove, ObjectChangeSet changeSet, AbstractSession session) {
        if (this.getContainerPolicy().hasOrder()) {
            this.simpleRemoveFromCollectionChangeRecordWithOrder(referenceKey, changeSetToRemove, changeSet, session);
        } else {
            this.simpleRemoveFromCollectionChangeRecordWithoutOrder(referenceKey, changeSetToRemove, changeSet, session);
        }
    }

    /**
     * Remove stuff from an ordered collection.
     */
    private void simpleRemoveFromCollectionChangeRecordWithOrder(Object referenceKey, Object changeSetToRemove, ObjectChangeSet changeSet, AbstractSession session) {
        EISOrderedCollectionChangeRecord changeRecord = (EISOrderedCollectionChangeRecord)changeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (changeRecord == null) {
            changeRecord = new EISOrderedCollectionChangeRecord(changeSet, this.getAttributeName(), this.getDatabaseMapping());
            changeSet.addChange(changeRecord);
        }
        changeRecord.simpleRemoveChangeSet(changeSetToRemove);
    }

    /**
     * Remove stuff from an unordered collection.
     */
    private void simpleRemoveFromCollectionChangeRecordWithoutOrder(Object referenceKey, Object changeSetToRemove, ObjectChangeSet changeSet, AbstractSession session) {
        EISCollectionChangeRecord changeRecord = (EISCollectionChangeRecord)changeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (changeRecord == null) {
            changeRecord = new EISCollectionChangeRecord(changeSet, this.getAttributeName(), this.getDatabaseMapping());
            changeSet.addChange(changeRecord);
        }
        changeRecord.simpleRemoveChangeSet(changeSetToRemove);
    }
}
