package com.util.wrapper.selfdestroycollections;

import java.io.Serializable;
import java.time.Instant;

/**
 * Default implementation of WrapElemCreateTime
 * @author Jérémy Ruelle
 */
public class WrapElemCreateTimeImpl<E> implements WrapElemCreateTime<E>, Serializable {

	private static final long serialVersionUID = -7052616690519185017L;
	
	private final Instant wrapperCreationTime;
	private E object;

	private WrapElemCreateTimeImpl(E object) {
		this.object = object;

		this.wrapperCreationTime = Instant.now();
	}

	public static <E> WrapElemCreateTimeImpl<E> wrapObject(E object) {
		return new WrapElemCreateTimeImpl<>(object);
	}

	@Override
	public Instant getCreationTime() {
		return wrapperCreationTime;
	}

	@Override
	public E getObject() {
		return object;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((object == null) ? 0 : object.hashCode());
		return result;
	}

	/**
	 * This equals method has been modified in order to return true if the object in argument is equals to the unwrapped object
	 * WARNING : this method is not reflexive (the object in argument would return false if given the wrapped object) and must be used carefully
	 */
	@Override
	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		if(this.object == obj) {
			return true;
		}
		if(obj == null) {
			return object == null;
		}
		if(obj instanceof WrapElemCreateTime) {
			WrapElemCreateTime<?> other = (WrapElemCreateTime<?>) obj;
			if(object == null) {
				if (other.getObject() != null)
					return false;
			} else if(!object.equals(other.getObject()))
				return false;
		}else {
			// Since obj has already been checked as not null, we can directly return false
			if(object == null) {
				return false;
			}else if(!object.equals(obj)) {
				return false;
			}
		}
		
		// If all checks above failed, then it means they are equals
		return true;
	}
}