/* -*- mia-c++ -*-
 *
 * This file is part of viewitgui - a library and program for the
 * visualization of 3D data sets. 
 *
 * Copyright (c) Leipzig, Madrid 1999-2013 Mirco Hellmann, Gert Wollny
 *
 * viewitgui 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.
 *
 * viewitgui 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 viewitgui; if not, see <http://www.gnu.org/licenses/>.
 */


#include <viewit/voxelmove.hh>
#include <algorithm>


TVoxelCloud::TVoxelCloud(const string& name,  int __size, float __time_step,
			 float __voxel_lifetime, 
			 const TDeformation& __deformation,
			 const C3DFVectorSource& __source):
	TDrawable(name),
	_M_mover(__deformation),
	_M_time_step(__time_step),
	_M_voxel_lifetime(__voxel_lifetime),
	_M_age(0),
	_M_source(__source),
	_M_size(__size)
	
{
	init_voxels();
}

void TVoxelCloud::init_voxels()
{
	_M_forward_voxels.clear();
	_M_backward_voxels.clear();
	
	for( int i = 0; i < _M_size; ++i) {
		bool b = false; 
		C3DFVector s;
		do {
			s = _M_source(); 
			b = _M_mover(s) < 1.0; 
		} while (b);
		
		_M_forward_voxels.push_back(s);
		_M_backward_voxels.push_back(s);
	}
}

shared_ptr<TVertexList> TVoxelCloud::get_vertex_list(int stride)const
{
	shared_ptr<TVertexList> result(new  TVertexList);
	
	TVoxelList::const_iterator li = _M_forward_voxels.begin();
	TVoxelList::const_iterator le = _M_forward_voxels.end();

	int i =0; 
	while (li != le) {
		if (! (i % stride) )
			result->push_back(*li);
		++li; 
		++i; 
	}
	
	li = _M_backward_voxels.begin();
	le = _M_backward_voxels.end();
	
	i =0; 
	while (li != le) {
		if (! (i % stride) )
			result->push_back(*li);
		++li; 
		++i; 
	}
	return result; 
}

void TVoxelCloud::do_gl_draw(const TCamera& c) const
{
	TVoxelList::const_iterator li =  _M_forward_voxels.begin();
	TVoxelList::const_iterator le =  _M_forward_voxels.end();

	glPointSize(2.0f);
	glEnable(GL_POINT_SMOOTH);
	
	glBegin(GL_POINTS);
	glColor3fv(&get_color1().x);
	while (li != le) {
		glVertex3fv(&(*li).x);
		++li; 
	}
	
	li = _M_backward_voxels.begin();
	le = _M_backward_voxels.end();
	
	glColor3fv(&get_color2().x);	
	while (li != le) {
		glVertex3fv(&(*li).x);
		++li; 
	}
	glEnd();
	glDisable(GL_POINT_SMOOTH);
}

bool TVoxelCloud::do_handle_key_event(int key)
{
	switch (key) {
	case 'p':init_voxels();break;
	case 'o':set_animated(true); break; 
	default:return TDrawable::do_handle_key_event(key); 
	}
	return true; 
}

bool TVoxelCloud::do_handle_command_event(PEventInfo info)
{
	switch (info->get_command()) {
		
	case EV_VOXELCLOUD_GET_STATE: {
		TVoxelCloudEventInfo& ev = dynamic_cast<TVoxelCloudEventInfo&>(*info);
		ev.set_lifetime(_M_voxel_lifetime);
		return true;
	}
	case EV_VOXELCLOUD_SET_LIFETIME: {
		TVoxelCloudEventInfo& ev = dynamic_cast<TVoxelCloudEventInfo&>(*info);
		init_voxels();	
		_M_voxel_lifetime = ev.get_lifetime();
		return true;
	}
	case EV_VOXELCLOUD_TOGGLE_DIFFUSION:
		set_animated(is_animated());
		return true;
	}
	return TDrawable::do_handle_command_event(info);
}


bool TVoxelCloud::animate()
{
	if (!is_animated()) return false;
	
	
	TVoxelList::iterator li =  _M_forward_voxels.begin();
	TVoxelList::iterator le =  _M_forward_voxels.end();
	
	while (li != le) {
		_M_mover.forward(&*li,_M_time_step);
		if (! _M_source.inside(*li)) {
			*li = _M_source();
		}
		++li; 
	}
	
	li = _M_backward_voxels.begin();
	le = _M_backward_voxels.end();

	while (li != le) {
		_M_mover.backward(&*li,_M_time_step);
		if (! _M_source.inside(*li)) {
			*li = _M_source();
		}
		++li; 
	}
	_M_age += _M_time_step;
	
	if (_M_age >= _M_voxel_lifetime) set_animated(false);
	
	return is_animated();
}

void TVoxelCloud::toggle_moving() {
	set_animated(is_animated());
}

void TVoxelCloud::set_lifetime(float lifetime) 
{
	init_voxels();	
	_M_voxel_lifetime = lifetime;
}

float TVoxelCloud::get_lifetime() const 
{
	return _M_voxel_lifetime;
}

const char* TVoxelCloud::get_classname() const 
{
	return VOXELCLOUD_CLASSNAME;
}

void TVoxelCloud::get_classname_list(list<string> *classlist) const
{
	if (classlist) {
		classlist->push_front(VOXELCLOUD_CLASSNAME);
		TDrawable::get_classname_list(classlist);
	}
}
