/**
 * $Id: LOD_MeshPrimitives.cpp,v 1.3 2002/11/25 09:52:52 mein Exp $
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * 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. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * 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.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

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

#include "LOD_MeshPrimitives.h"

#include "MT_assert.h"
#include "LOD_MeshException.h"
#include <algorithm>

using namespace std;

// Vertex Methods
/////////////////

LOD_Vertex::
LOD_Vertex(
) :
	pos (MT_Vector3()),
	m_select_tag(false)
{
};

	bool
LOD_Vertex::
RemoveEdge(
	LOD_EdgeInd e
){

	vector<LOD_EdgeInd>::iterator result = find(m_edges.begin(),m_edges.end(),e);
	if (result == m_edges.end()) {
		return false;
	}
	LOD_EdgeInd last = m_edges.back();
	m_edges.pop_back();
	if (m_edges.empty()) return true;

	*result = last;
	return true;	
};	

	void
LOD_Vertex::
AddEdge(
	LOD_EdgeInd e
){
	m_edges.push_back(e);
};

	void
LOD_Vertex::
SwapEdge(
	LOD_EdgeInd e_old,
	LOD_EdgeInd e_new
){

	vector<LOD_EdgeInd>::iterator result = 
		find(m_edges.begin(),m_edges.end(),e_old);
	if (result == m_edges.end()) {
		MT_assert(false);
		LOD_MeshException e(LOD_MeshException::e_search_error);
		throw(e);	
	}
	
	*result = e_new;
};

	bool
LOD_Vertex::
SelectTag(
) const {
	return m_select_tag;
};

	void
LOD_Vertex::
SetSelectTag(
	bool tag	
){
	m_select_tag = tag;
};

	bool
LOD_Vertex::
Degenerate(
){
	return m_edges.empty();
}

	void
LOD_Vertex::
CopyPosition(
	float *float_ptr
){
	pos.getValue(float_ptr);
}



// Edge Methods
///////////////

LOD_Edge::
LOD_Edge (
) {
	m_verts[0] = m_verts[1] = LOD_VertexInd::Empty();
	m_faces[0] = m_faces[1] = LOD_FaceInd::Empty();
}
		
	bool 
LOD_Edge::
operator == (
	LOD_Edge & rhs
) {
	// edges are the same if their vertex indices are the 
	// same!!! Other properties are not checked 

	int matches = 0;

	if (this->m_verts[0] == rhs.m_verts[0]) {
		++matches;
	}
	if (this->m_verts[1] == rhs.m_verts[0]) {
		++matches;
	}
	if (this->m_verts[0] == rhs.m_verts[1]) {
		++matches;
	}
	if (this->m_verts[1] == rhs.m_verts[1]) {
		++matches;
	}
	
	if (matches >= 2) {
		return true;
	}
	return false;
}

// Elementary helper methods
////////////////////////////

	LOD_FaceInd
LOD_Edge::
OpFace(
	LOD_FaceInd f
) const {
	if (f == m_faces[0]) {
		return m_faces[1];
	} else 
	if (f == m_faces[1]) {
		return m_faces[0];
	} else {
		MT_assert(false);
		LOD_MeshException e(LOD_MeshException::e_search_error);
		throw(e);	

		return LOD_FaceInd::Empty();
	}
}	

	void
LOD_Edge::
SwapFace(
	LOD_FaceInd old_f,
	LOD_FaceInd new_f
) {
	if (old_f == m_faces[0]) {
		m_faces[0] = new_f;
	} else 
	if (old_f == m_faces[1]) {
		m_faces[1] = new_f;
	} else {
		MT_assert(false);

		LOD_MeshException e(LOD_MeshException::e_search_error);
		throw(e);	
	}
}


// return the half edge face - the half edge is defined
// by the {vertex,edge} tuple. 

	LOD_FaceInd
LOD_Edge::
HalfEdgeFace(
	LOD_VertexInd vi
){
	if (vi == m_verts[0]) return m_faces[0];
	if (vi == m_verts[1]) return m_faces[1];
	MT_assert(false);
	
	LOD_MeshException e(LOD_MeshException::e_search_error);
	throw(e);	

	return LOD_FaceInd::Empty();
}	


	LOD_VertexInd
LOD_Edge::
OpVertex(
	LOD_VertexInd vi
) {
	if (vi == m_verts[0]) return m_verts[1];
	if (vi == m_verts[1]) return m_verts[0];
	MT_assert(false);

	LOD_MeshException e(LOD_MeshException::e_search_error);
	throw(e);	

	return LOD_VertexInd::Empty();
}

// replace the vertex v_old with vertex v_new
// error if v_old is not one of the original vertices

	void
LOD_Edge::
SwapVertex(
	LOD_VertexInd v_old,
	LOD_VertexInd v_new
) {
	if (v_old == m_verts[0]) {
		m_verts[0] = v_new;
	} else
	if (v_old == m_verts[1]) {
		m_verts[1] = v_new;
	} else {

		MT_assert(false);

		LOD_MeshException e(LOD_MeshException::e_search_error);
		throw(e);	
	}
	if(m_verts[0] == m_verts[1]) {
		MT_assert(false);

		LOD_MeshException e(LOD_MeshException::e_non_manifold);
		throw(e);	
	}

}			

	bool
LOD_Edge::
SelectTag(
) const {
	return bool(m_verts[1].Tag() & 0x1);
};

	void
LOD_Edge::
SetSelectTag(
	bool tag
) {
	m_verts[1].SetTag(int(tag));
};

	int
LOD_Edge::
OpenTag(
) const {
	return m_faces[0].Tag();
}

	void
LOD_Edge::
SetOpenTag(
	int tag
) {
	m_faces[0].SetTag(tag);
}

	bool
LOD_Edge::
Degenerate(
) const {
	return (
		(m_faces[0].IsEmpty() && m_faces[1].IsEmpty()) ||
		(m_verts[0] == m_verts[1])
	);
};

// TriFace Methods
//////////////////

LOD_TriFace::
LOD_TriFace(
) {
	m_verts[0] = m_verts[1] = m_verts[2] = LOD_VertexInd::Empty();
}

// Elementary helper methods
////////////////////////////

	void
LOD_TriFace::
SwapVertex(
	LOD_VertexInd old_v,
	LOD_VertexInd new_v
) {
	// could save branching here...

	if (m_verts[0] == old_v) {
		m_verts[0] = new_v;
	} else 
	if (m_verts[1] == old_v) {
		m_verts[1] = new_v;
	} else 
	if (m_verts[2] == old_v) {
		m_verts[2] = new_v;
	} else {
		MT_assert(false);

		LOD_MeshException excep(LOD_MeshException::e_search_error);
		throw(excep);	
	}
}

	bool
LOD_TriFace::
SelectTag(
) const {
	return bool(m_verts[1].Tag() & 0x1);
};

	void
LOD_TriFace::
SetSelectTag(
	bool tag
) {
	m_verts[1].SetTag(int(tag));
};

	int
LOD_TriFace::
OpenTag(
) {
	return m_verts[2].Tag();
}

	void
LOD_TriFace::
SetOpenTag(
	int tag
) {
	m_verts[2].SetTag(tag);
}

	bool
LOD_TriFace::
Degenerate(
) {

	return (
		(m_verts[0] == m_verts[1]) ||
		(m_verts[1] == m_verts[2]) ||
		(m_verts[2] == m_verts[0]) 
	);
}

	void
LOD_TriFace::
CopyVerts(
	int * index_ptr
){
	index_ptr[0] = m_verts[0];
	index_ptr[1] = m_verts[1];
	index_ptr[2] = m_verts[2];
};









