package sg.util;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;

import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jme.util.export.binary.BinaryImporter;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;
import com.jmex.model.converters.AseToJme;
import com.jmex.model.converters.MaxToJme;
import com.jmex.model.converters.Md2ToJme;
import com.jmex.model.converters.Md3ToJme;
import com.jmex.model.converters.MilkToJme;
import com.jmex.model.converters.ObjToJme;

/**
 * Helper class for loading models and other stuff. Currently only loads JME
 * binary models, but it's easily customizable for loading other types.
 * 
 * @author Erick B Passos
 * 
 */
public class SGUtil {	
	
	/**
	 * Loads a model from file, creating a bounding box for it.
	 * @param path Path to jme file.
	 * @return loaded model
	 * @throws IOException
	 */
	public static Node loadModel(String path) {
		try {
			Node node = new Node();
			BufferedInputStream in = new BufferedInputStream(FileFinder.findURL(path).openStream());
			String ext = FileFinder.fileExtension(path);
			
			// So JME can find the model textures easily.
			try {
				ResourceLocatorTool.addResourceLocator(
						ResourceLocatorTool.TYPE_TEXTURE, 
						new SimpleResourceLocator(
								SGUtil.class.getClassLoader().getResource(path)));
			} catch (URISyntaxException e) {
				e.printStackTrace();
			}

			if(ext.equalsIgnoreCase("jme")){			
				node.attachChild((Spatial)BinaryImporter.getInstance().load(in));
			}
			else{
				ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); //For loading the raw file		

				// Converts the file into a jme usable file
				if(ext.equalsIgnoreCase("3ds")) new MaxToJme().convert(in, byteArrayOutputStream);
				else if(ext.equalsIgnoreCase("ase")) new AseToJme().convert(in, byteArrayOutputStream);
				else if(ext.equalsIgnoreCase("md2")) new Md2ToJme().convert(in, byteArrayOutputStream);
				else if(ext.equalsIgnoreCase("md3")) new Md3ToJme().convert(in, byteArrayOutputStream);
				else if(ext.equalsIgnoreCase("ms3d")) new MilkToJme().convert(in, byteArrayOutputStream);
				else if(ext.equalsIgnoreCase("obj")) new ObjToJme().convert(in, byteArrayOutputStream);
				
				// Used to convert the jme usable file to a TriMesh
				ByteArrayInputStream bridge = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
				//importer returns a Loadable, cast to Node
				node.attachChild((Spatial)BinaryImporter.getInstance().load(bridge));
			}
			
			node.setModelBound(new BoundingBox());
			node.updateModelBound();
			return node;
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	/**
	 * Loads textures
	 * 
	 * @param url is the path to the texture
	 * @return an texture
	 */
	public static Texture loadTexture(String url){
		return TextureManager.loadTexture(
				FileFinder.findURL(url),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        /*
		return  TextureManager.loadTexture(
				FileFinder.findURL(url),
                Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear, Image.Format.RGBA8,
                0.0f, true);
        */
	}
	
	/**
	 * Returns a JME TextureState whit the given texture
	 * 
	 * @param url is the path to the texture
	 * @return an TextureState
	 */
	public static TextureState getTextureState(String url){
		TextureState tstate = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
		tstate.setTexture(loadTexture(url));
        tstate.setEnabled(true);
        return tstate;
	}
	
	/**
	 * Helper method to apply a ZBufferState to a node.
	 * @param node
	 */
	/*
	public static void applyZBuffer(Node node) {
		ZBufferState zbuf = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
		zbuf.setWritable(false);
		zbuf.setEnabled(true);
		zbuf.setFunction(ZBufferState.CF_LEQUAL);
		node.setRenderState(zbuf);
	}*/
}
