
/*
 * Copyright (C) 2002 - 2007 Lehrstuhl Grafische Systeme, BTU Cottbus
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package de.grogra.c4d;

import de.grogra.c4d.model.C4D;
import de.grogra.xl.util.LongHashMap;

public final class BaseDocument
{
	private final long pointer;
	private final LongHashMap<BaseObject> handleToObject = new LongHashMap<BaseObject>();
	private long referenceObjects;

	public BaseDocument(long pointer)
	{
		this.pointer = pointer;
	}

	public long getPointer()
	{
		return pointer;
	}

	boolean registerObject(long handle, BaseObject object)
	{
		BaseObject prev = handleToObject.put(handle, object);
		if (object instanceof XLObject)
		{
			C4D.setJavaObject(pointer, handle, (XLObject) object);
		}
		else if (prev != null)
		{
			C4D.setJavaObject(pointer, handle, null);
		}
		return prev != null;
	}

	public BaseObject getBaseObject(long handle)
	{
		if (handle == 0)
		{
			return null;
		}
		BaseObject o = handleToObject.get(handle);
		if (o == null)
		{
			switch (C4D.getType(pointer, handle))
			{
				case Constants.Onull:
					o = new Null(this, handle);
					break;
				case Constants.Osphere:
					o = new Sphere(this, handle);
					break;
				case Constants.Ocube:
					o = new Cube(this, handle);
					break;
				case Constants.Oinstance:
					o = new Instance(this, handle);
					break;
				case Constants.ID_XL_INSTANCE:
				case Constants.ID_XL_OBJECT:
					o = new XLObject(this, handle);
					break;
				case Constants.SPRING_OBJECT_ID:
					o = new Spring(this, handle);
					break;
				default:
					o = new BaseObject(this, handle);
					break;
			}
			handleToObject.put(handle, o);
		}
		return o;
	}

	public void removeObjectReferences(long[] handles)
	{
		if (handles != null)
		{
			for (int i = 0; i < handles.length; i++)
			{
				handleToObject.remove(handles[i]);
			}
		}
	}

	public BaseObject getFirstObject()
	{
		return getBaseObject(C4D.getFirstObject(pointer));
	}

	public BaseObject searchReferenceObject(String name)
	{
		if (referenceObjects == 0)
		{
			referenceObjects = C4D.findSibling(pointer, C4D.getFirstObject(pointer), "XL Reference Objects");
			if (referenceObjects == 0)
			{
				return null;
			}
		}
		long child = C4D.getDown(pointer, referenceObjects);
		if (child == 0)
		{
			return null;
		}
		return getBaseObject(C4D.findSibling(pointer, child, name));
	}

	public BaseObject searchObject(String name)
	{
		return getBaseObject(C4D.searchObject(pointer, name));
	}

	public void setupReferenceObjects()
	{
		if (referenceObjects != 0)
		{
			return;
		}
		referenceObjects = C4D.findSibling(pointer, C4D.getFirstObject(pointer), "XL Reference Objects");
		if (referenceObjects != 0)
		{
			return;
		}
		referenceObjects = C4D.newBaseObject(pointer, Constants.Onull, false);
		if (referenceObjects == 0)
		{
			return;
		}
		C4D.setEditorMode(pointer, referenceObjects, Constants.MODE_OFF);
		C4D.setRenderMode(pointer, referenceObjects, Constants.MODE_OFF);
		C4D.setName(pointer, referenceObjects, "XL Reference Objects");
		C4D.insertObject(pointer, referenceObjects, 0, 0, false);
		long obj = C4D.newBaseObject(pointer, Constants.Ocube, false);
		if (obj != 0)
		{
			C4D.setVector(pointer, obj, Constants.PRIM_CUBE_LEN, 2, 1, 2);
			C4D.setName(pointer, obj, "Cube");
			C4D.insertUnderLast(pointer, obj, referenceObjects);
		}
		obj = C4D.newBaseObject(pointer, Constants.Ocylinder, true);
		if (obj != 0)
		{
			C4D.setReal(pointer, obj, Constants.PRIM_CYLINDER_HEIGHT, 1);
			C4D.setReal(pointer, obj, Constants.PRIM_CYLINDER_RADIUS, 1);
			C4D.setName(pointer, obj, "Cylinder");
			C4D.insertUnderLast(pointer, obj, referenceObjects);
		}
		obj = C4D.newBaseObject(pointer, Constants.Ocone, true);
		if (obj != 0)
		{
			C4D.setReal(pointer, obj, Constants.PRIM_CONE_HEIGHT, 1);
			C4D.setReal(pointer, obj, Constants.PRIM_CONE_BRAD, 1);
			C4D.setName(pointer, obj, "Cone");
			C4D.insertUnderLast(pointer, obj, referenceObjects);
		}
	}

	public double getTime()
	{
		return C4D.getTime(pointer);
	}

	public int getFps()
	{
		return C4D.getFps(pointer);
	}

	public double getFrameStep()
	{
		return 1.0 / C4D.getFps(pointer);
	}

	private long handleForXLObject;

	public void setHandleForXLObject(long pointer)
	{
		handleForXLObject = pointer;
	}

	public long getHandleForXLObject()
	{
		long pointer = handleForXLObject;
		handleForXLObject = 0;
		return pointer;
	}
}
