/***************************************************************************
 *   Copyright (C) 2004-2005 by                                            *
 *     Paolo Sacconier   <axa1981@tin.it>                                  *
 *     Francesco Tamagni <minchiahead@hacari.org>                          *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) 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.             *
 ***************************************************************************/
#include "field.h"

namespace gillo {

Field::Field(Context& c)
: Entity(c)
{
	type = FIELD;
	dSpaceID sid = dSimpleSpaceCreate(c.getSid());
	gid = (dGeomID) sid;
	Entity::Init();
	
	int num_indices, ioff=0, voff=0;

	/* ssg part */
	ssgEntity *field_obj = ssgLoadAC ( "field.ac" ) ;
	ssgEntity *field_out_obj = ssgLoadAC ( "field_out.ac" ) ;
	//ssgInvisible * hide = new ssgInvisible;
	trans.addKid( field_obj );
	alphaTrans.addKid( field_out_obj );
	ssgFlatten         ( field_obj  ) ;
	ssgFlatten         ( field_out_obj  ) ;
	ssgSimpleState* ss = (ssgSimpleState *)((ssgLeaf *)((ssgBranch *) field_out_obj)->getKid(0))->getState();
	ss -> enable( GL_CULL_FACE );
	ssgStripify        ( &trans ) ;
	ssgStripify        ( &alphaTrans ) ;
// 	field_out_obj->clrTraversalMaskBits(SSGTRAV_ISECT);

	/* dde part */
	ssgTransform * f = (ssgTransform *) field_obj;
	num_indices = getNumIndices(f);
	
	// @FIXME memory wasting
	vertices = (dReal*) malloc(num_indices*3*sizeof(dReal));
	indices = (int*) malloc(num_indices*sizeof(int));
	gids = (dGeomID*) malloc(num_indices/3 * sizeof(dGeomID));
	
	sgMat4 thematrix;
	trans.getTransform(thematrix);
	getTriangleData(f, vertices, indices, &voff, &ioff, thematrix);
	vertexcount = voff/3;
	indexcount = ioff;
	
	// @FIXME
// 	printf("Vertex waste %d\n", num_indices*3 - voff);
// 	printf("Index waste %d\n", num_indices - ioff);

	// planes for ode collisions
	for (int i = 0; i < indexcount; i+= 3) {
		sgVec4 plane;
		sgVec3 v[3];
		
		for (int j= 0; j < 3; j++)
			for (int jj = 0; jj < 3; jj++)
				v[j][jj] = (float) vertices[indices[i+j]*3+jj];
		sgMakePlane(plane, v[0], v[1], v[2]);
		// REMEMBER:
		// 	ode  plane ax + by + cz = d
		// 	plib plane ax + by + cz + d = 0
		// fuck it!
		gids[i/3] = dCreatePlane (sid, (dReal) plane[0], (dReal) plane[1], (dReal) plane[2], (dReal) -plane[3]);
		dGeomSetData(gids[i/3], this);
	}
}


Field::~Field()
{
	if (vertices) free(vertices);
	if (indices) free(indices);
	if (gids) free(gids);
	//@fixme superclass destructor
}


void Field::update(float dt)
{
// 	sgSetCoord(&pos, 0.0f,  0.0f, 0.0f, 0.0f, 0.0f, 0.0f );
// 	trans.setTransform(&pos);
}

int Field::getNumIndices(ssgEntity * ent) {
	int i, num = 0;
	if (ent->getNumKids() == 0){
		ssgLeaf * le = (ssgLeaf *) ent;
		return (le->getNumTriangles())*3;
	}
	else {
		ssgBranch * br = (ssgBranch *) ent;
		for (i=0; i<br->getNumKids(); i++){
			num += getNumIndices(br->getKid(i));
		}
		return num;
	}
}

void Field::getTriangleData( ssgEntity * ent, dReal * vertices, int * indices, int *vert_offset, int *ind_offset, sgMat4 thematrix) {
	int i,j;
	if (ent->isAKindOf(ssgTypeLeaf())){
		ssgLeaf * le = (ssgLeaf *) ent;
		int ind_start = (*vert_offset)/3; // dio porco
		int ind_max = 0;
		
// 		printf("This leaf has %d triangles.\n", le->getNumTriangles());
		for (i=0; i<le->getNumTriangles(); i++) {
			short int ind[3];
			le->getTriangle(i, &ind[0], &ind[1], &ind[2]);
// 			printf("Catched triangle with indices: %4d %4d %4d.\n",
// 				ind[0], ind[1], ind[2]);
			for (j=0; j<3; j++){
				indices[*ind_offset+j] = (int) ind[j];
				
				if (indices[*ind_offset+j]>ind_max)
					ind_max = ind[j];

				indices[*ind_offset+j] += ind_start;	
			}
/*			printf("Stored  triangle with indices: %4d %4d %4d.\n",
				indices[*ind_offset+0], indices[*ind_offset+1], indices[*ind_offset+2]);*/
			(*ind_offset)+=3;
		}
		
		for (i = 0; i <= ind_max; i++) {
			float *vert_p;
			vert_p = le->getVertex(i);
			sgVec3 vert;
			sgCopyVec3(vert, vert_p);
			sgXformPnt3 (vert, thematrix);
			for (j=0; j<3; j++){
				vertices[*vert_offset+j] = (dReal) vert[j];
			}
// 			printf("Stored vertex num %d: %4f %4f %4f.\n",
// 				*vert_offset/3,
// 				vertices[*vert_offset+0], vertices[*vert_offset+1], vertices[*vert_offset+2]);
			(*vert_offset)+=3;
		}
        
	}
	else if (ent->isAKindOf(ssgTypeBranch())){
		ssgBranch * br = (ssgBranch *) ent;
		if (br->isAKindOf(ssgTypeTransform())){
			sgMat4 newmatrix;
			((ssgTransform*)br)->getTransform(newmatrix);
			sgPostMultMat4(thematrix, newmatrix);
		}
		
		for (i=0; i<br->getNumKids(); i++){
			getTriangleData(br->getKid(i), vertices, indices, vert_offset, ind_offset, thematrix);
		}
	} else {
		// FIXME
		printf("Unhandled Entity in scene while collecting triangles.\n");
	}
}

void Field::getPos(sgVec3 out)
{
	out[0] = 0;
	out[1] = 0;
	out[2] = 0;
}

};
