package net.sourceforge.pain.data;
import net.sourceforge.pain.db.*;
import java.util.*;
/**
 * role can be considered as type of object, every object could have only one role of the specified class
 */
public abstract class Role extends DbObject implements LogicalObject {
	/**
	 * used for default getSuperroles method impl
	 */
	private static final Class[] emptySuper = new Class[0];
	/**
	 * every LogicalObject may have as many Roles as it want to have
	 * All it's roles linked with one Root object.
	 * This field is a reference to the LogicalObject root
	 */
	private static final int ROOT = 0;
	/**
	 * Number of subrroles of this Role in LogicalObject.
	 * Subrroles is Dynamic SubClasses of this Role.
	 */
	private static final int NSUBROLES = 1;
	public static final int LAST_BASE_FIELD_INDEX = 1;
	/** used by db during startup */
	public Role() {
	}
	protected Role(PainDB db)  {
		super(db);
	}
	final void init(Root root) {
		setReference(ROOT, root);
	}
	/**
	 Every Role subclass MUST call provideSuperSchema();
	 */
	protected final int fillSuperSchema(byte[] types, String[] names) {
		types[ROOT] = DbType.REFERENCE;
		names[ROOT] = "root";
		types[NSUBROLES] = DbType.INT;
		names[NSUBROLES] = "nsubroles";
		return 1;
	}
	/** PAiN has dynamic inheritance model,
	 every type(role) should know own superroles with deep=1
	 this method could be overriden by impl
	 returns array of Role classes
	 */
	protected Class[] getSuperroles() {
		return emptySuper;
	}
	void incNSubroles() {
		setInt(NSUBROLES, getInt(NSUBROLES) + 1);
	}
	public boolean hasSubroles() {
		return getInt(NSUBROLES) > 0;
	}
	void decNSubroles() {
		setInt(NSUBROLES, getInt(NSUBROLES) - 1);
	}
	/** helpers:
	 Used to avoid explicit owner extraction before cast to another type
	 */
	public final Role getRole(Class typeClass) {
		if (typeClass == getClass()) {
			return this;
		}
		return getRoot().getRole(typeClass);
	}
	public final boolean is(Class typeClass) {
		if (typeClass == getClass()) {
			return true;
		}
		return getRoot().is(typeClass);
	}
	public final Role addRole(Class typeClass) throws Exception {
		return getRoot().addRole(typeClass);
	}
	public final void removeRole(Class typeClass) throws Exception {
		getRoot().removeRole(typeClass);
	}
	public final void detach() {
		getRoot().removeRole(this);
	}
	public int getRoleClassId() {
		return ((DbOid) getDbClass().getOid()).getIndexId(); // using paindb low level internals!
	}
	public boolean sameObjectAs(LogicalObject obj) {
		if (obj == this) {
			return true;
		}
		if (obj.getClass() == Root.class) {
			return getRoot() == obj;
		}
		return getRoot() == ((Role) obj).getRoot();
	}
	public Iterator rolesIterator() {
		return getRoot().rolesIterator();
	}
	protected Root getRoot() {
		return (Root) getReference(ROOT);
	}
	public void _nullRoot() {
		setReference(ROOT, null);
	}
	final void _delete() {
		super.delete();
	}
	/** will delete whole object with all roles */
	public void delete() {
		getRoot().delete();
	}
}