/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis 
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA 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
 * (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 MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <vistaio/vista4mia.hh>
#include <mia/mesh/triangularMesh.hh>

NS_BEGIN(vista_mesh_io)

NS_MIA_USE;
using namespace std;

static char const * const format = "vista";

class CVistaMeshIO: public CMeshIOPlugin {
public:
	CVistaMeshIO();
private:
	virtual PTriangleMesh do_load(string const &  filename) const;
	virtual bool do_save(string const &  filename, const CTriangleMesh& data) const;
	const string  do_get_descr() const;
};

extern "C" EXPORT CPluginBase *get_plugin_interface()
{
	//vista::prepare_vista_logging();
	return new CVistaMeshIO;
}

// implementation part


CVistaMeshIO::CVistaMeshIO():
	CMeshIOPlugin(format)
{
	//add_property(io_plugin_property_history);
	add_suffix(".-");
	add_suffix(".v");
	add_suffix(".V");
	add_suffix(".vmesh");
	add_suffix(".VMESH");

}

const string  CVistaMeshIO::do_get_descr()const
{
	return string("Vista/Simbio triangle mesh input/output support");
}

template <class T>
struct TVNodeType: public VistaIONodeBaseRec {
	T type;
	T3DVector<T> vertex;
};

template <class T>
struct TVNNodeType: public TVNodeType<T> {
	T3DVector<T> normal;
};

template <class T>
struct TVSNodeType: public TVNodeType<T> {
	T scale;
};

template <class T>
struct TVCNodeType: public TVNodeType<T> {
	T3DVector<T> color;
};

template <class T>
struct TVNCNodeType: public TVNNodeType<T> {
	T3DVector<T> color;
};

template <class T>
struct TVCSNodeType: public TVCNodeType<T> {
	T scale;
};

template <class T>
struct TVNSNodeType: public TVNNodeType<T> {
	T scale;
};

template <class T>
struct TVNCSNodeType: public TVNCNodeType<T> {
	T scale;
};

struct TTriangelType {
	VistaIONodeBaseRec base;
	int type;
	T3DVector<unsigned int> t;
};


static  CTriangleMesh::PTrianglefield  read_triangles(VistaIOGraph graph, size_t v_size)
{
	cvdebug() << "vista_meshio::read_triangles()\n";

	long node_size = graph->nfields;
	if ( node_size != 4 ) {
		cverr() << "only triangles supported\n";
		return CTriangleMesh::PTrianglefield();
	}

	if (VistaIONodeRepn(graph) != VistaIOLongRepn) {
		cverr() <<"only long indices supported\n";
		return CTriangleMesh::PTrianglefield();
	}
	TTriangelType *node = (TTriangelType*)VistaIOGraphFirstNode(graph);
	CTriangleMesh::PTrianglefield triangles(new CTriangleMesh::CTrianglefield(VistaIOGraphNNodes(graph)));

	CTriangleMesh::triangle_iterator t = triangles->begin();
	CTriangleMesh::triangle_iterator e = triangles->end();

	while (node) {

		if (t == e) {
			return CTriangleMesh::PTrianglefield();
		}

		node->t.x--;
		node->t.y--;
		node->t.z--;
		if (node->t.x < v_size &&
		    node->t.y < v_size &&
		    node->t.z < v_size) {
			// set triangle values
			*t++ = node->t;
		}else{
			cverr() <<"addressing vertexes " << node->t << " but have only "<<v_size<< "vertices\n";
			cverr() <<"Bougus mesh: Triangle vertex out of bounds - bailing out\n";
			return CTriangleMesh::PTrianglefield();
		}
		node = (TTriangelType*)VistaIOGraphNextNode(graph);
	}
	return triangles;
}

static  CTriangleMesh *read_vgraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	TVNodeType<float> *node = (TVNodeType<float> *)VistaIOGraphFirstNode(vgraph);
	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));

	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	while (node) {
		if (v == e)
			return NULL;
		*v++ = node->vertex;
		node = (TVNodeType<float> *)VistaIOGraphNextNode(vgraph);
	}
	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices);
}

static CTriangleMesh *read_vsgraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	TVSNodeType<float> *node =
		(TVSNodeType<float> *)VistaIOGraphFirstNode(vgraph);

	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PScalefield scales(new CTriangleMesh::CScalefield(VistaIOGraphNNodes(vgraph)));

	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	CTriangleMesh::scale_iterator s =  scales->begin();


	while (node && v != e) {
		*v++ = node->vertex;
		*s++ = node->scale;
		node = (TVSNodeType<float> *)VistaIOGraphNextNode(vgraph);
	}

	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices,
				 CTriangleMesh::PNormalfield(),
				 CTriangleMesh::PColorfield(), scales);

}

static CTriangleMesh *read_vcgraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PColorfield color(new CTriangleMesh::CColorfield(VistaIOGraphNNodes(vgraph)));

	TVCNodeType<float> *node =
		(TVCNodeType<float> *)VistaIOGraphFirstNode(vgraph);

	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	CTriangleMesh::color_iterator c = color->begin();

	cvdebug() << "First color = " << *c << "\n"; 
	while (node && v != e) {
		*v++ = node->vertex;
		*c++ = node->color;
		cvdebug() << "load: n=" << node->vertex << " c=" << node->color << "\n"; 
		node = (TVCNodeType<float> *)VistaIOGraphNextNode(vgraph);
	}

	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices,
				 CTriangleMesh::PNormalfield(),
				 color,
				 CTriangleMesh::PScalefield());
}


static CTriangleMesh *read_vcsgraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PColorfield  color(new CTriangleMesh::CColorfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PScalefield  scales(new CTriangleMesh::CScalefield(VistaIOGraphNNodes(vgraph)));

	TVCSNodeType<float> *node =
		(TVCSNodeType<float> *)VistaIOGraphFirstNode(vgraph);

	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	CTriangleMesh::color_iterator c = color->begin();
	CTriangleMesh::scale_iterator s = scales->begin();


	while (node && v != e) {
		*v++ = node->vertex;
		*c++ = node->color;
		*s++ = node->scale;
		node = (TVCSNodeType<float> *)VistaIOGraphNextNode(vgraph);
	}

	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices, CTriangleMesh::PNormalfield(), color, scales);
}

static CTriangleMesh *read_vngraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	TVNNodeType<float> *node =
		(TVNNodeType<float> *)VistaIOGraphFirstNode(vgraph);

	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PNormalfield normals(new CTriangleMesh::CNormalfield(VistaIOGraphNNodes(vgraph)));

	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	CTriangleMesh::normal_iterator n = normals->begin();

	while (node && v != e) {
		*v++ =  node->vertex;
		*n++ =  node->normal;
		node = (TVNNodeType<float> *)VistaIOGraphNextNode(vgraph);

	}

	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices, normals,
				 CTriangleMesh::PColorfield(),
				 CTriangleMesh::PScalefield());
}

static CTriangleMesh *read_vnsgraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	TVNSNodeType<float> *node =
		(TVNSNodeType<float> *)VistaIOGraphFirstNode(vgraph);

	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PNormalfield normals(new CTriangleMesh::CNormalfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PScalefield  scales(new CTriangleMesh::CScalefield(VistaIOGraphNNodes(vgraph)));


	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	CTriangleMesh::normal_iterator n = normals->begin();
	CTriangleMesh::scale_iterator s =  scales->begin();

	while (node && v != e) {
		*n++ = node->normal;
		*v++ = node->vertex;
		*s++ = node->scale;
		node = (TVNSNodeType<float> *)VistaIOGraphNextNode(vgraph);
	}

	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices,
				 normals, CTriangleMesh::PColorfield(), scales);
}


static CTriangleMesh *read_vncgraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	TVNCNodeType<float> *node =
		(TVNCNodeType<float> *)VistaIOGraphFirstNode(vgraph);

	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PNormalfield normals(new CTriangleMesh::CNormalfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PColorfield  color(new CTriangleMesh::CColorfield(VistaIOGraphNNodes(vgraph)));


	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	CTriangleMesh::normal_iterator n = normals->begin();
	CTriangleMesh::color_iterator c = color->begin();

	while (node && v != e) {
		*n++ = node->normal;
		*v++ = node->vertex;
		*c++ = node->color;
		node = (TVNCNodeType<float> *)VistaIOGraphNextNode(vgraph);
	}

	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices, normals, color, CTriangleMesh::PScalefield());

}

static CTriangleMesh *read_vncsgraph(VistaIOGraph vgraph, VistaIOGraph tgraph)
{
	TVNCSNodeType<float> *node =
		(TVNCSNodeType<float> *)VistaIOGraphFirstNode(vgraph);
	CTriangleMesh::PVertexfield vertices(new CTriangleMesh::CVertexfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PNormalfield normals(new CTriangleMesh::CNormalfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PColorfield  color(new CTriangleMesh::CColorfield(VistaIOGraphNNodes(vgraph)));
	CTriangleMesh::PScalefield  scales(new CTriangleMesh::CScalefield(VistaIOGraphNNodes(vgraph)));


	CTriangleMesh::vertex_iterator v = vertices->begin();
	CTriangleMesh::vertex_iterator e = vertices->end();
	CTriangleMesh::normal_iterator n = normals->begin();
	CTriangleMesh::color_iterator c = color->begin();
	CTriangleMesh::scale_iterator s = scales->begin();

	while (node && v != e) {
		*n++ = node->normal;
		*v++ = node->vertex;
		*c++ = node->color;
		*s++ = node->scale;
		node = (TVNCSNodeType<float> *)VistaIOGraphNextNode(vgraph);
	}

	CTriangleMesh::PTrianglefield triangles = read_triangles(tgraph, vertices->size());
	if (!triangles) {
		return NULL;
	}
	return new CTriangleMesh(triangles, vertices, normals, color, scales);
}


static VistaIOGraph create_vgraph(const CTriangleMesh& mesh)
{
	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 4, VistaIOFloatRepn, 0);


	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();

	TVNodeType<float> node;
	node.type = 1;

	int pos = 1;

	while (vi != ve) {
		node.vertex = *vi++;
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}

static VistaIOGraph create_vngraph(const CTriangleMesh& mesh)
{
	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 7, VistaIOFloatRepn, 0);
	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();
	CTriangleMesh::const_normal_iterator ni = mesh.normals_begin();

	TVNNodeType<float> node;
	node.type = 2;
	int pos = 1;
	
	while (vi != ve) {
		node.vertex = *vi++;
		node.normal = *ni++;
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}

static VistaIOGraph create_vsgraph(const CTriangleMesh& mesh)
{
	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 5, VistaIOFloatRepn, 0);
	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();
	CTriangleMesh::const_scale_iterator si = mesh.scale_begin();

	TVSNodeType<float> node;
	node.type = 4;
	int pos = 1;

	while (vi != ve) {
		node.vertex = *vi++;
		node.scale  = *si++;
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}


static VistaIOGraph create_vnsgraph(const CTriangleMesh& mesh)
{

	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 8, VistaIOFloatRepn, 0);
	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();
	CTriangleMesh::const_normal_iterator ni = mesh.normals_begin();
	CTriangleMesh::const_scale_iterator si = mesh.scale_begin();

	int pos = 1;
	TVNSNodeType<float> node;
	node.type = 5;

	while (vi != ve) {
		node.vertex = *vi++;
		node.normal = *ni++;
		node.scale  = *si++;
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}

static VistaIOGraph create_vcgraph(const CTriangleMesh& mesh)
{

	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 7, VistaIOFloatRepn, 0);
	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();
	CTriangleMesh::const_color_iterator  ci  = mesh.color_begin();

	int pos = 1;
	TVCNodeType<float> node;
	node.type = 7;
	
	while (vi != ve) {
		node.vertex = *vi++;
		node.color  = *ci++;
		cvdebug() << "write: n=" << node.vertex << " c=" << node.color << "\n"; 
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}

static VistaIOGraph create_vncgraph(const CTriangleMesh& mesh)
{

	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 10, VistaIOFloatRepn, 0);
	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();
	CTriangleMesh::const_normal_iterator ni = mesh.normals_begin();
	CTriangleMesh::const_color_iterator  ci = mesh.color_begin();

	int pos = 1;
	TVNCNodeType<float> node;
	node.type = 3;

	while (vi != ve) {
		node.vertex = *vi++;
		node.normal = *ni++;
		node.color  = *ci++;

		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}

static VistaIOGraph create_vcsgraph(const CTriangleMesh& mesh)
{

	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 8, VistaIOFloatRepn, 0);
	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();
	CTriangleMesh::const_color_iterator  ci = mesh.color_begin();
	CTriangleMesh::const_scale_iterator si = mesh.scale_begin();

	TVCSNodeType<float> node;
	node.type = 8;
	int pos = 1;


	while (vi != ve) {
		node.vertex = *vi++;
		node.color  = *ci++;
		node.scale  = *si++;
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}
static VistaIOGraph create_vncsgraph(const CTriangleMesh& mesh)
{

	VistaIOGraph result = VistaIOCreateGraph(mesh.vertices_size(), 11, VistaIOFloatRepn, 0);
	CTriangleMesh::const_vertex_iterator vi = mesh.vertices_begin();
	CTriangleMesh::const_vertex_iterator ve = mesh.vertices_end();
	CTriangleMesh::const_normal_iterator ni = mesh.normals_begin();
	CTriangleMesh::const_color_iterator  ci = mesh.color_begin();
	CTriangleMesh::const_scale_iterator si = mesh.scale_begin();

	TVNCSNodeType<float> node;
	node.type = 6;
	int pos = 1;

	while (vi != ve) {
		node.vertex = *vi++;
		node.normal = *ni++;
		node.color  = *ci++;
		node.scale  = *si++;
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
	}
	return result;
}

typedef VistaIOGraph (*vertexgraph_create)(const CTriangleMesh& mesh);
typedef CTriangleMesh *   (*vertexgraph_read)(VistaIOGraph graph1, VistaIOGraph graph2);

typedef struct {
	int simbio_type;
	const char *type_name;
	vertexgraph_create create;
	vertexgraph_read   read;
	int data_avail;
} vertexio_t;

vertexio_t vertexio_lookup[]  = {
	{ 1, "Vertex",                  create_vgraph,    read_vgraph   ,
	  CTriangleMesh::ed_vertex },

	{ 2, "VertexNormal",            create_vngraph,   read_vngraph  ,
	  CTriangleMesh::ed_vertex | CTriangleMesh::ed_normal},

	{ 4, "VertexScalar",            create_vsgraph,   read_vsgraph  ,
	  CTriangleMesh::ed_vertex | CTriangleMesh::ed_scale},

	{ 5, "VertexNormalScalar",      create_vnsgraph,  read_vnsgraph ,
	  CTriangleMesh::ed_vertex | CTriangleMesh::ed_normal| CTriangleMesh::ed_scale},

	{ 7, "VertexColor",             create_vcgraph,   read_vcgraph  ,
	  CTriangleMesh::ed_vertex | CTriangleMesh::ed_color},

	{ 8, "VertexColorScalar",       create_vcsgraph,  read_vcsgraph ,
	  CTriangleMesh::ed_vertex | CTriangleMesh::ed_color| CTriangleMesh::ed_scale},

	{ 3, "VertexNormalColor",       create_vncgraph,  read_vncgraph ,
	  CTriangleMesh::ed_vertex | CTriangleMesh::ed_normal | CTriangleMesh::ed_color},

	{ 6, "VertexNormalColorScalar", create_vncsgraph, read_vncsgraph,
	  CTriangleMesh::ed_vertex | CTriangleMesh::ed_normal
	  | CTriangleMesh::ed_color | CTriangleMesh::ed_scale},

	{ 0, NULL, NULL, NULL, 0}
};

typedef struct {
	VistaIOGraph graph;
	vertexgraph_read   read;
} vertex_reader_t;

static bool  lookup_vertex_graph(VistaIOAttrList list, VistaIOAttrListPosn *pos, vertex_reader_t *result)
{
	vertexio_t *lookup =  vertexio_lookup;
	while (lookup->simbio_type != 0) {
		if (VistaIOLookupAttr(list,lookup->type_name,pos)) {
			VistaIOGetAttrValue(pos, NULL, VistaIOGraphRepn, &result->graph);
			if (result->graph) {
				result->read = lookup->read;
				cvdebug() <<"found "<<  lookup->type_name << "\n";
				VistaIONextAttr(pos);
				return true;
			}
		}
		++lookup;
	}

	cvwarn() <<"I didn't find a known  graph attribute, will try generic graph\n";

	lookup =  vertexio_lookup;

	VistaIOFirstAttr(list, pos);
	while (VistaIOAttrExists(pos)) {
		if (VistaIOGetAttrRepn(pos) == VistaIOGraphRepn){
			cvdebug() <<"Got a graph\n";
			VistaIOGetAttrValue(pos, NULL, VistaIOGraphRepn, &result->graph);
			TVNodeType<float> *node = (TVNodeType<float> *)VistaIOGraphFirstNode(result->graph);
			while (lookup->simbio_type  && lookup->simbio_type != node->type)
				++lookup;

			cvdebug() <<"found "<<  lookup->type_name << "\n";

			result->read = lookup->read;

			VistaIONextAttr(pos);
			break;
		}
		VistaIONextAttr(pos);
	}
	return lookup->simbio_type != 0;
}


static VistaIOGraph lookup_triangle_graph(VistaIOAttrList list, VistaIOAttrListPosn *pos)
{
	VistaIOAttrListPosn save_pos = *pos;
	VistaIOGraph result = NULL;
	if (VistaIOLookupAttr(list,"Triangles",pos)) {
		VistaIOGetAttrValue(pos, NULL, VistaIOGraphRepn, &result);
		VistaIONextAttr(pos);
	}else{
		*pos = save_pos;
		cvdebug() <<"Didn't find an attribute called 'triangles', will try generic graph\n";
		while (VistaIOAttrExists(pos)) {
			if (VistaIOGetAttrRepn(pos) == VistaIOGraphRepn){
				cvdebug() <<"Got a graph\n";
				VistaIOGetAttrValue(pos, NULL, VistaIOGraphRepn, &result);
				VistaIONextAttr(pos);
				break;
			}
			VistaIONextAttr(pos);
		}
	}
	return result;
}

static CTriangleMesh *do_load_mesh(VistaIOAttrList list)
{
	VistaIOAttrListPosn pos;
	vertex_reader_t vertex_source;

	VistaIOGraph triangle_graph = NULL;

	if ( ! lookup_vertex_graph(list,&pos,&vertex_source) ) {
		cvwarn() <<"Didn't find a graph type attribute\n";
		return NULL;
	}
	// pos is now behind the vertex - graph

	if ((triangle_graph = lookup_triangle_graph(list,&pos) ) == NULL) {
		cvwarn() <<"Unable to find triangles\n";
		return NULL;
	}

	int v_size = VistaIOGraphNNodes(vertex_source.graph);
	int num_faces = VistaIOGraphNNodes(triangle_graph);

	if (VistaIONodeRepn(vertex_source.graph) != VistaIOFloatRepn) {
		cvwarn() <<"Sorry, only float vertex coordinates supported\n";
		return NULL;
	}

	cvdebug() << "Create mesh with " << v_size << " vertices and " << num_faces << " faces.\n";



	return vertex_source.read(vertex_source.graph, triangle_graph);
}

PTriangleMesh CVistaMeshIO::do_load(string const &  filename) const
{


	CInputFile file(filename);
	if (!file)
		return PTriangleMesh();

	VistaIOAttrList list= VistaIOReadFile(file,0);

	CTriangleMesh *result = NULL;
	if (list) {
		cvdebug() << "Got a valid vista file\n";
		VistaIOAttrList nested_list;
		VistaIOAttrListPosn pos;

		if (VistaIOLookupAttr(list,"mesh",&pos)) {
			VistaIOGetAttrValue(&pos,NULL,VistaIOAttrListRepn,&nested_list);
		}else{
			cvdebug() << "Let's put meshes in a nested list!\n";
			nested_list = list;
		}

		result = do_load_mesh(nested_list);

		VistaIODestroyAttrList(list);
	}

	return PTriangleMesh(result);
}


static VistaIOGraph create_triangle_graph_and_link(const CTriangleMesh& mesh, VistaIOGraph vertex_graph)
{
	VistaIOGraph result = VistaIOCreateGraph(mesh.triangle_size(), 4, VistaIOLongRepn, 0);

	VistaIOSetAttr(VistaIOGraphAttrList(result), "primitive_interp",  NULL, VistaIOStringRepn, "surface");
	VistaIOSetAttr(VistaIOGraphAttrList(result), "implicit_links", NULL, VistaIOStringRepn, "true");
	VistaIOSetAttr(VistaIOGraphAttrList(result), "component_interp", NULL, VistaIOStringRepn, "primitive");

	CTriangleMesh::const_triangle_iterator ti = mesh.triangles_begin();
	CTriangleMesh::const_triangle_iterator te = mesh.triangles_end();

	TTriangelType node;
	node.type = 3;
	int pos = 1;

	while (ti != te) {
		node.t = *ti++;
		++node.t.x;
		++node.t.y;
		++node.t.z;
		VistaIOGraphAddNodeAt(result,(VistaIONodestruct*)&node,pos++);
		VistaIOGraphLinkNodesBi(vertex_graph, node.t.x, node.t.y );
		VistaIOGraphLinkNodesBi(vertex_graph, node.t.y, node.t.z );
		VistaIOGraphLinkNodesBi(vertex_graph, node.t.z, node.t.x );
	}

	return result;
}


bool CVistaMeshIO::do_save(string const &  filename, const CTriangleMesh& mesh)const
{
	bool result = false;

	COutputFile outf(filename);
	if (!outf)
		return false;

	VistaIOGraph vertex_graph;
	VistaIOGraph triangle_graph;
	int  type = mesh.get_available_data();

	cvdebug() << "available: " << type << "\n";

	VistaIOAttrList list = VistaIOCreateAttrList();

	vertexio_t *lookup =  vertexio_lookup;

	while (lookup->data_avail && lookup->data_avail != type)
		++lookup;

	if (!lookup->data_avail) {
		cverr() << "Fatal: unknown data in mesh\n";
		return false;
	}

	cvdebug() << "will save " << lookup->type_name << "\n";
	
	vertex_graph = lookup->create(mesh);

	if (!vertex_graph) {
		cverr() << "Fatal: unable to create vertex graph\n";
		return false;
	}



	VistaIOSetAttr(VistaIOGraphAttrList(vertex_graph), "component_interp", NULL, VistaIOStringRepn, "vertex");
	VistaIOSetAttr(list, lookup->type_name, NULL, VistaIOGraphRepn, vertex_graph);

	triangle_graph = create_triangle_graph_and_link(mesh, vertex_graph);
	if (!triangle_graph)
		VistaIODestroyAttrList(list);

	VistaIOSetAttr(list, "Triangles", NULL, VistaIOGraphRepn, triangle_graph);

	result = (VistaIOWriteFile(outf, list) == TRUE);
	VistaIODestroyAttrList(list);

	return result;
}

NS_END
