package org.codefilarete.stalactite.dsl.relation;

import org.codefilarete.reflection.SerializableAccessor;
import org.codefilarete.reflection.SerializableMutator;
import org.codefilarete.stalactite.engine.configurer.onetoone.OneToOneRelationConfigurer;
import org.codefilarete.stalactite.sql.ddl.structure.Column;

/**
 * @param <C> entity type
 * @param <I> entity identifier type
 * @param <O> target entity type
 * @author Guillaume Mary
 */
public interface OneToOneEntityOptions<C, I, O> extends OneToOneOptions<C, O> {
	
	/**
	 * {@inheritDoc}
	 * Overridden for return type accuracy
	 */
	OneToOneEntityOptions<C, I, O> mandatory();
	
	/**
	 * Defines the bidirectional relation.
	 * No need to additionally call {@link #mappedBy(SerializableAccessor)} or {@link #reverseJoinColumn(Column)}.
	 *
	 * If the relation is already defined through {@link #reverseJoinColumn(Column)} or {@link #mappedBy(SerializableAccessor)} then there's no
	 * guaranty about which one will be taken first. Algorithm is defined in {@link OneToOneRelationConfigurer}.
	 *
	 * Overridden for return type accuracy
	 *
	 * @param reverseLink opposite owner of the relation (setter)
	 * @return the global mapping configurer
	 */
	OneToOneEntityOptions<C, I, O> mappedBy(SerializableMutator<? super O, C> reverseLink);
	
	/**
	 * Defines the bidirectional relation.
	 * No need to additionally call {@link OneToOneOptions#mappedBy(SerializableMutator)} or {@link #reverseJoinColumn(Column)}.
	 *
	 * If the relation is already defined through {@link #reverseJoinColumn(Column)} or {@link OneToOneOptions#mappedBy(SerializableMutator)} then there's no
	 * guaranty about which one will be taken first. Algorithm is defined in {@link OneToOneRelationConfigurer}.
	 *
	 * @param reverseLink opposite owner of the relation (getter)
	 * @return the global mapping configurer
	 */
	OneToOneEntityOptions<C, I, O> mappedBy(SerializableAccessor<? super O, C> reverseLink);
	
	/**
	 * {@inheritDoc}
	 * Overridden for return type accuracy
	 *
	 * @param reverseColumnName opposite owner of the relation
	 * @return the global mapping configurer
	 */
	OneToOneEntityOptions<C, I, O> reverseJoinColumn(String reverseColumnName);
	
	/**
	 * Defines reverse side owning column.
	 * Note that defining it this way will not allow relation to be fixed in memory (after select in database), prefer {@link OneToOneOptions#mappedBy(SerializableMutator)}.
	 * Use this method to define unidirectional relation.
	 *
	 * If the relation is already defined through {@link #mappedBy(SerializableAccessor)} or {@link OneToOneOptions#mappedBy(SerializableMutator)} then there's no
	 * guaranty about which one will be taken first. Algorithm is defined in {@link OneToOneRelationConfigurer}.
	 *
	 * @param reverseLink opposite owner of the relation
	 * @return the global mapping configurer
	 */
	OneToOneEntityOptions<C, I, O> reverseJoinColumn(Column<?, I> reverseLink);
	
	/**
	 * {@inheritDoc}
	 * Overridden for return type accuracy
	 *
	 * @return the global mapping configurer
	 */
	OneToOneEntityOptions<C, I, O> fetchSeparately();
	
	/**
	 * {@inheritDoc}
	 * Overridden for return type accuracy
	 *
	 * @return the global mapping configurer
	 */
	OneToOneOptions<C, O> columnName(String columnName);
	
	/**
	 * {@inheritDoc}
	 * Overridden for return type accuracy
	 *
	 * @return the global mapping configurer
	 */
	OneToOneEntityOptions<C, I, O> unique();
	
}
