/*
 * This file is part of the DistSim distributed simulation framework (hibernate-extension)
 * Copyright (C) 2007 Ulf Hermann; 2003-2006 Doug Currie, doug.currie@alum.mit.edu and others
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package brn.distsim.ormapper.class2hbm;

import java.io.Serializable;

/**
 * @version 1.x
 * @author <a href="mailto:doug.currie@alum.mit.edu">e</a>
 */
class ReflectedComponent extends ReflectedProperty {

	private static final int KIND_UNKNOWN = 0;

	private static final int KIND_BASIC = 1; // nothing or serializable

	private static final int KIND_ASSOCIATION = 2;

	private static final int KIND_COMPONENT = 3;

	private ReflectedClass component; // my component

	private int kind = KIND_UNKNOWN;

	protected ReflectedComponent(String name, Class type, MapGenerator map,
			ReflectedClass comp, String className) {
		super(name, type, map, "prospective-component", className);
		this.component = comp;
	}

	private int determineKind() {
		// this decision has to be delayed to avoid circularities
		// e.g., a component which includes itself will not have
		// access to this info until it is fully processed
		// but we cache it here...
		if (kind != KIND_UNKNOWN)
			return kind;
		// is the prospective component a persistent class
		if (component.isPersistent()) {
			// make it an association
			comment = "association";
			kind = KIND_ASSOCIATION;
			return KIND_ASSOCIATION;
		}
		// does the prospective component have any properties?
		// first let it look in superclasses
		component.addSuperclassProps();
		if (component.hasProperties()) {
			// make it a component
			comment = "component";
			kind = KIND_COMPONENT;
			return KIND_COMPONENT;
		}
		if (Serializable.class.isAssignableFrom(type)) {
			// make it a serializable
			tynm = "serializable";
			comment = "serializable";
			kind = KIND_BASIC;
			return KIND_BASIC;
		} else {
			buf.append("<!--  BUG unknown kind! name=\"").append(name).append(
					"\" type=\"").append(type.getName()).append("\" -->\n");
			kind = KIND_BASIC;
			return KIND_BASIC;
		}
	}

	protected void getXMLinArray(int level, StringBuffer buf) {
		this.buf = buf;
		switch (determineKind()) {
		case KIND_BASIC:
			super.getXML(level, buf);
			break;
		case KIND_COMPONENT:
			getXMLas(level, true);
			break;
		case KIND_ASSOCIATION:
			component.getXMLasMany2Many(level);
			break;
		default:
			throw new IllegalArgumentException("can't map that class");
		}
	}

	protected void getXMLinComposite(int level, StringBuffer buf) {
		// this.buf = buf;
		getXMLinArray(level, buf);
	}

	protected void emitMany2OneStr(int level) {
		map.emitPrefix(level);
		buf.append("<many-to-one cascade=\"all\" name=\"").append(name).append(
				"\" column=\"").append(map.columnNameFor(name)).append(
				"\" class=\"").append(tynm).append("\" access=\"field").append(
				"\"/>\n");
	}

	protected void getXML(int level, StringBuffer buf) {
		this.buf = buf;
		switch (determineKind()) {
		case KIND_BASIC:
			super.getXML(level, buf);
			return;
		case KIND_COMPONENT:
			getXMLas(level, false); // go on...
			return;
		case KIND_ASSOCIATION:
			emitMany2OneStr(level);
			return;
		default:
			throw new IllegalArgumentException("can't map that class");
		}
	}

	private void getXMLas(int level, boolean isComposite) {
		if (component != null) {
			if (map.cycleBuster.contains(component)) {
				throw new IllegalArgumentException("can't map that class");
			} else {
				map.cycleBuster.add(component);
			}
			if (isComposite) {
				component.getXMLasComposite(level);
			} else {
				component.getXMLasComponent(level, name);
			}
		}
	}

}
