/**
 * Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *         Florian Pirchner - Initial implementation
 */

package org.eclipse.osbp.dsl.dto.lib;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

import org.eclipse.osbp.dsl.common.datatypes.IDto;
import org.eclipse.osbp.dsl.dto.lib.impl.DtoServiceAccess;
import org.eclipse.osbp.jpa.services.Query;
import org.eclipse.osbp.jpa.services.filters.LCompare;
import org.eclipse.osbp.runtime.common.annotations.DtoUtils;
import org.eclipse.osbp.runtime.common.filter.IDTOService;
import org.eclipse.osbp.runtime.common.hash.HashUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractOppositeDtoList<D extends IDto> extends ArrayList<D>
		implements IEntityMappingList<D>, PropertyChangeListener, Serializable {

	private static final String NOT_SUPPORTED_FOR_NOW = "Not supported for now.";
	private static final long serialVersionUID = -5777389952283179658L;

	private static Logger LOGGER = LoggerFactory.getLogger(AbstractOppositeDtoList.class);

	private final Class<?> dtoType;
	private final String parentProperty;
	private final transient Supplier<Object> idSupplier;
	private final transient PropertyChangeListener childListener;

	private boolean resolved;
	private boolean resolving;

	private transient Map<Object, D> addedToSuper = new HashMap<>();
	private transient Map<Object, D> added = new HashMap<>();
	private transient Map<Object, D> removed = new HashMap<>();
	private transient Map<Object, D> updated = new HashMap<>();

	private MappingContext mappingContext;

	public AbstractOppositeDtoList(MappingContext mappingContext, Class<?> dtoType, String parentProperty,
			Supplier<Object> idSupplier, PropertyChangeListener containerListener) {
		super();
		this.mappingContext = mappingContext != null ? mappingContext : new MappingContext();
		this.dtoType = dtoType;
		this.idSupplier = idSupplier;
		this.parentProperty = parentProperty;

		childListener = (e) -> {
			containerListener.propertyChange(e);
		};

	}

	public List<D> getAdded() {
		return new ArrayList<>(added.values());
	}

	public List<D> getRemoved() {
		return new ArrayList<>(removed.values());
	}

	public List<D> getUpdated() {
		return new ArrayList<>(updated.values());
	}

	/**
	 * Notifies the container of this list in case of cascading reference.
	 * @param changedDto
	 */
	protected void notifyContainer(D changedDto) {
		// implement in subclass
	}

	@SuppressWarnings("unchecked")
	protected void resolve() {
		syncContextWithTransaction();

		if (resolved || resolving || mappingContext.isNoCollectionResolving()) {
			return;
		}

		boolean oldDirtyStateActive = mappingContext.isDirtyAdapterActive();
		try {
			resolving = true;
			mappingContext.makeCurrent();
			mappingContext.setDirtyAdapterActive(false);

			IDTOService<?> service = DtoServiceAccess.getService(dtoType);

			Query query = new Query(new LCompare.Equal(parentProperty, idSupplier.get()));
			Collection<D> dtos = (Collection<D>) service.find(query);

			// remove the removed from the added
			for (D removed : getRemoved()) {
				String hash = hashDto(removed);
				added.remove(hash);

				// remove from super
				D toSuper = addedToSuper.remove(hash);
				if (toSuper != null) {
					super.remove(toSuper);
				}
			}

			// now merge the query result
			if (dtos.isEmpty()) {
				// if result is empty, add all added
				super.addAll(getAdded());
				addedToSuper.putAll(added);
			} else {
				HashMap<Object, D> tempAdded = new HashMap<>(added);
				for (D dto : dtos) {
					String hashCode = hashDto(dto);

					if (removed.containsKey(hashCode)) {
						// if it was removed, we do not add the dto
						continue;
					} else {
						if (tempAdded.containsKey(hashCode)) {
							// if it was added and contained in the DB, then we
							// add the added one
							D instance = tempAdded.get(hashCode);
							super.add(instance);
							addedToSuper.put(hashCode, instance);
							tempAdded.remove(hashCode);
						} else {
							// otherwise we add the persistent dto
							super.add(dto);

							addedToSuper.put(hashCode, dto);

							// register property change listener to the
							// persisted dto
							if (DtoUtils.getAdapter(getClass(), dto) == null) {
								DtoUtils.registerAdapter(this, dto);
							}
							dto.addPropertyChangeListener(childListener);
						}
					}
				}

				// now we add the pending added
				super.addAll(tempAdded.values());
				addedToSuper.putAll(tempAdded);
			}

		} catch (Exception ex) {
			resolved = false;
			resolving = false;
			throw new RuntimeException(ex);
		} finally {
			resolved = true;
			resolving = false;
			mappingContext.setDirtyAdapterActive(oldDirtyStateActive);
			mappingContext.unmakeCurrent();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.osbp.dsl.dto.lib.IEntityMappingList#mapToEntity(org.eclipse
	 * .osbp.dsl.dto.lib.IMapper, java.util.function.Consumer,
	 * java.util.function.Consumer)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <E> void mapToEntity(IMapper<D, E> childMapper, Consumer<E> oppositeAdder, Consumer<E> oppositeRemover) {

		syncContextWithTransaction();

		boolean oldNoContainerMapping = mappingContext.isNoContainerMapping();
		try {
			mappingContext.makeCurrent();

			// no container mapping! Otherwise childMapper.mapToEntity will
			// map the opposite side, which will cause a wrong container entity
			mappingContext.setNoContainerMapping(true);
			for (D added : getAdded()) {
				E addedE = mappingContext.get(childMapper.createEntityHash(added));
				if (addedE == null) {
					addedE = childMapper.createEntity();
					childMapper.mapToEntity(added, addedE, mappingContext);
				}
				oppositeAdder.accept(addedE);

				if (isResolved()) {
					if (!super.contains(added)) {
						super.add(added);
						addedToSuper.put(hashDto(added), added);
					}
				}
			}
			added.clear();

			// for remove we use container mapping! The container is null
			// and removeFromChildren will not remove the elements.
			mappingContext.setNoContainerMapping(true);
			for (D removed : getRemoved()) {
				E removedE = mappingContext.get(childMapper.createEntityHash(removed));
				if (removedE == null) {
					IDTOService<D> service = (IDTOService<D>) DtoServiceAccess.getService(dtoType);
					Object id = service.getId((D) removed);
					removedE = (E) mappingContext.findEntityByEntityManager(childMapper.createEntity().getClass(), id);
					if (removedE == null) {
						removedE = childMapper.createEntity();
						childMapper.mapToEntity(removed, removedE, mappingContext);
					}
				}
				oppositeRemover.accept(removedE);
				super.remove(removed);
				addedToSuper.remove(hashDto(removed));
			}
			removed.clear();

			// handle the changed values by remove and add
			//
			for (D modified : getUpdated()) {
				// remove
				//
				E modifiedE = mappingContext.get(childMapper.createEntityHash(modified));
				if (modifiedE == null) {
					IDTOService<D> service = (IDTOService<D>) DtoServiceAccess.getService(dtoType);
					Object id = service.getId((D) modified);
					modifiedE = (E) mappingContext.findEntityByEntityManager(childMapper.createEntity().getClass(), id);
					if (modifiedE == null) {
						modifiedE = childMapper.createEntity();
						childMapper.mapToEntity(modified, modifiedE, mappingContext);
					}
				}
				oppositeRemover.accept(modifiedE);
				if (isResolved()) {
					super.remove(modified);
					addedToSuper.remove(hashDto(modified));
				}

				// add
				//
//				modifiedE = childMapper.createEntity();
				childMapper.mapToEntity(modified, modifiedE, mappingContext);
				mappingContext.register(childMapper.createEntityHash(modified), modifiedE);
				oppositeAdder.accept(modifiedE);
				if (isResolved()) {
					if (!super.contains(modified)) {
						super.add(modified);
						addedToSuper.put(hashDto(modified), modified);
					}
				}
			}
			updated.clear();

		} finally {
			mappingContext.setNoContainerMapping(oldNoContainerMapping);
			mappingContext.unmakeCurrent();
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void propertyChange(PropertyChangeEvent evt) {

		if (removed.containsKey(hashDto((D) evt.getSource()))) {
			return;
		}
		if (!Objects.equals(evt.getOldValue(), evt.getNewValue())) {
			updated.put(hashDto((D) evt.getSource()), (D) evt.getSource());

			// notify the container that detail changed
			notifyContainer((D) evt.getSource());
		}
	}

	/**
	 * Checks if there is a current context from a transaction done right now.
	 * If so then use this one as the new mapping context since it is connected
	 * to the root service.
	 */
	private void syncContextWithTransaction() {
		MappingContext currentContext = MappingContext.getCurrent();
		if (currentContext != null) {
			mappingContext = currentContext;
		}
	}

	public boolean isResolved() {
		return resolved;
	}

	private String hashDto(D dto) {
		return HashUtil.createObjectWithIdHash(dto.getClass(), dto);
	}

	@Override
	public Stream<D> parallelStream() {
		resolve();
		return super.parallelStream();
	}

	@Override
	public Stream<D> stream() {
		resolve();
		return super.stream();
	}

	@Override
	public boolean add(D dto) {

		dto.addPropertyChangeListener(childListener);

		String hash = hashDto(dto);
		removed.remove(hash);
		added.put(hash, dto);

		// notify the container that detail changed
		notifyContainer(dto);

		if (resolving) {
			return false;
		}
		if (!resolved) {
			return true;
		} else {
			// add to super
			addedToSuper.put(hash, dto);
			return super.add(dto);
		}
	}

	@Override
	public void add(int arg0, D dto) {
		add(dto);
	}

	@Override
	public boolean addAll(Collection<? extends D> dtos) {
		boolean result = true;
		for (D dto : dtos) {
			result &= add(dto);
		}
		return result;
	}

	@Override
	public boolean addAll(int arg0, Collection<? extends D> dtos) {
		boolean result = true;
		for (D dto : dtos) {
			result &= add(dto);
		}
		return result;
	}

	@Override
	public void clear() {
		super.clear();
		added.clear();
		removed.clear();
	}

	@Override
	public Object clone() {
		resolve();
		return super.clone();
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean contains(Object arg0) {
		String hash = hashDto((D) arg0);
		if (getAdded().contains(hash)) {
			return true;
		}

		if (getRemoved().contains(hash)) {
			return false;
		}

		if (isResolved()) {
			return addedToSuper.containsKey(hash);
		} else {
			IDTOService<D> service = (IDTOService<D>) DtoServiceAccess.getService(dtoType);
			Object id = service.getId((D) arg0);
			D persDto = service.get(id);
			return persDto != null;
		}
	}

	@Override
	public void forEach(Consumer<? super D> arg0) {
		resolve();
		super.forEach(arg0);
	}

	@Override
	public D get(int arg0) {
		resolve();
		return super.get(arg0);
	}

	@Override
	public int indexOf(Object arg0) {
		resolve();
		return super.indexOf(arg0);
	}

	@Override
	public boolean isEmpty() {
		return size() == 0;
	}

	@Override
	public Iterator<D> iterator() {
		resolve();
		return super.iterator();
	}

	@Override
	public int lastIndexOf(Object arg0) {
		resolve();
		return super.lastIndexOf(arg0);
	}

	@Override
	public ListIterator<D> listIterator() {
		resolve();
		return super.listIterator();
	}

	@Override
	public ListIterator<D> listIterator(int arg0) {
		resolve();
		return super.listIterator(arg0);
	}

	@Override
	public D remove(int arg0) {
		// now we need to resolve, since we got an index...
		resolve();
		D result = super.remove(arg0);

		addedToSuper.remove(hashDto(result));
		updated.remove(hashDto(result));
		removed.put(hashDto(result), result);

		DtoUtils.unregisterAdapter(this, result);
		result.removePropertyChangeListener(childListener);

		// notify the container that detail changed
		notifyContainer(result);

		return result;
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean remove(Object dto) {
		String hash = hashDto((D) dto);
		removed.put(hash, (D) dto);
		added.remove(hash);
		updated.remove(hash);
		DtoUtils.unregisterAdapter(this, dto);
		((IDto) dto).removePropertyChangeListener(childListener);

		// notify the container that detail changed
		notifyContainer((D) dto);

		if (!resolved) {
			return true;
		} else {
			D ref = addedToSuper.remove(hash);
			return super.remove(ref);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean removeAll(Collection<?> arg0) {
		boolean result = true;
		for (Object x : arg0) {
			D dto = (D) x;
			result &= remove(dto);
		}
		return result;
	}

	@Override
	public boolean removeIf(Predicate<? super D> arg0) {
		throw new UnsupportedOperationException(NOT_SUPPORTED_FOR_NOW);
	}

	@Override
	protected void removeRange(int arg0, int arg1) {
		throw new UnsupportedOperationException(NOT_SUPPORTED_FOR_NOW);
	}

	@Override
	public void replaceAll(UnaryOperator<D> arg0) {
		throw new UnsupportedOperationException(NOT_SUPPORTED_FOR_NOW);
	}

	@Override
	public boolean retainAll(Collection<?> arg0) {
		throw new UnsupportedOperationException(NOT_SUPPORTED_FOR_NOW);
	}

	@Override
	public D set(int arg0, D arg1) {
		resolve();
		D dto = super.set(arg0, arg1);
		removed.put(hashDto(dto), dto);
		added.put(hashDto(arg1), arg1);
		return dto;
	}

	@Override
	public int size() {
		if (resolved) {
			return super.size();
		} else if (mappingContext.isNoCollectionResolving()) {
			return 0;
		}
		IDTOService<?> service = DtoServiceAccess.getService(dtoType);

		Query query = new Query(new LCompare.Equal(parentProperty, idSupplier.get()));
		return service.size(query) + getAdded().size() - getRemoved().size();
	}

	@Override
	public void sort(Comparator<? super D> arg0) {
		resolve();
		super.sort(arg0);
	}

	@Override
	public Spliterator<D> spliterator() {
		resolve();
		return super.spliterator();
	}

	@Override
	public List<D> subList(int arg0, int arg1) {
		resolve();
		return super.subList(arg0, arg1);
	}

	@Override
	public Object[] toArray() {
		resolve();
		return super.toArray();
	}

	@Override
	public <T> T[] toArray(T[] arg0) {
		resolve();
		return super.toArray(arg0);
	}

	@Override
	public void trimToSize() {
		resolve();
		super.trimToSize();
	}

	@Override
	public boolean containsAll(Collection<?> arg0) {
		for (Object dto : arg0) {
			if (!contains(dto)) {
				return false;
			}
		}
		return true;
	}

	@Override
	public boolean equals(Object o) {
		if (added.size() > 0 || removed.size() > 0) {
			return false;
		}

		LOGGER.error("equals - Check what to do here!");
		return super.equals(o);
	}
	
	@Override
	public int hashCode() {
		return super.hashCode();
	}
}
