/*
@license.text@
 */
package com.hammurapi.reasoning.tutorial.rules;

import com.hammurapi.reasoning.spi.Condition;
import com.hammurapi.reasoning.spi.Infer;
import com.hammurapi.reasoning.spi.InferenceContext;
import com.hammurapi.reasoning.tutorial.objectmodel.Aunt;
import com.hammurapi.reasoning.tutorial.objectmodel.Brother;
import com.hammurapi.reasoning.tutorial.objectmodel.Child;
import com.hammurapi.reasoning.tutorial.objectmodel.Cousin;
import com.hammurapi.reasoning.tutorial.objectmodel.Daughter;
import com.hammurapi.reasoning.tutorial.objectmodel.Husband;
import com.hammurapi.reasoning.tutorial.objectmodel.Nephew;
import com.hammurapi.reasoning.tutorial.objectmodel.Niece;
import com.hammurapi.reasoning.tutorial.objectmodel.Parent;
import com.hammurapi.reasoning.tutorial.objectmodel.Sibling;
import com.hammurapi.reasoning.tutorial.objectmodel.Sister;
import com.hammurapi.reasoning.tutorial.objectmodel.Son;
import com.hammurapi.reasoning.tutorial.objectmodel.Uncle;
import com.hammurapi.reasoning.tutorial.objectmodel.Wife;

/**
 * Infers aunt, uncle, cousin, niece, nephew
 * @author Pavel Vlasov
 * @revision $Revision$
 */
public class SecondaryRules {
	
	/**
	 * Infers cousin as a child or parent's sibling.
	 */
	@Infer(Cousin.class)
	public void infer(Child child1, Child child2, Sibling sibling) {
		if (child1.getObject().equals(sibling.getSubject()) && child2.getObject().equals(sibling.getObject())) {
			InferenceContext.INSTANCE.post(new Cousin(child1.getSubject(), child2.getSubject()));
		}
	}
	
	/**
	 * If A is a cousin of B then B is a cousin of A
	 * @param cousin
	 * @return
	 */
	@Infer
	public Cousin infer(Cousin cousin) {
		return new Cousin(cousin.getObject(), cousin.getSubject());
	}
	
	/**
	 * Another way to infer cousin to demonstrate mutiple derivations
	 * @param aunt
	 * @param child
	 */
	@Infer
	@Condition("arg0.getSubject().equals(arg1.getSubject())")
	public Cousin infer(Aunt aunt, Parent parent) {
		return new Cousin(aunt.getObject(), parent.getObject());
	}
	
	/**
	 * Another way to infer cousin to demonstrate mutiple derivations
	 * @param uncle
	 * @param child
	 */
	@Infer
	public Cousin infer(Uncle uncle, Parent parent) {
		if (uncle.getSubject().equals(parent.getSubject())) {
			return new Cousin(uncle.getObject(), parent.getObject());
		}
		return null;
	}
	
	/**
	 * Sister of parent is aunt.
	 * @param sister
	 * @param parent
	 */
	@Infer
	public Aunt infer(Sister sister, Parent parent) {
		return sister.getObject().equals(parent.getSubject()) ? new Aunt(sister.getSubject(), parent.getObject()) : null;
	}
	
	/**
	 * Wife of uncle is aunt.
	 * @param sister
	 * @param parent
	 */
	@Infer
	public Aunt infer(Wife wife, Uncle uncle) {
		return wife.getObject().equals(uncle.getSubject()) ? new Aunt(wife.getSubject(), uncle.getObject()) : null;
	}
	
	/**
	 * Brother of parent is uncle.
	 * @param sister
	 * @param parent
	 */
	@Infer
	public Uncle infer(Brother brother, Parent parent) {
		return brother.getObject().equals(parent.getSubject()) ? new Uncle(brother.getSubject(), parent.getObject()) : null;
	}
	
	/**
	 * Husband of aunt is uncle.
	 * @param sister
	 * @param parent
	 */
	@Infer
	public Uncle infer(Husband husband, Aunt aunt) {
		return husband.getObject().equals(aunt.getSubject()) ? new Uncle(husband.getSubject(), aunt.getObject()) : null;
	}
	
	/**
	 * Daughter of sibling is niece.
	 */
	@Infer
	public Niece infer(Daughter daughter, Sibling sibling) {
		if (daughter.getObject().equals(sibling.getSubject())) {
			return new Niece(daughter.getSubject(), sibling.getObject());
		}
		return null;
	}
	
	// TODO Implement: Spouse's niece is my niece.
	
	/**
	 * Son of sibling is nephew.
	 */
	@Infer
	public Nephew infer(Son son, Sibling sibling) {
		if (son.getObject().equals(sibling.getSubject())) {
			return new Nephew(son.getSubject(), sibling.getObject());
		}
		return null;
	}
	
	// TODO Implement: Spouse's nephew is my nephew.
		
}
