/*
 * Copyright (c) 2009-2010 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jme3.scene.plugins.blender;

import java.util.List;

import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.asset.BlenderKey.WorldData;
import com.jme3.light.AmbientLight;
import com.jme3.light.Light;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.Camera;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.plugins.blender.cameras.CameraHelper;
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.lights.LightHelper;
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
import com.jme3.scene.plugins.blender.meshes.MeshHelper;
import com.jme3.scene.plugins.blender.objects.ObjectHelper;

/**
 * This class converts blender file blocks into jMonkeyEngine data structures.
 * @author Marcin Roguski
 */
/* package */class JmeConverter {

	private final DataRepository	dataRepository;

	/**
	 * Constructor. Creates the loader and checks if the given data is correct.
	 * @param dataRepository
	 *        the data repository; it should have the following field set: - asset manager - blender key - dna block
	 *        data - blender input stream Otherwise IllegalArgumentException will be thrown.
	 * @param featuresToLoad
	 *        bitwise flag describing what features are to be loaded
	 * @see FeaturesToLoad FeaturesToLoad
	 */
	public JmeConverter(DataRepository dataRepository) {
		// validating the given data first
		if (dataRepository.getAssetManager() == null) {
			throw new IllegalArgumentException("Cannot find asset manager!");
		}
		if (dataRepository.getBlenderKey() == null) {
			throw new IllegalArgumentException("Cannot find blender key!");
		}
		if (dataRepository.getDnaBlockData() == null) {
			throw new IllegalArgumentException("Cannot find dna block!");
		}
		if (dataRepository.getInputStream() == null) {
			throw new IllegalArgumentException("Cannot find blender file stream!");
		}
		this.dataRepository = dataRepository;
	}

	/**
	 * This method converts the given structure to a scene node.
	 * @param structure
	 *        structure of a scene
	 * @return scene's node
	 */
	public Node toScene(Structure structure) {// TODO: import the scene
		if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.SCENES) == 0) {
			return null;
		}
		return new Node(structure.getName());
	}

	/**
	 * This method converts the given structure to a camera.
	 * @param structure
	 *        structure of a camera
	 * @return camera's node
	 */
	public Camera toCamera(Structure structure) throws BlenderFileException {
		CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class);
		if (cameraHelper.shouldBeLoaded(structure, dataRepository)) {
			return cameraHelper.toCamera(structure);
		}
		return null;
	}

	/**
	 * This method converts the given structure to a light.
	 * @param structure
	 *        structure of a light
	 * @return light's node
	 */
	public Light toLight(Structure structure) throws BlenderFileException {
		LightHelper lightHelper = dataRepository.getHelper(LightHelper.class);
		if (lightHelper.shouldBeLoaded(structure, dataRepository)) {
			return lightHelper.toLight(structure, dataRepository);
		}
		return null;
	}

	/**
	 * This method converts the given structure to a node.
	 * @param structure
	 *        structure of an object
	 * @return object's node
	 */
	public Object toObject(Structure structure) throws BlenderFileException {
		ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
		if (objectHelper.shouldBeLoaded(structure, dataRepository)) {
			return objectHelper.toObject(structure, dataRepository);
		}
		return null;
	}

	/**
	 * This method converts the given structure to a list of geometries.
	 * @param structure
	 *        structure of a mesh
	 * @return list of geometries
	 */
	public List<Geometry> toMesh(Structure structure) throws BlenderFileException {
		MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);
		if (meshHelper.shouldBeLoaded(structure, dataRepository)) {
			return meshHelper.toMesh(structure, dataRepository);
		}
		return null;
	}

	/**
	 * This method converts the given structure to a material.
	 * @param structure
	 *        structure of a material
	 * @return material's node
	 */
	public Material toMaterial(Structure structure) throws BlenderFileException {
		MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
		if (materialHelper.shouldBeLoaded(structure, dataRepository)) {
			return materialHelper.toMaterial(structure, dataRepository);
		}
		return null;
	}

	/**
	 * This method returns the data read from the WORLD file block. The block contains data that can be stored as
	 * separate jme features and therefore cannot be returned as a single jME scene feature.
	 * @param structure
	 *        the structure with WORLD block data
	 * @return data read from the WORLD block that can be added to the scene
	 */
	public WorldData toWorldData(Structure structure) {
		WorldData result = new WorldData();

		// reading ambient light
		AmbientLight ambientLight = new AmbientLight();
		float ambr = ((Number) structure.getFieldValue("ambr")).floatValue();
		float ambg = ((Number) structure.getFieldValue("ambg")).floatValue();
		float ambb = ((Number) structure.getFieldValue("ambb")).floatValue();
		ambientLight.setColor(new ColorRGBA(ambr, ambg, ambb, 0.0f));
		result.setAmbientLight(ambientLight);

		return result;
	}
}
