// This source code is property of the Computer Graphics and Visualization 
// chair of the TU Dresden. Do not distribute! 
// Copyright (C) CGV TU Dresden - All Rights Reserved
//

#include "CGVDemo.h"

#include <cgv/utils/ostream_printf.h>
#include <cgv/gui/file_dialog.h>
#include <cgv/gui/dialog.h>
#include <cgv/render/view.h>
#include <cgv/base/find_action.h>

using namespace cgv::utils;

// The constructor of this class
CGVDemo::CGVDemo() : node("CGV Demo")
{
	// Default setting for the render mode	
	show_coordinate_system = true;
	
	slider_value = 0.0f;

	// Connect the timer_event method to the (cgv-library) animation
	// trigger to be called every 1/60 sec.
	connect(get_animation_trigger().shoot, this, &CGVDemo::timer_event);
}

int local_test_value;
void local_test_value_changed(control<int>& c)
{
	std::cout << "Local test value has been changed to " << local_test_value <<". "
		<< "Old value was " << c.get_old_value() << std::endl;
}

// Create the gui elements
// This method overrides a virtual method of the provider base class.
void CGVDemo::create_gui() {

	// Controls are chosen based on the variable's type

	// Create a toggle button that controls the variable "show_coordinate_system". 
	// Every time this button is pressed, the method on_set is called
	// that calls post_redraw to redraw the scene.	
	// Possible gui_types are "toggle" and "check"
	add_member_control(this, "Show Coordinate System", show_coordinate_system, "toggle");

	// Example control for a float or integer value
	// Possible gui_types are "slider", "value_slider", "wheel", "dial", "adjuster", and "value_input"
	add_member_control(this, "Demo Slider", slider_value, "value_slider", "min=0.0;max=5.0");
	
	// This is how to set attributes programmatically
	find_control(slider_value)->set("max", 7);

	// add_member_control requires the variable's container to be a base_ptr. It
	// then calls the container's on_set method when it changes the value. If a
	// value that is not enclosed in a base_ptr should be targeted, add_control 
	// can be used and the signal can be connected manually:
	auto slider = add_control("Non base_ptr", local_test_value, "value_slider", "min=0;max=20");
	connect(slider->value_change, &local_test_value_changed);

	// To add further control elements you can copy the lines above. Other control
	// elements such as buttons exist. This line creates a button, which calls an
	// arbitrary method. Whenever a click was performed, the method "button_pressed" 
	// is called. rebind() is used to target the member function.
	connect_copy(add_button("Press me")->click,
		rebind(this, &CGVDemo::button_pressed));		

	// Find the view
	std::vector<cgv::render::view*> view_ptrs;
	cgv::base::find_interface<cgv::render::view>(get_node(), view_ptrs);
	if (view_ptrs.empty()) {
		// If there is no view, we cannot update it
		cgv::gui::message("could not find a view to adjust!!");
	}
	else
	{
		// Set view direction
		view_ptrs[0]->set_view_dir(-1, -1, -1);
		// Set focus point of view
		double focus_point[3] = { 0, 0, 0 };
		view_ptrs[0]->set_focus(focus_point);
		// Set the scene's size at the focus point
		view_ptrs[0]->set_y_extent_at_focus(1);
	}
}

// The timer event. This method is called every 1/60 sec.
void CGVDemo::timer_event(double, double dt)
{
	// Use post_redraw() to issue a new frame for animation
	// dt it the time since the last call
}



// Method that is called whenever a gui element changes a bound value
void CGVDemo::on_set(void* member_ptr)
{
	// Redraw the scene every time a gui value was changed
	post_redraw();
}


// Demo button action
void CGVDemo::button_pressed()
{
	std::cout << "I was pressed!" << std::endl;

	//Sample file open dialog:
	std::string filename = cgv::gui::file_open_dialog("Open", "Image Files (jpg,gif):*.jpg;*.gif|Video Files (avi):*.avi|All Files:*.*");
	if (!filename.empty())
		std::cout << filename << std::endl;
}




void CGVDemo::draw(context& c) {
	
	// Disable face culling
	glDisable(GL_CULL_FACE);
	

	if (show_coordinate_system)
		render_coordinate_system();


	// Re-enable backface culling
	glEnable(GL_CULL_FACE);
}



void CGVDemo::render_coordinate_system()
{
	// Remember the OpenGL enable bits
	glPushAttrib(GL_ENABLE_BIT);
	// Disable lighting
	glDisable(GL_LIGHTING);
	
	// Start transferring line information
	glBegin(GL_LINES);

	// Show a red arrow towards the X axis
	glColor3f(1.0f, 0.0f, 0.0f);
	glVertex3f(0.0f, 0.0f, 0.0f);
	glVertex3f(0.5f, 0.0f, 0.0f);
	
	// Show a green arrow towards the Y axis
	glColor3f(0.0f, 1.0f, 0.0f);
	glVertex3f(0.0f, 0.0f, 0.0f);
	glVertex3f(0.0f, 0.5f, 0.0f);
	
	// Show a blue arrow towards the Z axis
	glColor3f(0.0f, 0.0f, 1.0f);
	glVertex3f(0.0f, 0.0f, 0.0f);
	glVertex3f(0.0f, 0.0f, 0.5f);
	
	glEnd();
	
	// Restore enable bits
	glPopAttrib();
}