/**
 {copyright}
 */

package com.{company}.{initiative}.common;

import javax.cim.CIMObjectPath;
import javax.wbem.WBEMException;

import com.{company}.{initiative}.providers.ReferenceInterface;


/**
 * Helper class used for performing reference and associator calls. This class
 * provides a call back mechanism for association methods to utilize. The
 * function that creates this needs to build this class such that either the
 * Reference1 (top) or Reference2 (bottom) part if the association is empty. The
 * class will them add the references based on which one is empty. For example:
 * If we are iterating an association class we may get all the Reference1s (top)
 * part and then want to add the appropriate Reference2 (bottom) parts. You
 * would create an instance of this class with the specific reference1 you are
 * working with and it can then be used to add. In essence one class creates
 * this class, it then calls another classes enumerate function. That enumerate
 * function will see that this parameter is not null and will use this to fill
 * the iterator. the Reference2 parts. See HostedStoragePoolInstrumentation for
 * an example.
 */
public class ReferenceInfo {

	// Objectpath of the top part of an assoc (Antecedent, GroupComponent etc..)
	private CIMObjectPath mReference1;
	// Objectpath of the bottom part of an assoc (Dependent, PartComponent
	// etc..)
	private CIMObjectPath mReference2;
	// The role, if it is for the top part
	private final String mRef1Role;
	// role for the bottom part
	private final String mRef2Role;
	// if returning instances, only return local properties
	private final boolean mLocalOnly;
	// if returning instances, only return class origin attribure
	private final boolean mIncludeClassOrigin;
	// property list
	private final String[] mPropertyList;
	// Are we getting instances or objectpaths
	private final boolean mIsObjectPath;
	// The reference interface we will use
	private final ReferenceInterface mRefInterface;

	/**
	 * Creates a new ReferenceInfo reference1 or reference2 can be null, but
	 * they both can not be null nor can both have a value
	 * 
	 * @param reference1
	 *            The objectpath representing the top portion of an assoc e.g.
	 *            Antecedent, GroupComponent
	 * @param reference2
	 *            The objectpath representing the botton portion of an assoc
	 *            e.g. Dependent, PartComponent.
	 * @param ref1Role
	 *            Role name for top part
	 * @param ref2Role
	 *            role name for bottom
	 * @param pPropertyList
	 *            List of properties to get, null for all
	 * @param pIsObjectPath
	 *            true to get objectpaths, false for instances
	 * @param pRefInterface
	 *            the reference interface to use - <B>CAN NOT BE NULL</B>
	 * @throws WBEMException
	 */
	public ReferenceInfo(CIMObjectPath reference1, CIMObjectPath reference2,
			final String ref1Role, final String ref2Role,
			final boolean localOnly, final boolean includeClassOrigin,
			String[] pPropertyList, boolean pIsObjectPath,
			final ReferenceInterface pRefInterface) throws WBEMException {
		if (reference1 != null && reference2 != null) {
			throw new WBEMException(WBEMException.CIM_ERR_FAILED,
					"ReferenceInfo CTOR: Either the reference1 or reference2"
							+ "must be null");
		}
		if (pRefInterface == null) {
			throw new WBEMException(WBEMException.CIM_ERR_FAILED,
					"ReferenceInfo CTOR: ReferenceInterface can not be null");
		}
		mReference1 = reference1;
		mReference2 = reference2;
		mRef1Role = ref1Role;
		mRef2Role = ref2Role;
		mPropertyList = pPropertyList;
		mIsObjectPath = pIsObjectPath;
		mRefInterface = pRefInterface;
		mLocalOnly = localOnly;
		mIncludeClassOrigin = includeClassOrigin;
	}

	public synchronized CIMObjectPath getReference1() {
		return mReference1;
	}

	public synchronized CIMObjectPath getReference2() {
		return mReference2;
	}

	public synchronized String getReference1Role() {
		return mRef1Role;
	}

	public synchronized String getReference2Role() {
		return mRef2Role;
	}

	public synchronized String[] getPropertyList() {
		return mPropertyList;
	}

	public synchronized boolean isObjectPath() {
		return mIsObjectPath;
	}

	/**
	 * @return localOnly value
	 */
	public synchronized boolean localOnly() {
		return mLocalOnly;
	}

	/**
	 * 
	 * @return includeClassOrigin values
	 */
	public synchronized boolean includeClassOrigin() {
		return mIncludeClassOrigin;
	}

	public synchronized void addReference(final CustomCloseableIterator<?> iter,
			final CIMObjectPath pReference) {
		boolean ref1Null = true;
		// See which member is null and set that to the pReference param
		if (null == mReference1) {
			mReference1 = pReference;
		} else {
			ref1Null = false;
			mReference2 = pReference;
		}
		// Call the addReference function to do the work.
		mRefInterface.AddReference(iter, pReference, this);
		// since this is a shared object we have to reset the reference value
		// back to null
		if (ref1Null) {
			mReference1 = null;
		} else {
			mReference2 = null;
		}
	}
}
