/**
 * $Id: verse_geometry_node.c 14444 2008-04-16 22:40:48Z hos $
 *
 * ***** BEGIN GPL 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.
 *
 * 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.
 *
 * Contributor(s): Jiri Hnidek.
 *
 * ***** END GPL LICENSE BLOCK *****
 */

#ifdef WITH_VERSE

#include <string.h>

#include "MEM_guardedalloc.h"

#include "DNA_listBase.h"

#include "BLI_dynamiclist.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"

#include "BKE_verse.h"
#include "BKE_utildefines.h"

#include "BIF_verse.h"

#include "verse.h"

/* function prototypes of static functions */

/* test functions for callback functions */
static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3);

/* callback functions */
static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, 	real32 y, real32 z);
static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id);
static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id);
static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);

/* other static functions */

static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface);
static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert);
static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface);
static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer);

static void send_verse_face(struct VerseFace *vface);

static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z);
static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);

static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface);
static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert);
static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert);
static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface);
static void increase_verse_verts_references(struct VerseFace *vface);
static void recalculate_verseface_normals(struct VNode *vnode);

/* verse edge functions */
static VerseEdge* find_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
static void insert_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
static void remove_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
static void remove_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
static void add_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
static void update_edgehash_of_deleted_verseface(struct VNode *vnode, struct VerseFace *vface);
static void update_edgehash_of_changed_verseface(struct VNode *vnode, struct VerseFace *vface, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
static void update_edgehash_of_new_verseface(struct VNode *vnode, uint32 v0, uint32 v1, uint32 v2, uint32 v3);

/*
 * recalcute normals of all VerseFaces
 */
static void recalculate_verseface_normals(VNode *vnode)
{
	struct VLayer *vert_layer, *face_layer;
	struct VerseFace *vface;
	struct VerseVert *vvert;

	if(vnode->type != V_NT_GEOMETRY) return;

	vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
	face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);

	vvert = vert_layer->dl.lb.first;
	while(vvert) {
		vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
		vvert = vvert->next;
	}

	vface = face_layer->dl.lb.first;
	while(vface) {
		/* calculate face normals */
		if(vface->vvert3) {
			CalcNormFloat4(vface->vvert0->co, vface->vvert1->co,
					vface->vvert2->co, vface->vvert3->co, vface->no);
			VecAddf(vface->vvert3->no, vface->vvert3->no, vface->no);
		}
		else
			CalcNormFloat(vface->vvert0->co, vface->vvert1->co,
					vface->vvert2->co, vface->no);

		/* calculate vertex normals ... it is averadge of all face normals using the vertex */
		VecAddf(vface->vvert0->no, vface->vvert0->no, vface->no);
		VecAddf(vface->vvert1->no, vface->vvert1->no, vface->no);
		VecAddf(vface->vvert2->no, vface->vvert2->no, vface->no);

		vface = vface->next;
	}

	/* we have to normalize all vertex normals */
	vvert = vert_layer->dl.lb.first;
	while(vvert) {
		Normalize(vvert->no);
		vvert = vvert->next;
	}
}

/*
 * add created item to the queue and send it if possible
 */
void add_item_to_send_queue(ListBase *lb, void *item, short type)
{
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct VerseVert *vvert;
	struct VerseFace *vface;

	/* this prevent from adding duplicated faces */
	if(type==VERSE_FACE) {
		struct Link *link = (Link*)lb->first;
		while(link) {
			if(link==item) {
				if(((VerseFace*)item)->flag & FACE_SENT) {
/*					printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/
					((VerseFace*)item)->flag |= FACE_OBSOLETE;
				}
				return;
			}
			link = link->next;
		}
	}

	/* add item to sending queue (two way dynamic list) */
	BLI_addtail(lb, item);

	/* send item, when it is possible */
	switch (type) {
		case VERSE_NODE:	/* only first node in queue can be sent */
			if(lb->first==lb->last)	
				send_verse_node((VNode*)item);
			break;
		case VERSE_LINK:	/* both object between have to exist */
			if(((VLink*)item)->flag & LINK_SEND_READY)
				send_verse_link((VLink*)item);
			break;
		case VERSE_LAYER:
			if(((VLayer*)item)->vnode->flag & NODE_RECEIVED)
				send_verse_layer((VLayer*)item);
			break;
		case VERSE_VERT:
			if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED)
				send_verse_vertex((VerseVert*)item);
			break;
		case VERSE_FACE:	/* all vertexes of face have to be received */
			if(((VerseFace*)item)->flag & FACE_SEND_READY)
				send_verse_face((VerseFace*)item);
			break;
		case VERSE_TAG:
			send_verse_tag((VTag*)item);
			break;
		case VERSE_TAG_GROUP:
			send_verse_taggroup((VTagGroup*)item);
			break;
		case VERSE_VERT_UINT32:	/* parent item has to exist */
			vnode = (((uint32_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
			vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
			if(vvert != NULL)
				send_verse_vert_uint32((uint32_item*)item, type);
			break;
		case VERSE_VERT_REAL32:	/* parent item has to exist */
			vnode = (((real32_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
			vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
			if( vvert != NULL)
				send_verse_vert_real32((real32_item*)item, type);
			break;
		case VERSE_VERT_VEC_REAL32:	/* parent item has to exist */
			vnode = (((vec_real32_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
			vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((vec_real32_item*)item)->id );
			if(vvert != NULL)
				send_verse_vert_vec_real32((vec_real32_item*)item, type);
			break;
		case VERSE_FACE_UINT8:	/* parent item has to exist */
			vnode = (((uint8_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
			vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint8_item*)item)->id );
			if(vface != NULL)
				send_verse_face_uint8((uint8_item*)item, type);
			break;
		case VERSE_FACE_UINT32:	/* parent item has to exist */
			vnode = (((uint32_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
			vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
			if(vface != NULL)
				send_verse_face_uint32((uint32_item*)item, type);
			break;
		case VERSE_FACE_REAL32:	/* parent item has to exist */
			vnode = (((real32_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
			vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
			if(vface != NULL)
				send_verse_face_real32((real32_item*)item, type);
			break;
		case VERSE_FACE_QUAT_UINT32:	/* parent item has to exist */
			vnode = (((quat_uint32_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
			vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_uint32_item*)item)->id );
			if(vface != NULL)
				send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type);
			break;
		case VERSE_FACE_QUAT_REAL32:	/* parent item has to exist */
			vnode = (((quat_real32_item*)item)->vlayer)->vnode;
			vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
			vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_real32_item*)item)->id );
			if(vface != NULL)
				send_verse_face_corner_quat_real32((quat_real32_item*)item, type);
			break;
	}
}

/*
 * return VerseLayer with certain content (vertexes, polygons, in the
 * future: weight, red color, etc.)
 */
VLayer* find_verse_layer_type(VGeomData *geom, short content)
{
	struct VLayer *vlayer = NULL;
	
	switch(content) {
		case VERTEX_LAYER:
			/* VERTEX_LAYER equals 0 and vertex layer is
			 * always in 1st layer */
			vlayer = geom->layers.da.items[VERTEX_LAYER];
			break;
		case POLYGON_LAYER:
			/* POLYGON_LAYER equals 1 and vertex layer is
			 * always in 2nd layer */
			vlayer = geom->layers.da.items[POLYGON_LAYER];
			break;
	}

	return vlayer;
}

/*
 * increase references of VerseVerts of new VerseFace
 */
static void increase_verse_verts_references(VerseFace *vface)
{
	if(vface->vvert0) vface->vvert0->counter++;
	if(vface->vvert1) vface->vvert1->counter++;
	if(vface->vvert2) vface->vvert2->counter++;
	if(vface->vvert3) vface->vvert3->counter++;
}

/*
 * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed
 * then this VerseFace is only removed from list of orphans)
 */
static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface)
{
	/* remove vface from list of orphans */
	BLI_remlink(&(vlayer->orphans), vface);
	/* increase references of all vertexes beying part of this face*/
	increase_verse_verts_references(vface);

	if(vface->flag & FACE_RECEIVED) {
		/* set up vface flag */
		vface->flag &= ~FACE_RECEIVED;
		/* move vface to dynamic list of faces */
		BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
		/* recalculate all vertex and faces normals */
		recalculate_verseface_normals(vnode);
		/* post create action (change local data) */
		((VGeomData*)vnode->data)->post_polygon_create(vface);
	}
	else if(vface->flag & FACE_CHANGED) {
		/* set up vface flag */
		vface->flag &= ~FACE_CHANGED;
		/* move vface to dynamic list of faces */
		BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
		/* recalculate all vertex and faces normals */
		recalculate_verseface_normals(vnode);
		/* post create action (change local data) */
		((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
	}
}

/*
 * find all VerseFaces waiting in queue, which needs id of new VerseVert
 */
static void find_unsent_faces(VNode *vnode, VerseVert *vvert)
{
	VLayer *vlayer;
	VerseFace *vface, *next_vface;

	vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);

	if(vlayer) {
		vface = vlayer->queue.first;
		while(vface) {
			next_vface = vface->next;
			if(vface->vvert0==vvert) {
				vface->v0 = vvert->id;
				vface->counter--;
			}
			else if(vface->vvert1==vvert) {
				vface->v1 = vvert->id;
				vface->counter--;
			}
			else if(vface->vvert2==vvert) {
				vface->v2 = vvert->id;
				vface->counter--;
			}
			else if(vface->vvert3==vvert){
				vface->v3 = vvert->id;
				vface->counter--;
			}

			if(vface->counter<1 && !(vface->flag & FACE_SENT))
				send_verse_face(vface);

			vface = next_vface;
		}
	}
}

/*
 * find all VerseFace orphans, which needs incoming VerseVert
 */
static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert)
{
	VLayer *vlayer;
	VerseFace *vface, *next_vface;
	unsigned int vertex_id = vvert->id;

	vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);

	if(vlayer) {
		vface = vlayer->orphans.first;
		while(vface){
			next_vface = vface->next;
			if(vface->v0 == vertex_id) {
				vface->vvert0 = vvert;
				vface->counter--;
			}
			else if(vface->v1 == vertex_id) {
				vface->vvert1 = vvert;
				vface->counter--;
			}
			else if(vface->v2 == vertex_id) {
				vface->vvert2 = vvert;
				vface->counter--;
			}
			else if(vface->v3 == vertex_id) {
				vface->vvert3 = vvert;
				vface->counter--;
			}
			if(vface->counter<1) {
				/* moving VerseFace orphan to dlist */
				move_face_orphan_to_dlist(vnode, vlayer, vface);
			}
			vface = next_vface;
		}
	}
}

/*
 * return number of VerseVerts missing to incoming VerseFace, set up pointers
 * at VerseVerts
 */
static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface)
{
	struct VLayer *vert_layer;
	struct VerseVert *vvert; 
	int counter=0;

	vert_layer = find_verse_layer_type(geom, VERTEX_LAYER);

	if(vface->v0 != -1){
		vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0);
		if(vvert==NULL) counter++;
		else vface->vvert0 = vvert;
	}
	if(vface->v1 != -1){
		vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1);
		if(vvert==NULL) counter++;
		else vface->vvert1 = vvert;
	}
	if(vface->v2 != -1){
		vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2);
		if(vvert==NULL) counter++;
		else vface->vvert2 = vvert;
	}
	if(vface->v3 != -1){
		vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3);
		if(vvert==NULL) counter++;
		else vface->vvert3 = vvert;
	}
	
	return counter;
}

/*
 * try to find changed VerseFace in sending queue
 */
static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id)
{
	struct VerseFace *vface = vlayer->queue.first;

	while(vface){
		if(vface->id == polygon_id && vface->flag & FACE_CHANGED) {
			return vface;
		}
		vface = vface->next;
	}
	return NULL;
}

/*
 * try to find VerseFace in queue
 */
static VerseFace* find_verse_face_in_queue(
		VLayer *vlayer,
		VNodeID node_id,
		uint32 polygon_id,
		uint32 v0,
		uint32 v1,
		uint32 v2,
		uint32 v3)
{
	struct VerseFace *vface = vlayer->queue.first;

	while(vface){
		if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){
			vface->id = polygon_id;
			vface->vlayer = vlayer;
			return vface;
		}
		vface = vface->next;
	}
	return NULL;
}

/*
 * try to find VerseVert in queue
 */
static VerseVert* find_verse_vert_in_queue(
		VLayer *vlayer,
		VNodeID node_id,
		uint32 vertex_id,
		real32 x,
		real32 y,
		real32 z)
{
	struct VerseVert *vvert = vlayer->queue.first;

	while(vvert){
		if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z))
		{
			vvert->id = vertex_id;
			vvert->vlayer = vlayer;

			return vvert;
		}
		vvert = vvert->next;
	}

	return NULL;
}


/*
 * send quat of float values to verse server (4x32 bits)
 */
void send_verse_face_corner_quat_real32(quat_real32_item *item, short type)
{
	verse_send_g_polygon_set_corner_real32(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value[0],
			item->value[1],
			item->value[2],
			item->value[3]);
}

/*
 * send quat of unsigned int values to verse server (4x32 bits)
 */
void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type)
{
	verse_send_g_polygon_set_corner_uint32(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value[0],
			item->value[1],
			item->value[2],
			item->value[3]);
}

/*
 * send float value (32 bits) to verse server
 */
void send_verse_face_real32(real32_item *item, short type)
{
	verse_send_g_polygon_set_face_real32(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value);
}

/*
 * send unsigned integer (32 bits) to verse server
 */
void send_verse_face_uint32(uint32_item *item, short type)
{
	verse_send_g_polygon_set_face_uint32(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value);
}

/*
 * send unsigned char (8 bits) to verse server
 */
void send_verse_face_uint8(uint8_item *item, short type)
{
	verse_send_g_polygon_set_face_uint8(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value);
}

/*
 * send vector of float values to verse server (3x32 bits)
 */
void send_verse_vert_vec_real32(vec_real32_item *item, short type)
{
	verse_send_g_vertex_set_xyz_real32(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value[0],
			item->value[1],
			item->value[2]);
}

/*
 * send float value (32 bits) to verse server
 */
void send_verse_vert_real32(real32_item *item, short type)
{
	verse_send_g_vertex_set_real32(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value);
}

/*
 * send unsigned integer (32 bits) to verse server
 */
void send_verse_vert_uint32(uint32_item *item, short type)
{
	verse_send_g_vertex_set_uint32(
			item->vlayer->vnode->id,
			item->vlayer->id,
			item->id,
			item->value);
}

/*
 * send delete command to verse server
 */
void send_verse_vertex_delete(VerseVert *vvert)
{
	verse_session_set(vvert->vlayer->vnode->session->vsession);

	vvert->flag |= VERT_OBSOLETE;
	
	verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id);
}

/*
 * send VerseLayer to verse server
 */
void send_verse_layer(VLayer *vlayer)
{
	verse_session_set(vlayer->vnode->session->vsession);

	verse_send_g_layer_create(
			vlayer->vnode->id,
			vlayer->id,
			vlayer->name,
			vlayer->type,
			vlayer->def_int,
			vlayer->def_real);
}

/* 
 * send VerseVert to verse server
 */
void send_verse_vertex(VerseVert *vvert)
{
	/* new vertex position will not be sent, when vertex was deleted */
	if(vvert->flag & VERT_OBSOLETE) return;
	
	verse_session_set(vvert->vlayer->vnode->session->vsession);

	verse_send_g_vertex_set_xyz_real32(
			vvert->vlayer->vnode->id,
			vvert->vlayer->id,
			vvert->id,
			vvert->co[0],
			vvert->co[2],
			-vvert->co[1]);
}

/*
 * send delete command to verse server
 */
void send_verse_face_delete(VerseFace *vface)
{
	verse_session_set(vface->vlayer->vnode->session->vsession);

	vface->flag |= FACE_DELETED;

	verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id);
}

/*
 * send VerseFace to verse server
 */
static void send_verse_face(VerseFace *vface)
{
	verse_session_set(vface->vlayer->vnode->session->vsession);

	vface->flag |= FACE_SENT;

	if(vface->v3 != -1) {
		verse_send_g_polygon_set_corner_uint32(
				vface->vlayer->vnode->id,
				vface->vlayer->id,
				vface->id,
				vface->v0,
				vface->v3,	/* verse use clock-wise winding */
				vface->v2,
				vface->v1);	/* verse use clock-wise winding */
	}
	else {
		verse_send_g_polygon_set_corner_uint32(
				vface->vlayer->vnode->id,
				vface->vlayer->id,
				vface->id,
				vface->v0,
				vface->v2,	/* verse use clock-wise winding */
				vface->v1,	/* verse use clock-wise winding */
				vface->v3);
	}
}

/*
 * free VerseVert
 */
static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert)
{
	/* free VerseVert */
	BLI_freelinkN(&(vlayer->orphans), vvert);
}

/*
 * free VerseFace (and blender face)
 */
static void free_verse_face(VLayer *vlayer, VerseFace *vface)
{
	/* free VerseFace */
	BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id);
}

/*
 * free VerseLayer data
 */
static void free_verse_layer_data(VNode *vnode, VLayer *vlayer)
{
	struct VerseFace *vface;
	struct VerseVert *vvert;

	/* set up EditVert->vvert and EditFace->vface pointers to NULL */
	switch(vlayer->content) {
		case VERTEX_LAYER:
			vvert = (VerseVert*)vlayer->dl.lb.first;
			while(vvert) {
				((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert);
				vvert = vvert->next;
			}
			break;
		case POLYGON_LAYER:
			vface = (VerseFace*)vlayer->dl.lb.first;
			while(vface) {
				((VGeomData*)vnode->data)->post_polygon_free_constraint(vface);
				vface = vface->next;
			}
			break;
		default:
			break;
	}
	/* free Verse Layer name */
	MEM_freeN(vlayer->name);
	/* destroy VerseLayer data (vertexes, polygons, etc.) */
	BLI_dlist_destroy(&(vlayer->dl));
	/* free unsent data */
	BLI_freelistN(&(vlayer->queue));
	/* free orphans */
	BLI_freelistN(&(vlayer->orphans));
}

/*
 * free all unneeded VerseVerts waiting for deleting
 */
static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface)
{
	struct VLayer *vert_vlayer;

	/* find layer containing vertexes */
	vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);

	/* free all "deleted" VerseVert waiting for deleting this VerseFace */
	
	if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
		((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
		free_verse_vertex(vert_vlayer, vface->vvert0);
		vface->vvert0 = NULL;
	}
	if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
		((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
		free_verse_vertex(vert_vlayer, vface->vvert1);
		vface->vvert1 = NULL;
	}
	if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
		((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
		free_verse_vertex(vert_vlayer, vface->vvert2);
		vface->vvert2 = NULL;
	}
	if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
		((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
		free_verse_vertex(vert_vlayer, vface->vvert3);
		vface->vvert3 = NULL;
	}
}

/*
 * This function create VerseVert and returns pointer on this vertex
 */
VerseVert* create_verse_vertex(
		VLayer *vlayer,
		uint32 vertex_id,
		real32 x,
		real32 y,
		real32 z)
{
	struct VerseVert *vvert;

	vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert");
	
	/* set up pointer on parent node */
	vvert->vlayer = vlayer;
	vvert->id = vertex_id;
	/* position */
	vvert->co[0] = x;
	vvert->co[1] = y;
	vvert->co[2] = z;
	/* normal */
	vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
	/* blender internals */
	vvert->flag = 0;
	vvert->counter = 0;
	vvert->vertex = NULL;

	/* increase layer counter of vertexes */
	vlayer->counter++;

	return vvert;
}

/*
 * this function creates fake VerseEdge and returns pointer at this edge
 */
VerseEdge *create_verse_edge(uint32 v0, uint32 v1)
{
	struct VerseEdge *vedge;

	vedge = (VerseEdge*)MEM_mallocN(sizeof(VerseEdge), "VerseEdge");

	vedge->v0 = v0;
	vedge->v1 = v1;
	vedge->counter = 0;

	return vedge;
}

/*
 * this function will create new VerseFace and will return pointer on such Face
 */
VerseFace* create_verse_face(
		VLayer *vlayer,
		uint32 polygon_id,
		uint32 v0,
		uint32 v1,
		uint32 v2,
		uint32 v3)
{
	struct VerseFace *vface;

	vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace");

	/* verse data */
	vface->vlayer = vlayer;
	vface->id = polygon_id;

	vface->vvert0 = NULL;
	vface->vvert1 = NULL;
	vface->vvert2 = NULL;
	vface->vvert3 = NULL;

	vface->v0 = v0;
	vface->v1 = v1;
	vface->v2 = v2;
	vface->v3 = v3;

	/* blender data */
	vface->face = NULL;
	vface->flag = 0;
	vface->counter = 4;

	/* increase layer counter of faces */
	vlayer->counter++;
	
	return vface;
}

/*
 * create and return VerseLayer
 */
VLayer *create_verse_layer(
		VNode *vnode,
		VLayerID layer_id,
		const char *name,
		VNGLayerType type,
		uint32 def_integer,
		real64 def_real)
{
	struct VLayer *vlayer;

	/* add layer to the DynamicList */
	vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer");

	/* store all relevant info to the vlayer and set up vlayer */
	vlayer->vnode = vnode;
	vlayer->id = layer_id;
	vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name");
	strcpy(vlayer->name, name);
	vlayer->type = type;
	vlayer->def_int = def_integer;
	vlayer->def_real = def_real;

	if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0))
		vlayer->content = VERTEX_LAYER;
	else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1))
		vlayer->content = POLYGON_LAYER;
	else
		vlayer->content = -1;

	/* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/
	BLI_dlist_init(&(vlayer->dl));
	/* initialization of queue of layer */
	vlayer->queue.first = vlayer->queue.last = NULL;
	/* initialization of list of orphans */
	vlayer->orphans.first = vlayer->orphans.last = NULL;
	/* initialize number of sent items (vertexes, faces, etc) */
	vlayer->counter = 0;
	/* initialize flag */
	vlayer->flag = 0;

	/* set up methods */
	vlayer->post_layer_create = post_layer_create;
	vlayer->post_layer_destroy = post_layer_destroy;

	return vlayer;
}

/*
 * create geometry data
 */
VGeomData *create_geometry_data(void)
{
	struct VGeomData *geom;

	geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData");
	BLI_dlist_init(&(geom->layers));
	geom->vlink = NULL;
	geom->queue.first = geom->queue.last = NULL;
	geom->mesh = NULL;
	geom->editmesh = NULL;

	/* initialize list of fake verse edges and initialize verse edge hash */
	geom->edges.first = geom->edges.last = NULL;
	geom->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");

	/* set up methods */
	geom->post_vertex_create = post_vertex_create;
	geom->post_vertex_set_xyz = post_vertex_set_xyz;
	geom->post_vertex_delete = post_vertex_delete;
	geom->post_vertex_free_constraint = post_vertex_free_constraint;
	geom->post_polygon_create = post_polygon_create;
	geom->post_polygon_set_corner = post_polygon_set_corner;
	geom->post_polygon_delete = post_polygon_delete;
	geom->post_polygon_free_constraint = post_polygon_free_constraint;
	geom->post_geometry_free_constraint = post_geometry_free_constraint;
	geom->post_polygon_set_uint8 = post_polygon_set_uint8;

	return geom;
}

/* Create item containing 4 floats */
static quat_real32_item *create_quat_real32_item(
		VLayer *vlayer,
		uint32 item_id,
		real32 v0,
		real32 v1,
		real32 v2,
		real32 v3)
{
	struct quat_real32_item *item;

	item = (quat_real32_item*)MEM_mallocN(sizeof(quat_real32_item), "quat_real32_item");

	item->vlayer = vlayer;
	item->id = item_id;
	item->value[0] = v0;
	item->value[1] = v1;
	item->value[2] = v2;
	item->value[3] = v3;

	return item;
}

/* Create item containing 1 float */
static real32_item *create_real32_item(VLayer *vlayer, uint32 item_id, real32 value)
{
	struct real32_item *item;

	item = (real32_item*)MEM_mallocN(sizeof(real32_item), "real32_item");

	item->vlayer = vlayer;
	item->id = item_id;
	item->value = value;

	return item;
}

/* Create item containing 1 integer */
static uint32_item *create_uint32_item(VLayer *vlayer, uint32 item_id, uint32 value)
{
	struct uint32_item *item;

	item = (uint32_item*)MEM_mallocN(sizeof(uint32_item), "uint32_item");

	item->vlayer = vlayer;
	item->id = item_id;
	item->value = value;

	return item;
}

/* Create item containing 1 byte */
static uint8_item *create_uint8_item(VLayer *vlayer, uint32 item_id, uint8 value)
{
	struct uint8_item *item;

	item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item");

	item->vlayer = vlayer;
	item->id = item_id;
	item->value = value;

	return item;
}

/*
 * callback function: vertex crease was set
 */
static void cb_g_crease_set_vertex(
		void *user_data,
		VNodeID node_id,
		const char *layer,
		uint32 def_crease)
{
}

/*
 * we have to test corretness of incoming data from verse server
 * no two vertexes can have the same index
 */
static char test_polygon_set_corner_uint32(
		uint32 v0,
		uint32 v1,
		uint32 v2,
		uint32 v3)
{
	if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3))
		return 0;
	else
		return 1;
}

/*
 * try to find verse layer in sending queue of verse geometry node
 */
static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id)
{
	struct VLayer *vlayer;
	
	/* try to find verse layyer in sending queue */
	vlayer = ((VGeomData*)vnode->data)->queue.first;
	while(vlayer) {
		if(vlayer->id==layer_id) return vlayer;
		vlayer = vlayer->next;
	}

	return NULL;
}

/*
 * this function will find edge in hash table, hash function isn't too optimal (it needs
 * lot of memory for every verse node), but it works without any bug
 */
static VerseEdge* find_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
{
	struct HashVerseEdge *hve;

	if(((VGeomData*)vnode->data)->hash==NULL)
		((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");

	hve = ((VGeomData*)vnode->data)->hash + VEDHASH(v0, v1);;
	while(hve) {
		/* edge v0---v1 is the same edge as v1---v0 */
		if(hve->vedge && ((hve->vedge->v0==v0 && hve->vedge->v1==v1) || (hve->vedge->v0==v1 && hve->vedge->v1==v0))) return hve->vedge;
		hve = hve->next;
	}

	return NULL;
}

/*
 * insert hash of verse edge to hash table
 */
static void insert_verse_edgehash(VNode *vnode, VerseEdge *vedge)
{
	struct HashVerseEdge *first, *hve;

	if(((VGeomData*)vnode->data)->hash==NULL)
		((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");

	first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);

	if(first->vedge==NULL) {
		first->vedge = vedge;
	}
	else {
		hve = &(vedge->hash);
		hve->vedge = vedge;
		hve->next = first->next;
		first->next = hve;
	}
}

/*
 * remove hash of verse edge from hash table
 */
static void remove_verse_edgehash(VNode *vnode, VerseEdge *vedge)
{
	struct HashVerseEdge *first, *hve, *prev;

	hve = first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);

	while(hve) {
		if(hve->vedge == vedge) {
			if(hve==first) {
				if(first->next) {
					hve = first->next;
					first->vedge = hve->vedge;
					first->next = hve->next;
				}
				else {
					hve->vedge = NULL;
				}
			}
			else {
				prev->next = hve->next;
			}
			return;
		}
		prev = hve;
		hve = hve->next;
	}
}

/*
 * this function will try to remove existing fake verse edge, when this verse
 * edge is still used by some faces, then counter will be only decremented
 */
static void remove_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
{
	struct VerseEdge *vedge;

	vedge = find_verse_edge(vnode, v0, v1);
	if(vedge) {
		vedge->counter--;
		if(vedge->counter==0) {
			remove_verse_edgehash(vnode, vedge);
			BLI_freelinkN(&(((VGeomData*)vnode->data)->edges), vedge);
		}
	}
	else {
		printf("error: remove_verse_edge %d, %d\n", v0, v1);
	}
}

/*
 * this function will try to add new fake verse edge, when no such edge exist,
 * when such edge exist, then only counter of edge will be incremented
 */
static void add_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
{
	struct VerseEdge *vedge;

	vedge = find_verse_edge(vnode, v0, v1);
	if(!vedge) {
		if(v0!=v1) {
			vedge = create_verse_edge(v0, v1);
			BLI_addtail(&(((VGeomData*)vnode->data)->edges), vedge);
			insert_verse_edgehash(vnode, vedge);
		}
		else {
			printf("error:add_verse_edge: %d, %d\n", v0, v1);
			return;
		}
	}
	vedge->counter++;
}

/*
 * verse face was deleted ... update edge hash
 */
static void update_edgehash_of_deleted_verseface(VNode *vnode, VerseFace *vface)
{
	uint32 v0, v1, v2, v3;		/* verse vertex indexes of deleted verse face */
	
	v0 = vface->vvert0->id;
	v1 = vface->vvert1->id;
	v2 = vface->vvert2->id;
	v3 = vface->vvert3 ? vface->vvert3->id : -1;

	remove_verse_edge(vnode, v0, v1);
	remove_verse_edge(vnode, v1, v2);
	if(v3!=-1) {
		remove_verse_edge(vnode, v2, v3);
		remove_verse_edge(vnode, v3, v0);
	}
	else {
		remove_verse_edge(vnode, v2, v0);
	}
}

/*
 * existing verse face was changed ... update edge hash
 */
static void update_edgehash_of_changed_verseface(
		VNode *vnode,
		VerseFace *vface,
		uint32 v0,
		uint32 v1,
		uint32 v2,
		uint32 v3)
{
	uint32 ov0, ov1, ov2, ov3;	/* old indexes at verse vertexes*/
	
	ov0 = vface->vvert0->id;
	ov1 = vface->vvert1->id;
	ov2 = vface->vvert2->id;
	ov3 = vface->vvert3 ? vface->vvert3->id : -1;

	/* 1st edge */
	if(v0!=ov0 || v1!=ov1) {
		remove_verse_edge(vnode, ov0, ov1);
		add_verse_edge(vnode, v0, v1);
	}
	
	/* 2nd edge */
	if(v1!=ov1 || v2!=ov2) {
		remove_verse_edge(vnode, ov1, ov2);
		add_verse_edge(vnode, v1, v2);
	}

	/* 3rd edge */
	if(v2!=ov2 || v3!=ov3 || v0!=ov0) {
		if(ov3!=-1) {
			remove_verse_edge(vnode, ov2, ov3);
			if(v3!=-1) {
				add_verse_edge(vnode, v2, v3);		/* new 3rd edge (quat->quat) */
			}
			else {
				remove_verse_edge(vnode, ov3, ov0);	/* old edge v3,v0 of quat have to be removed */
				add_verse_edge(vnode, v2, v0);		/* new 3rd edge (quat->triangle) */	
			}
		}
		else {
			remove_verse_edge(vnode, ov2, ov0);
			if(v3!=-1) {
				add_verse_edge(vnode, v2, v3);		/* new 3rd edge (triangle->quat) */
			}
			else {
				add_verse_edge(vnode, v2, v0);		/* new 3rd edge (triangle->triangle) */
			}
		}
	}

	/* 4th edge */
	if(v3!=-1 && (v3!=ov3 || v0!=ov0)) {
		remove_verse_edge(vnode, ov3, ov0);
		add_verse_edge(vnode, v3, v0);
	}
}

/*
 * new verse face was created ... update list of edges and edge has
 */
static void update_edgehash_of_new_verseface(
		VNode *vnode,
		uint32 v0,
		uint32 v1,
		uint32 v2,
		uint32 v3)
{
	/* when edge already exists, then only its counter is incremented,
	 * look at commentary of add_verse_edge() function */
	add_verse_edge(vnode, v0, v1);
	add_verse_edge(vnode, v1, v2);
	if(v3!=-1) {
		add_verse_edge(vnode, v2, v3);
		add_verse_edge(vnode, v3, v0);
	}
	else {
		add_verse_edge(vnode, v2, v0);
	}
}

/*
 * callback function: edge crease was set
 */
static void cb_g_crease_set_edge(
		void *user_data,
		VNodeID node_id,
		const char *layer,
		uint32 def_crease)
{
}

/*
 * callback function: float value for polygon was set up
 */
static void cb_g_polygon_set_face_real32(
		void *user_def,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 polygon_id,
		real32 value)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct real32_item *item;

	if(!session) return;

	/* find needed node (we can be sure, that it is geometry node) */
	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);

	/* find layer containing uint_8 data */
	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);

	/* try to find item*/
	item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);

	if(item) {
		item->value = value;
	}
	else {
		item = create_real32_item(vlayer, polygon_id, value);
		BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
	}
}

/*
 * callback function: int values for polygon was set up
 */
static void cb_g_polygon_set_face_uint32(
		void *user_def,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 polygon_id,
		uint32 value)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct uint32_item *item;

	if(!session) return;

	/* find needed node (we can be sure, that it is geometry node) */
	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);

	/* find layer containing uint_8 data */
	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);

	/* try to find item*/
	item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);

	if(item) {
		item->value = value;
	}
	else {
		item = create_uint32_item(vlayer, polygon_id, value);
		BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
	}
}

/*
 * callback function: uint8 value for polygon was set up
 */
static void cb_g_polygon_set_face_uint8(
		void *user_def,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 polygon_id,
		uint8 value)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct uint8_item *item;

	if(!session) return;

	/* find needed node (we can be sure, that it is geometry node) */
	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);

	/* find layer containing uint_8 data */
	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);

	/* try to find item*/
	item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);

	if(item) {
		item->value = value;
	}
	else {
		item = create_uint8_item(vlayer, polygon_id, value);
		BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
	}
}

/*
 * callback function: float value for polygon corner was set up
 */
static void cb_g_polygon_set_corner_real32(
		void *user_def,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 polygon_id,
		real32 v0,
		real32 v1,
		real32 v2,
		real32 v3)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct quat_real32_item *item;

	if(!session) return;

	/* find needed node (we can be sure, that it is geometry node) */
	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);

	/* find layer containing uint_8 data */
	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);

	/* try to find item*/
	item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);

	if(item) {
		item->value[0] = v0;
		item->value[1] = v1;
		item->value[2] = v2;
		item->value[3] = v3;
	}
	else {
		item = create_quat_real32_item(vlayer, polygon_id, v0, v1, v2, v3);
		BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
	}
}

/*
 * callback function: polygon is deleted
 */
static void cb_g_polygon_delete(
		void *user_data,
		VNodeID node_id,
		uint32 polygon_id)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	VNode *vnode;
	VLayer *vlayer;
	VerseFace *vface;

	if(!session) return;

	/* find needed node (we can be sure, that it is geometry node) */
	vnode = BLI_dlist_find_link(&(session->nodes), node_id);

	/* find layer containing faces */
	vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);

	/* find wanted VerseFace */
	vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id);

	if(!vface) return;

	/* update edge hash */
	update_edgehash_of_deleted_verseface(vnode, vface);
	
	((VGeomData*)vnode->data)->post_polygon_delete(vface);

	/* decrease references at coresponding VerseVertexes */
	vface->vvert0->counter--;
	vface->vvert1->counter--;
	vface->vvert2->counter--;
	if(vface->vvert3) vface->vvert3->counter--;

	/* delete unneeded VerseVertexes */
	free_unneeded_verseverts_of_verseface(vnode, vface);
	
	free_verse_face(vlayer, vface);
}

/*
 * callback function: new polygon (face) created or existing polygon was changed
 */
static void cb_g_polygon_set_corner_uint32(
		void *user_data,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 polygon_id,
		uint32 v0,
		uint32 v1,
		uint32 v2,
		uint32 v3)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct VerseFace *vface=NULL;

	if(!session) return;

	/* try to find VerseNode */
	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
	if(!vnode) return;

	/* try to find VerseLayer */
	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
	if(!vlayer) return;

	/* we have to test coretness of incoming data */
	if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return;
	
	/* Blender uses different order of vertexes */
	if(v3!=-1) { /* quat swap */
		unsigned int v; v = v1; v1 = v3; v3 = v;
	}
	else { /* triangle swap */
		unsigned int v; v = v1; v1 = v2; v2 = v;
	}

	/* try to find VerseFace */
	vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id);

	/* try to find modified VerseFace */
	if(!vface) {
		vface = find_changed_verse_face_in_queue(vlayer, polygon_id);
		if(vface) {
			BLI_remlink(&(vlayer->queue), (void*)vface);
			BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
		}
	}

	if(!vface) {
		/* try to find VerseFace in list of VerseVaces created by me and set up polygon and
		 * layer ids */
		vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3);
		
		/* update edge hash */
		update_edgehash_of_new_verseface(vnode, v0, v1, v2, v3);
		
		if(vface){
			/* I creeated this face ... remove VerseFace from queue */
			BLI_remlink(&(vlayer->queue), (void*)vface);
		}
		else {
			/* some other client created this face*/
			vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3);
		}

		vface->flag &= ~FACE_SENT;

		/* return number of missing verse vertexes */
		vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface);

		if(vface->counter < 1) {
			/* when VerseFace received all needed VerseFaces, then it is moved
			 * to list of VerseFaces */
			BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
			increase_verse_verts_references(vface);
			recalculate_verseface_normals(vnode);
			((VGeomData*)vnode->data)->post_polygon_create(vface);
		}
		else {
			/* when all needed VerseVertexes weren't received, then VerseFace is moved to
			 * the list of orphans waiting on needed vertexes */
			vface->flag |= FACE_RECEIVED;
			BLI_addtail(&(vlayer->orphans), (void*)vface);
		}
	}
	else {
		VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
		/* VerseVertexes of existing VerseFace were changed (VerseFace will use some different
		 * VerseVertexes or it will use them in different order) */

		/* update fake verse edges */
		update_edgehash_of_changed_verseface(vnode, vface, v0, v1, v2, v3);
		
		/* initialize count of unreceived vertexes needed for this face */
		vface->counter = 4;

		/* 1st corner */
		if(vface->vvert0->id != v0) {
			/* decrease references of obsolete vertexes*/
			vface->vvert0->counter--;
			/* delete this vertex, when it isn't used by any face and it was marked as deleted */
			if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
				((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
				free_verse_vertex(vert_vlayer, vface->vvert0);
			}
			/* try to set up new pointer at verse vertex */
			vface->v0 = v0;
			vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0);
			if(vface->vvert0) {
				/* increase references at new vertex */
				vface->vvert0->counter++;
				/* decrease count of needed vertex to receive */
				vface->counter--;
			}
			
		}
		else
			/* this corner wasn't changed */
			vface->counter--;

		/* 2nd corner */
		if(vface->vvert1->id != v1) {
			vface->vvert1->counter--;
			if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
				((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
				free_verse_vertex(vert_vlayer, vface->vvert1);
			}
			vface->v1 = v1;
			vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1);
			if(vface->vvert1) {
				vface->vvert1->counter++;
				vface->counter--;
			}
		}
		else
			vface->counter--;

		/* 3rd corner */
		if(vface->vvert2->id != v2) {
			vface->vvert2->counter--;
			if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
				((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
				free_verse_vertex(vert_vlayer, vface->vvert2);
			}
			vface->v2 = v2;
			vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2);
			if(vface->vvert2) {
				vface->vvert2->counter++;
				vface->counter--;
			}
		}
		else
			vface->counter--;
	
		/* 4th corner */	
		if(vface->vvert3) {
			if(vface->vvert3->id != v3) {
				vface->vvert3->counter--;
				if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
					((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
					free_verse_vertex(vert_vlayer, vface->vvert3);
				}
				vface->v3 = v3;
				if(v3 != -1) {
					vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
					if(vface->vvert3) {
						vface->vvert3->counter++;
						vface->counter--;
					}
				}
				else {
					/* this is some special case, this face hase now only 3 corners
					 * quat -> triangle */
					vface->vvert3 = NULL;
					vface->counter--;
				}
			}
		}
		else if(v3 != -1)
			/* this is some special case, 4th corner of this polygon was created
			 * triangle -> quat */
			vface->v3 = v3;
			vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
			if(vface->vvert3) {
				vface->vvert3->counter++;
				vface->counter--;
			}
		else {
			vface->v3 = -1;
			vface->counter--;
		}
		
		vface->flag &= ~FACE_SENT;
		vface->flag |= FACE_CHANGED;

		if(vface->counter<1) {
			vface->flag &= ~FACE_CHANGED;
			recalculate_verseface_normals(vnode);
			((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
		}
		else {
			/* when all needed VerseVertexes weren't received, then VerseFace is added to
			 * the list of orphans waiting on needed vertexes */
			BLI_dlist_rem_item(&(vlayer->dl), vface->id);
			BLI_addtail(&(vlayer->orphans), (void*)vface);
		}
	}
}

/*
 * callback function: float value was set up for VerseVert with vertex_id
 */
static void cb_g_vertex_set_real32(
		void *user_def,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 vertex_id,
		real32 value)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct real32_item *item;

	if(!session) return;

	/* find needed node (we can be sure, that it is geometry node) */
	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);

	/* find layer containing uint_8 data */
	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);

	/* try to find item*/
	item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);

	if(item) {
		item->value = value;
	}
	else {
		item = create_real32_item(vlayer, vertex_id, value);
		BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
	}
}

/*
 * callback function: int value was set up for VerseVert with vertex_id
 */
static void cb_g_vertex_set_uint32(
		void *user_def,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 vertex_id,
		uint32 value)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;
	struct uint32_item *item;

	if(!session) return;

	/* find needed node (we can be sure, that it is geometry node) */
	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);

	/* find layer containing uint_8 data */
	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);

	/* try to find item*/
	item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);

	if(item) {
		item->value = value;
	}
	else {
		item = create_uint32_item(vlayer, vertex_id, value);
		BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
	}
}

/*
 * callback function: polygon was deleted
 */
static void cb_g_vertex_delete_real32(
		void *user_data,
		VNodeID node_id,
		uint32 vertex_id)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	VNode *vnode=NULL;
	VLayer *vert_vlayer=NULL;
	VerseVert *vvert=NULL;

	if(!session) return;

	vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);

	vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);

	vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id);

	if(!vvert) return;

	if(vvert->counter < 1) {
		((VGeomData*)vnode->data)->post_vertex_delete(vvert);
		BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
	}
	else {
		/* some VerseFace(s) still need VerseVert, remove verse vert from
		 * list verse vertexes and put it to list of orphans */
		vvert->flag |= VERT_DELETED;
		BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
		BLI_addtail(&(vert_vlayer->orphans), vvert);
	}
}

/*
 * callback function: position of one vertex was changed or new vertex was created
 */
static void cb_g_vertex_set_xyz_real32(
		void *user_data,
		VNodeID node_id,
		VLayerID layer_id,
		uint32 vertex_id,
		real32 x,
		real32 y,
		real32 z)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode = NULL;
	struct VLayer *vlayer = NULL;
	struct VerseVert *vvert = NULL;
	real32 tmp;

	if(!session) return;

	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
	if(!vnode)return;

	vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
	if(!vlayer) return;

	/* switch axis orientation */
	tmp = y;
	y = -z;
	z = tmp;
	
	if(vlayer->id == 0) {
		/* try to pick up verse vert from DynamicList */
		vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id);

		if(vvert) {
			if(vvert->flag & VERT_OBSOLETE) return;

			if (vvert->flag & VERT_LOCKED) {
				/* this application changed position of this vertex */
				if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) {
					/* unlock vertex position */
					vvert->flag &= ~VERT_LOCKED;
					/* call post_vertex_set_xyz only, when position of vertex is
					 * obsolete ... the new vertex position will be sent to
					 * verse server */
					if (vvert->flag & VERT_POS_OBSOLETE) {
						((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
					}
				}
			}
			else {
				/* somebody else changed position of this vertex*/
				if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) {
					vvert->co[0] = x;
					vvert->co[1] = y;
					vvert->co[2] = z;
					recalculate_verseface_normals(vnode);
					((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
				}
			}
		}
		else {
			/* create new verse vert */

			/* test if we are authors of this vertex :-) */
			vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z);

			if(vvert) {
				/* remove vert from queue */
				BLI_remlink(&(vlayer->queue), (void*)vvert);
				/* add vvert to the dynamic list */
				BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
				/* set VerseVert flags */
				vvert->flag |= VERT_RECEIVED;
				if(!(vvert->flag & VERT_POS_OBSOLETE))
					vvert->flag &= ~VERT_LOCKED;
				/* find VerseFaces orphans */
				find_vlayer_orphans(vnode, vvert);
				/* find unsent VerseFaces */
				find_unsent_faces(vnode, vvert);
			}
			else {
				/* create new VerseVert */
				vvert = create_verse_vertex(vlayer, vertex_id, x, y, z);
				/* add VerseVert to list of VerseVerts */
				BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
				/* set VerseVert flags */
				vvert->flag |= VERT_RECEIVED;
				/* find VerseFaces orphans */
				find_vlayer_orphans(vnode, vvert);
			}

			((VGeomData*)vnode->data)->post_vertex_create(vvert);
		}
	}
}

/*
 * callback function for destroyng of verse layer
 */
static void cb_g_layer_destroy(
		void *user_data,
		VNodeID node_id,
		VLayerID layer_id)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode;
	struct VLayer *vlayer;

	if(!session) return;

	vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id);
	if(!vnode) return;

	vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id);

	if(vlayer){
		/* free VerseLayer data */
		free_verse_layer_data(vnode, vlayer);
		/* remove VerseLayer from list of verse layers */
		BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id);
		/* do client dependent actions */
		vlayer->post_layer_destroy(vlayer);
		/* free vlayer itself */
		MEM_freeN(vlayer);
	}

}

/*
 * callback function: new layer was created
 */
static void cb_g_layer_create(
		void *user_data,
		VNodeID node_id,
		VLayerID layer_id,
		const char *name,
		VNGLayerType type,
		uint32 def_integer,
		real64 def_real)
{
	struct VerseSession *session = (VerseSession*)current_verse_session();
	struct VNode *vnode=NULL;
	struct VLayer *vlayer=NULL;

	if(!session) return;

	/* find node of this layer*/
	vnode = BLI_dlist_find_link(&(session->nodes), node_id);
	if(!vnode) return;

	/* when we created this layer, then subscribe to this layer */
	if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE)
		verse_send_g_layer_subscribe(node_id, layer_id, 0);

	/* try to find */
	if(vnode->owner_id == VN_OWNER_MINE)
		vlayer = find_vlayer_in_sending_queue(vnode, layer_id);

	if(vlayer) {
		/* remove vlayer form sending queue add verse layer to list of verse layers */
		BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer);
		BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id);
		/* send all not sent vertexes to verse server
		 * other items waiting in sending queue will be automaticaly sent to verse server,
		 * when verse vertexes will be received from verse server */
		if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) {
			struct VerseVert *vvert = (VerseVert*)vlayer->queue.first;
			while(vvert) {
				send_verse_vertex(vvert);
				vvert = vvert->next;
			}
		}
	}
	else {
		/* create new VerseLayer */
		vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real);
		/* add layer to the list of VerseLayers */
		BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id);
	}

	vlayer->flag |= LAYER_RECEIVED;

	/* post callback function */
	vlayer->post_layer_create(vlayer);
}

/*
 * this function will send destroy commands for all VerseVertexes and
 * VerseFaces to verse server, but it will not send destroy commands
 * for VerseLayers or geometry node, it can be used in other functions
 * (undo, destroy geom node, some edit mesh commands, ... ), parameter of
 * this function has to be geometry verse node
 */
void destroy_geometry(VNode *vnode)
{
	struct VLayer *vert_vlayer, *face_vlayer;
	struct VerseFace *vface;
	struct VerseVert *vvert;

	if(vnode->type != V_NT_GEOMETRY) return;

	face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
	vface = face_vlayer->dl.lb.first;

	while(vface) {
		send_verse_face_delete(vface);
		vface = vface->next;
	}

	vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
	vvert = vert_vlayer->dl.lb.first;

	while(vvert) {
		send_verse_vertex_delete(vvert);
		vvert = vvert->next;
	}

	/* own destruction of local verse date will be executed, when client will
	 * receive apropriate callback commands from verse server */
}

/*
 * free VGeomData
 */
void free_geom_data(VNode *vnode)
{
	struct VerseSession *session = vnode->session;
	struct VLayer *vlayer;

	if(vnode->data){
		vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first;
		while(vlayer){
			/* unsubscribe from layer */
			if(session->flag & VERSE_CONNECTED)
				verse_send_g_layer_unsubscribe(vnode->id, vlayer->id);
			/* free VerseLayer data */
			free_verse_layer_data(vnode, vlayer);
			/* next layer */
			vlayer = vlayer->next;
		}
		/* free constraint between vnode and mesh */
		((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode);
		/* free all VerseLayers */
		BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
		/* free fake verse edges */
		BLI_freelistN(&((VGeomData*)vnode->data)->edges);
		/* free edge hash */
		MEM_freeN(((VGeomData*)vnode->data)->hash);
	}
}

void set_geometry_callbacks(void)
{
	/* new layer created */
	verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL);
	/* layer was destroyed */
	verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL);

	/* position of vertex was changed */
	verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL);
	/* vertex was deleted */
	verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL);

	/* callback functions for values being associated with vertexes */
	verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL);
	verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL);

	/* new polygon was created / vertex(es) of polygon was set */
	verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL);
	/* polygon was deleted */
	verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL);

	/* callback functions for values being associated with polygon corners */
	verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL);
	/* callback functions for values being associated with faces */
	verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL);
	verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL);
	verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL);

	/* crease of vertex was set */
	verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL);
	/* crease of edge was set */
	verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL);
}

#endif
