/********************************************************************************
 * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 ********************************************************************************/

package org.eclipse.mdm.api.atfxadapter.transaction;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import org.asam.ods.AoException;
import org.asam.ods.T_LONGLONG;
import org.eclipse.mdm.api.base.adapter.EntityType;
import org.eclipse.mdm.api.base.adapter.Relation;
import org.eclipse.mdm.api.base.model.Channel;
import org.eclipse.mdm.api.base.model.ContextRoot;
import org.eclipse.mdm.api.base.model.ContextType;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.FilesAttachable;
import org.eclipse.mdm.api.base.model.Measurement;
import org.eclipse.mdm.api.base.model.ParameterSet;
import org.eclipse.mdm.api.base.model.TestStep;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.base.query.Filter;
import org.eclipse.mdm.api.base.query.JoinType;
import org.eclipse.mdm.api.base.query.Query;
import org.eclipse.mdm.api.base.query.Result;
import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Delete statement is used to delete entities with their children.
 *
 * @see org.eclipse.mdm.api.odsadapter.transaction.DeleteStatement
 */
final class DeleteStatement extends BaseStatement {

	private static final List<String> AUTO_DELETABLE = Arrays.asList("MeaQuantity", "SubMatrix", "LocalColumn",
			"ExternalComponent");
	private static final Logger LOGGER = LoggerFactory.getLogger(DeleteStatement.class);

	private final boolean useAutoDelete;

	/**
	 * Constructor.
	 *
	 * @param transaction   The owning {@link ATFXTransaction}.
	 * @param entityType    The associated {@link EntityType}.
	 * @param useAutoDelete If {@code true} child relations of {@link Measurement}
	 *                      entities are not followed.
	 */
	DeleteStatement(ATFXTransaction transaction, EntityType entityType, boolean useAutoDelete) {
		super(transaction, entityType);
		this.useAutoDelete = useAutoDelete;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void execute(Collection<Entity> entities) throws AoException, DataAccessException {
		if (entities.stream().filter(e -> !e.getTypeName().equals(getEntityType().getName())).findAny().isPresent()) {
			throw new IllegalArgumentException("At least one given entity is of incompatible type.");
		}

		long start = System.currentTimeMillis();
		int amount = delete(getEntityType(), entities.stream().map(Entity::getID).collect(Collectors.toSet()), false);
		LOGGER.debug("{} instances deleted in {} ms.", amount, System.currentTimeMillis() - start);
	}

	/**
	 * Recursively follows child relations of given entities and deletes all child
	 * entities before deleting parent entities.
	 *
	 * @param entityType     {@link EntityType} of the deleted entities.
	 * @param instanceIDs    Instance IDs of entities which have to be deleted.
	 * @param ignoreSiblings Is it required to check whether {@link Measurement}
	 *                       siblings share a common {@link ContextRoot}s.
	 * @return Returns the total number of deleted instances.
	 * @throws AoException         Thrown if unable to delete entities.
	 * @throws DataAccessException Thrown if unable to query child entities.
	 */
	private int delete(EntityType entityType, Collection<String> instanceIDs, boolean ignoreSiblings)
			throws AoException, DataAccessException {
		if (instanceIDs.isEmpty()) {
			return 0;
		}

		Query query = getQueryService().createQuery().selectID(entityType);
		for (Relation relation : entityType.getChildRelations()) {
			if (useAutoDelete && AUTO_DELETABLE.contains(relation.getTarget().getName())) {
				continue;
			}

			if (!relation.getTarget().equals(relation.getSource())) {
				query.join(relation, JoinType.OUTER).selectID(relation.getTarget());
			}
		}

		// select attributes containing file links only for entity types
		// implementing FilesAttachable
		EntityConfig<?> entityConfig = getModelManager().getEntityConfig(entityType);
		if (FilesAttachable.class.isAssignableFrom(entityConfig.getEntityClass())) {
			entityType.getAttributes().stream().filter(a -> a.getValueType().isFileLinkType()).forEach(query::select);
		}

		EntityType testStep = getModelManager().getEntityType(TestStep.class);
		EntityType measurement = getModelManager().getEntityType(Measurement.class);
		EntityType channel = getModelManager().getEntityType(Channel.class);

		EntityType unitUnderTest = getModelManager().getEntityType(ContextRoot.class, ContextType.UNITUNDERTEST);
		EntityType testSequence = getModelManager().getEntityType(ContextRoot.class, ContextType.TESTSEQUENCE);
		EntityType testEquipment = getModelManager().getEntityType(ContextRoot.class, ContextType.TESTEQUIPMENT);

		// type in this list must be deleted AFTER this this instances have been
		// deleted
		// informative relation is considered as a child relation
		List<EntityType> delayedDelete = new ArrayList<>();

		// join context roots
		if (measurement.equals(entityType) || testStep.equals(entityType)) {
			query.join(entityType.getRelation(unitUnderTest), JoinType.OUTER).selectID(unitUnderTest);
			query.join(entityType.getRelation(testSequence), JoinType.OUTER).selectID(testSequence);
			query.join(entityType.getRelation(testEquipment), JoinType.OUTER).selectID(testEquipment);
			delayedDelete.addAll(Arrays.asList(unitUnderTest, testSequence, testEquipment));
		}

		// join parameter sets
		if (measurement.equals(entityType) || channel.equals(entityType)) {
			EntityType parameterSet = getModelManager().getEntityType(ParameterSet.class);
			query.join(entityType.getRelation(parameterSet), JoinType.OUTER).selectID(parameterSet);
		}

		Filter filter = Filter.or().ids(entityType, instanceIDs);
		entityType.getParentRelations().stream().filter(r -> r.getTarget().equals(entityType))
				.forEach(relation -> filter.ids(relation, instanceIDs));

		// query child IDs
		Map<EntityType, Set<String>> children = new HashMap<>();
		for (Result result : query.fetch(filter)) {
			// load children of other types
			result.stream().filter(r -> r.getID() != null && r.getID().length() > 0).forEach(r -> {
				children.computeIfAbsent(r.getEntityType(), k -> new HashSet<>()).add(r.getID());
			});
		}

		// omit context roots with references to not removed measurements
		if (!ignoreSiblings && measurement.equals(entityType)) {
			for (EntityType contextRoot : Arrays.asList(unitUnderTest, testSequence, testEquipment)) {
				Set<String> contextRootIDs = children.getOrDefault(contextRoot, Collections.emptySet());
				if (contextRootIDs.isEmpty()) {
					continue;
				}

				Query contextQuery = getQueryService().createQuery();
				contextQuery.selectID(contextRoot, measurement);
				contextQuery.join(contextRoot, measurement);

				for (Result result : contextQuery.fetch(Filter.idsOnly(contextRoot, contextRootIDs))) {
					if (instanceIDs.contains(result.getRecord(measurement).getID())) {
						continue;
					}

					// context root references a not removed measurement
					contextRootIDs.remove(result.getRecord(contextRoot).getID());
				}
			}
		}

		int amount = 0;
		// delete real children
		List<Entry<EntityType, Set<String>>> consideredChildren = new ArrayList<>();
		for (Entry<EntityType, Set<String>> entry : children.entrySet()) {
			EntityType childType = entry.getKey();
			Set<String> childInstanceIDs = entry.getValue();
			if (entityType.equals(childType)) {
				childInstanceIDs.removeAll(instanceIDs);
			} else if (delayedDelete.contains(entry.getKey())) {
				consideredChildren.add(entry);
				continue;
			}
			amount += delete(entry.getKey(), childInstanceIDs, true);
		}

		getApplElemAccess().deleteInstances(((ODSEntityType) entityType).getODSID(), toODSIDs(instanceIDs));

		// delete considered children (informative relation)
		for (Entry<EntityType, Set<String>> entry : consideredChildren) {
			amount += delete(entry.getKey(), entry.getValue(), true);
		}

		return amount + instanceIDs.size();
	}

	/**
	 * Converts given {@code Collection} of instance IDs to ODS a {@link T_LONGLONG}
	 * array.
	 *
	 * @param instanceIDs The instance IDs.
	 * @return The corresponding ODS {@code T_LONGLONG[]} is returned.
	 */
	private T_LONGLONG[] toODSIDs(Collection<String> instanceIDs) {
		return instanceIDs.stream().map(ODSConverter::toODSID).toArray(T_LONGLONG[]::new);
	}

}
