// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library 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 2 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.teqser;

import java.io.PrintStream;
import java.lang.reflect.Method;

import net.cellcomputing.himawari.accessory.primitive.p_String;
import net.cellcomputing.himawari.accessory.primitive.p_boolean;
import net.cellcomputing.himawari.accessory.primitive.p_double;
import net.cellcomputing.himawari.argparse.ArgParse;
import net.cellcomputing.himawari.library.RendermanInterface;
import net.cellcomputing.himawari.main.Himawari;
import net.cellcomputing.himawari.util.HimawariLogger;

/**
 * Himawari用のTextureを作成するためのツール
 * @author NTT DATA Corporation
 */
public strictfp class TeqserMain {
	//teqser.cppに定義されている値
	static p_boolean	g_version = new p_boolean(false);
	static p_boolean	g_help = new p_boolean(false);
	static p_boolean	g_envcube = new p_boolean(false);
	static p_boolean	g_envlatl = new p_boolean(false);
	static p_boolean	g_shadow = new p_boolean(false);

	static p_String	g_swrap = new p_String("black");
	static p_String	g_twrap = new p_String("black");
	static p_String	g_wrap = new p_String("");
	static p_String g_filter = new p_String("box");
	static p_String g_resize = new p_String("up");
	static 	p_double g_swidth = new p_double(1.0f);
	static 	p_double g_twidth = new p_double(1.0f);
	static p_double g_fov = new p_double(90.0f);
	static p_double g_width = new p_double(-1.0f);
	static p_String g_compress = new p_String("none");
	static 	p_double g_quality = new p_double(70.0f);
	static 	p_double g_bake = new p_double(64.0f);
	
	public static final String VERSION_STR = "1.0.0";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
	    ArgParse ap = new ArgParse();
	    Method filterfunc = null;
//	    args = new String[args.length+1];
	    
	    ap.usageHeader("Usage: " + Himawari.class.getSimpleName() + " [options] outfile" );
	    ap.argFlag( "help", "print this help and exit", g_help );
	    ap.argFlag( "version", "print version information and exit", g_version );
	    ap.argString( "compression", "=string[none|lzw|packbits|deflate]", g_compress );
	    ap.argFlag( "envcube", " px nx py ny pz nzproduce a cubeface environment map from 6 images.", g_envcube );
	    ap.argFlag( "envlatl", "produce a latlong environment map from an image file.", g_envlatl );
	    ap.argFlag( "shadow", "produce a shadow map from a z file.", g_shadow );
	    ap.argString( "swrap", "=strings wrap [black|periodic|clamp]", g_swrap );
	    ap.argString( "smode", "=string(equivalent to swrap for BMRT compatibility)", g_swrap );
	    ap.argString( "twrap", "=stringt wrap [black|periodic|clamp]", g_twrap );
	    ap.argString( "tmode", "=string(equivalent to twrap for BMRT compatibility)", g_swrap );
	    ap.argString( "wrap", "=stringwrap st [black|periodic|clamp]", g_wrap );
	    ap.argString( "mode", "=strings (equivalent to wrap for BMRT compatibility)", g_wrap );
	    ap.argString( "filter", "=string[box|bessel|catmull-rom|disk|gaussian|sinc|triangle]", g_filter );
	    ap.argFloat( "fov(envcube)", "=float[>=0.0f]", g_fov );
	    ap.argFloat( "swidth", "=floats width [>0.0f]", g_swidth );
	    ap.argFloat( "twidth", "=floatt width [>0.0f]", g_twidth );
	    ap.argFloat( "width", "=floatwidth [>0,0f] set both swidth and twidth", g_width );
	    ap.argFloat( "quality", "=float[>=1.0f &&  <= 100.0f]", g_quality );
	    ap.argFloat( "bake", "=float[>=2.0f && <= 2048.0f]", g_bake );
	    ap.argString( "resize", "=string[up|down|round|up-|down-|round-]\nNot used, for BMRT compatibility only!", g_resize );


	    if ( args.length > 0 && !ap.parse( args.length, args ) )
	    {
	        System.err.print( ap.errmsg() +"\n");
	        System.err.print(ap.usagemsg());
	        System.exit( 1 );
	    }

	    if ( g_version.value )
	    {
	        version( System.out );
	        System.exit( 0 );
	    }

	    if ( g_help.value || ap.leftovers().size() <= 1 )
	    {
	        System.out.print( ap.usagemsg());
	        System.exit( 0 );
	    }

	    if ( g_envcube.value && g_shadow.value )
	    {
	        System.out.println("Specify only one of envcube or shadow" );
	        System.exit( 1 );
	    }

	    /* find the pixel's filter function */
	    try {
			filterfunc =RendermanInterface.class.getMethod("RiBoxFilter",float.class, float.class, float.class, float.class);
			if ( g_filter.value.equals( "box" ))
			    filterfunc = RendermanInterface.class.getMethod("RiBoxFilter",float.class, float.class, float.class, float.class);
			else if ( g_filter.value.equals( "sinc") )
			    filterfunc = RendermanInterface.class.getMethod("RiSincFilter",float.class, float.class, float.class, float.class);
			else if ( g_filter.value.equals( "catmull-rom") )
			    filterfunc = RendermanInterface.class.getMethod("RiCatmullRomFilter",float.class, float.class, float.class, float.class);
			else if ( g_filter.value.equals( "disk") )
			    filterfunc = RendermanInterface.class.getMethod("RiDiskFilter",float.class, float.class, float.class, float.class);
			else if ( g_filter.value.equals( "bessel") )
			    filterfunc = RendermanInterface.class.getMethod("RiBesselFilter",float.class, float.class, float.class, float.class);
			else if ( g_filter.value.equals( "triangle") )
			    filterfunc = RendermanInterface.class.getMethod("RiTriangleFilter",float.class, float.class, float.class, float.class);
			else if ( g_filter.value.equals( "gaussian") )
			    filterfunc = RendermanInterface.class.getMethod("RiGaussianFilter",float.class, float.class, float.class, float.class);
		} catch (SecurityException e) {
			HimawariLogger.outputException(e);
			filterfunc = null;
		} catch (NoSuchMethodException e) {
			HimawariLogger.outputException(e);
			filterfunc = null;
		}



	    /* protect the s,t width */
	    if ( g_swidth.value < 1.0 )
	    {
	        System.err.print("g_swidth is smaller than 1.0." +" 1.0 will be used instead." +"\n");
	        g_swidth.value = 1.0;
	    }
	    if ( g_twidth.value < 1.0 )
	    {
	        System.err.print("g_twidth is smaller than 1.0." +" 1.0 will be used instead." +"\n");
	        g_twidth.value = 1.0;
	    }

	    /* protect the s,t wrap mode */
	    if ( !( ( g_swrap.value.equals("black") ) || ( g_swrap.value.equals("periodic") ) || ( g_swrap.value.equals("clamp") ) ) )
	    {
	        System.err.print("Unknown s wrap mode: " +g_swrap.value +". black will be used instead." +"\n");
	        g_swrap.value = "black";
	    }
	    if ( !( ( g_twrap.value.equals("black") ) || ( g_twrap.value.equals("periodic") ) || ( g_twrap.value.equals("clamp") ) ) )
	    {
	        System.err.print("Unknown t wrap mode: " +g_twrap.value +". black will be used instead." +"\n");
	        g_twrap.value = "black";
	    }
	    if ( !( ( g_wrap.value.equals("") ) || ( g_wrap.value.equals("black") ) || ( g_wrap.value.equals("periodic") ) || ( g_wrap.value.equals("clamp") ) ) )
	    {
	        System.err.print("Unknown wrap mode: " +g_wrap.value +". black will be used instead." +"\n");
	        g_wrap.value = "black";
	    }
	    
		/* If wrap is specified, it overrides both s and t */
//		if( g_wrap.value != "" )
		if(! g_wrap.value.equals("") )
		{
			g_twrap.value = g_wrap.value;
			g_swrap.value = g_wrap.value;
		}
		
		/* Need to set both st width ? */
	    if ( g_width.value > 0.0 )
	    {
	        g_twidth.value = g_swidth.value = g_width.value;
	    }

	    /* protect the compression mode */
	    if ( !( ( g_compress.value.equals( "deflate" ) ) ||
	            ( g_compress.value.equals( "lzw" ) ) ||
	            ( g_compress.value.equals( "none" ) ) ||
	            ( g_compress.value.equals( "packbits" ) )
	          )
	       )
	    {
	        System.err.print("Unknown compression mode: " +g_compress +". none." +"\n");
	        g_compress.value = "none";
	    }

	    /* protect the quality mode */
	    if ( g_quality.value < 1.0f ) g_quality.value = 1.0;
	    if ( g_quality.value > 100.0f ) g_quality.value = 100.0;

	    /* protect the bake mode */
	    if ( g_bake.value < 2.0f ) g_bake.value = 2.0;
	    if ( g_bake.value > 2048.0f ) g_bake.value = 2048.0;

	    String compression = ( String) g_compress.value;
	    float quality = ( float ) g_quality.value;


	    RendermanInterface.RiBegin( "teqser" );

	    if ( g_envcube.value )
	    {
	        if ( ap.leftovers().size() != 7 )
	        {
	            System.err.print("Need 6 images for cubic environment map" +"\n");
	            System.exit( -1 );
	        }

	        System.out.printf( "CubeFace Environment %s %s %s %s %s %s ----> %s \n\t\"fov\"= %4.1f\n\t\"filter\"= %s \n\t\"swidth\"= %4.1f\n\t\"twidth\"= %4.1f\n\t\"compression\" = %s\n",
			(String)(ap.leftovers().elementAt(0)),
			(String)(ap.leftovers().elementAt( 1 )),
			(String)(ap.leftovers().elementAt( 2 )),
			(String)(ap.leftovers().elementAt( 3 )),
			(String)(ap.leftovers().elementAt( 4 )),
			(String)(ap.leftovers().elementAt( 5 )),
			(String)(ap.leftovers().elementAt( 6 )),
	                g_fov.value,
	                g_filter.value,
	                g_swidth.value,
	                g_twidth.value,
	                (String) g_compress.value
	              );

	        RendermanInterface.RiMakeCubeFaceEnvironment(
			(String)(ap.leftovers().elementAt( 0 )),
			(String)(ap.leftovers().elementAt( 1 )),
			(String)(ap.leftovers().elementAt( 2 )),
			(String)(ap.leftovers().elementAt( 3 )),
			(String)(ap.leftovers().elementAt( 4 )),
			(String)(ap.leftovers().elementAt( 5 )),
			(String)(ap.leftovers().elementAt( 6 )),
	               (float) g_fov.value,
	                filterfunc,
			( float ) g_swidth.value,
			( float ) g_twidth.value,
			"compression",
			compression,
			"quality",
			quality,
			null );
	    }
	    else if ( g_shadow.value )
	    {
	        System.out.printf( "Shadow %s ----> %s \n\t\"compression\" = %s\n",
	                (String) ap.leftovers().elementAt( 0 ),
	                (String) ap.leftovers().elementAt( 1 ),
	                (String) g_compress.value);



	        RendermanInterface.RiMakeShadow( (String) ap.leftovers().elementAt( 0 ), (String) ap.leftovers().elementAt( 1 ), ( float ) g_twidth.value, "compression", compression, "quality", quality, null );
	    }
	    else if ( g_envlatl.value )
	    {
	        System.out.printf( "LatLong Environment %s ----> %s \n\t\"compression\" = %s \n",
	                (String) ap.leftovers().elementAt( 0 ),
	                (String) ap.leftovers().elementAt( 1 ),
	                (String) g_compress.value );



	        RendermanInterface.RiMakeLatLongEnvironment( (String) ap.leftovers().elementAt( 0 ), (String) ap.leftovers().elementAt( 1 ), filterfunc,
	                                  ( float ) g_swidth.value, ( float ) g_twidth.value, "compression", compression, "quality", quality, null );
	    }
	    else
	    {

	        System.out.printf( "Texture %s ----> %s \n\t\"swrap\"= %s \n\t\"twrap\"= %s \n\t\"filter\"= %s \n\t\"swidth\"= %4.1f\n\t\"twidth\"= %4.1f\n\t\"compression\" = %s\n",
	                (String) ap.leftovers().elementAt( 0 ),
	                (String) ap.leftovers().elementAt( 1 ),
	                (String) g_swrap.value,
	                (String) g_twrap.value,
	                (String) g_filter.value,
	                g_swidth.value,
	                g_twidth.value,
	                compression
	              );

	        if (ap.leftovers().elementAt( 0 ).contains(".bake"))
	        {
//	        	String envbake = new String();
//	            int bake = (int) g_bake.value;
//
//	            envbake =  "BAKE=" + bake;
//	            
//	            putenv(envbake);
	        }
	        RendermanInterface.RiMakeTexture( (String) ap.leftovers().elementAt( 0 ), (String) ap.leftovers().elementAt( 1 ),
	                       (String) g_swrap.value, (String) g_twrap.value, filterfunc,
	                       ( float ) g_swidth.value, ( float ) g_twidth.value, "compression", compression, "quality", quality, null );

	    }

	    RendermanInterface.RiEnd();

	    System.exit( 0 ); 
	}

	public static void version(PrintStream  Stream )
	{
		Stream.println("teqser version " +  VERSION_STR);
	}
}
