// Copyright (c) 2013, Regents of the University of Pennsylvania                    //
// All rights reserved.                                                             //
//                                                                                  //
// Redistribution and use in source and binary forms, with or without               //
// modification, are permitted provided that the following conditions are met:      //
//     * Redistributions of source code must retain the above copyright             //
//       notice, this list of conditions and the following disclaimer.              //
//     * Redistributions in binary form must reproduce the above copyright          //
//       notice, this list of conditions and the following disclaimer in the        //
//       documentation and/or other materials provided with the distribution.       //
//     * Neither the name of the <organization> nor the                             //
//       names of its contributors may be used to endorse or promote products       //
//       derived from this software without specific prior written permission.      //
//                                                                                  //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND  //
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED    //
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           //
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY               //
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES       //
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;     //
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND      //
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       //
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS    //
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                     //
//                                                                                  //
// Contact Tiantian Liu (ltt1598@gmail.com) if you have any questions.              //
//----------------------------------------------------------------------------------//

#pragma warning( disable : 4996)

#include "precompile.h"

#include <fstream>
#include <iostream>

#include "anttweakbar_wrapper.h"
#include "headers\math_headers.h"

#ifdef ENABLE_MATLAB_DEBUGGING
#include "matlab_debugger.h"
#endif
//#include "mesh.h"
//#include "simulation.h"

//----------Events Related Variables--------------------//
static int g_old_screen_width;
static int g_old_screen_height;
static ScalarType g_old_timestep;
static ScalarType g_old_stretch_stiffness;
static ScalarType g_old_bending_stiffness;
static ScalarType g_old_attachment_stiffness;
static bool g_old_camera_mode;
static bool g_old_enable_matlab_debugger = false;
static OptimizationMethod g_old_optimization_method;

//----------Global Parameters----------------//
extern int g_screen_width;
extern int g_screen_height;
extern char g_obj_file_path[255];
extern char g_mesh_file_path[255];
extern float g_mesh_scaling;
extern glm::vec3 g_handle_color;
extern bool g_random_handle_color;

//----------State Control--------------------//
extern bool g_only_show_sim;
extern bool g_camera_mode;
extern bool g_record;
extern bool g_animation_mode;
extern bool g_pause;
extern int g_mesh_color_type;
extern bool g_show_wireframe;
extern int  g_wireframe_linewidth;
extern bool g_show_w11;
extern bool g_show_detw;
extern bool g_show_detf;
extern bool g_show_texture;

//----------Recording Related----------------//
extern bool g_recording_limit;
extern int g_total_frame;

//----------anttweakbar handlers----------//
extern void TW_CALL reset_simulation(void*);
extern void TW_CALL step_through(void*);
extern void TW_CALL reset_camera(void*);
extern void TW_CALL set_handle(void*);
extern void TW_CALL save_weights(void*);
extern void TW_CALL load_weights(void*);
extern void TW_CALL compute_weights(void*);
extern void TW_CALL matlab_reset_current_data(void*);
extern void TW_CALL matlab_reset_all_data(void*);
extern void TW_CALL matlab_new_data(void*);
extern void TW_CALL matlab_export_data(void*);
extern void TW_CALL matlab_plot(void*);
extern void TW_CALL matlab_plot_all(void*);

//----------key components--------------//
extern SelectionTool* g_selection_tool;
extern Sim* g_simulation;
#ifdef ENABLE_MATLAB_DEBUGGING
extern MatlabDebugger* g_debugger;
#endif

//----------global variables for testing------------//
ScalarType test1;
ScalarType test2;
ScalarType test3;
ScalarType test4;
ScalarType test5;

AntTweakBarWrapper::AntTweakBarWrapper()
{

}

AntTweakBarWrapper::~AntTweakBarWrapper()
{
	SaveSettings(NULL);
	Cleanup();
}

void AntTweakBarWrapper::Init()
{
	TwInit(TW_OPENGL, NULL);

	//Control Panel bar
	m_control_panel_bar = TwNewBar("Control Panel");
	TwDefine(" 'Control Panel' size='200 710' position='814 10' color='255 255 255' text=dark ");
	char control_bar_pos_string [255];
	sprintf(control_bar_pos_string, "'Control Panel' position='%d 10'", g_screen_width-210);
	TwDefine(control_bar_pos_string);
	// state control
	TwAddVarRW(m_control_panel_bar, "Pause", TwType(sizeof(bool)), &(g_pause), "group='State Control'");
	TwAddButton(m_control_panel_bar, "Step Once", step_through, NULL, "group='State Control' ");
	TwAddVarRW(m_control_panel_bar, "Record", TwType(sizeof(bool)), &(g_record), "group='State Control'");
	TwAddVarRW(m_control_panel_bar, "Animation Mode", TwType(sizeof(bool)), &(g_animation_mode), "group='Recording'");
	TwAddVarRW(m_control_panel_bar, "Has End", TwType(sizeof(bool)), &(g_recording_limit), "group='Recording'");
	TwAddVarRW(m_control_panel_bar, "Total Frames", TW_TYPE_INT32, &(g_total_frame), "min=1 group='Recording'");
	TwDefine(" 'Control Panel'/'Recording' group='State Control'");
	TwAddSeparator(m_control_panel_bar, NULL, "");
	// visualization
	TwEnumVal meshColorEV[3] =  {{0, "No Fill"},
								 {1, "Default Color"},
	                             {2, "Skin Weight"},
								};
	TwType meshColor = TwDefineEnum("MeshColor", meshColorEV, 3);
	TwAddVarRW(m_control_panel_bar, "Mesh Color", meshColor, &g_mesh_color_type, " group='Visualization' ");
	TwAddVarRW(m_control_panel_bar, "Wireframe", TwType(sizeof(bool)), &(g_show_wireframe), "group='Visualization'");
	TwAddVarRW(m_control_panel_bar, "Line Width", TW_TYPE_INT32, &(g_wireframe_linewidth), "min=1 group='Visualization'");
	TwAddVarRW(m_control_panel_bar, "det(F)", TwType(sizeof(bool)), &(g_show_detf), "group='Visualization'");
	TwAddVarRW(m_control_panel_bar, "W11", TwType(sizeof(bool)), &(g_show_w11), "group='Visualization'");
	TwAddVarRW(m_control_panel_bar, "det(W)", TwType(sizeof(bool)), &(g_show_detw), "group='Visualization'");
	TwAddVarRW(m_control_panel_bar, "Texture", TwType(sizeof(bool)), &(g_show_texture), "group='Visualization'");
	TwAddVarRW(m_control_panel_bar, "Width", TW_TYPE_INT32, &(g_screen_width), "min=640 group='Screen Resolution'");
	TwAddVarRW(m_control_panel_bar, "Height", TW_TYPE_INT32, &(g_screen_height), "min=480 group='Screen Resolution'");
	// matlab
#ifdef ENABLE_MATLAB_DEBUGGING
	TwAddVarRW(m_control_panel_bar, "Matlab Debugger", TwType(sizeof(bool)), &(g_debugger->m_enable), "group = 'Matlab'");
	TwEnumVal axisStyleEV[4] =  {{PLOT_TYPE_PLOT, "plot"},
								{PLOT_TYPE_SEMILOG_X, "semilogx"},
								{PLOT_TYPE_SEMILOG_Y, "semilogy"},
								{PLOT_TYPE_LOGLOG, "loglog"}};
	TwType axisStyle = TwDefineEnum("AStyle", axisStyleEV, 4);
	TwAddVarRW(m_control_panel_bar, "Axis Style", axisStyle, &g_debugger->m_plot_type, " group='Matlab Plot' ");
	TwAddVarRW(m_control_panel_bar, "x-Axis Variable", TwType(sizeof(bool)), &g_debugger->m_plot_x_axis_plot_iterations, "true='Iteration' false='Time' group='Matlab Plot'");
	TwAddButton(m_control_panel_bar, "Plot", matlab_plot, (void*)(this), " group='Matlab Plot' ");
	TwAddButton(m_control_panel_bar, "Plot All", matlab_plot_all, (void*)(this), " group='Matlab Plot' ");
	TwDefine(" 'Control Panel'/'Matlab Plot' group='Matlab'");
	TwAddButton(m_control_panel_bar, "Reset Current Data", matlab_reset_current_data, (void*)(this), " group='Matlab Data' ");
	TwAddButton(m_control_panel_bar, "Reset All Data", matlab_reset_all_data, (void*)(this), " group='Matlab Data' ");
	TwAddVarRW(m_control_panel_bar, "Legend", TW_TYPE_CSSTRING(sizeof(g_debugger->m_legend_string)), &(g_debugger->m_legend_string), " group='Matlab Data' ");
	TwAddButton(m_control_panel_bar, "Add This Data", matlab_new_data, (void*)(this), " group='Matlab Data' ");
	TwAddButton(m_control_panel_bar, "Export Data", matlab_export_data, (void*)(this), " group='Matlab Data' ");
	TwDefine(" 'Control Panel'/'Matlab Data' group='Matlab'");
#endif
	// test field
	TwAddVarRW(m_control_panel_bar, "Test1", TW_TYPE_SCALAR_TYPE, &test1,"group='Test Field'");
	TwAddVarRW(m_control_panel_bar, "Test2", TW_TYPE_SCALAR_TYPE, &test2,"group='Test Field'");
	TwAddVarRW(m_control_panel_bar, "Test3", TW_TYPE_SCALAR_TYPE, &test3,"group='Test Field'");
	TwAddVarRW(m_control_panel_bar, "Test4", TW_TYPE_SCALAR_TYPE, &test4,"group='Test Field'");
	TwAddVarRW(m_control_panel_bar, "Test5", TW_TYPE_SCALAR_TYPE, &test5,"group='Test Field'");
	// buttons
	TwAddSeparator(m_control_panel_bar, NULL, "");
	TwAddButton(m_control_panel_bar, "Save Settings", SaveSettings, this, " ");
	TwAddButton(m_control_panel_bar, "Load Settings", LoadSettings, this, " ");
	TwAddButton(m_control_panel_bar, "Default Settings", SetDefaultSettings, this, " ");
	TwAddSeparator(m_control_panel_bar, NULL, "");
	TwAddButton(m_control_panel_bar, "Reset Camera", reset_camera, NULL, " ");
	TwAddButton(m_control_panel_bar, "Reset Simulation", reset_simulation, NULL, " ");
	//!Control Panel bar

	// mesh and selection
	m_mesh_bar = TwNewBar("Mesh & Selection");
	TwDefine(" 'Mesh & Selection' size='200 250' position='10 10' color='210 240 255' text=dark ");
	// mesh Load
	TwAddVarRW(m_mesh_bar, "Mesh Mode", TwType(sizeof(bool)), &(g_camera_mode), " true='2D' false='3D' ");
	TwAddVarRW(m_mesh_bar, "Obj File", TW_TYPE_CSSTRING(sizeof(g_obj_file_path)), &(g_obj_file_path), " ");
	TwAddVarRW(m_mesh_bar, "Tet File", TW_TYPE_CSSTRING(sizeof(g_mesh_file_path)), &(g_mesh_file_path), " ");
	TwAddVarRW(m_mesh_bar, "Mesh Scaling", TW_TYPE_FLOAT, &(g_mesh_scaling), " min=0.0001");
	// selection
	TwEnumVal mouseModeEV[3] =  {{GUI_MODE_SELECTION, "Selection (Q)"},
								 {GUI_MODE_TRANSLATION, "Translation (W)"},
	                             {GUI_MODE_ROTATION, "Rotation (R)"}};
	TwType mouseMode = TwDefineEnum("MouseMode", mouseModeEV, 3);
	TwAddVarRW(m_mesh_bar, "Mouse Mode", mouseMode, &g_selection_tool->m_gui_mode, " group='Handle' ");
	TwAddVarRW(m_mesh_bar, "Random Handle Color", TwType(sizeof(bool)), &(g_random_handle_color), " group='Handle' ");
	TwAddVarRW(m_mesh_bar, "Handle Color", TW_TYPE_COLOR3F, &(g_handle_color[0]), " group='Handle' colormode=hls ");
	TwAddButton(m_mesh_bar, "Set Handle (H)", set_handle, NULL, " group='Handle' key='h' ");
	// skin weight
	TwAddButton(m_mesh_bar, "Save Weights & Handles", save_weights, NULL, " group='Skin Weights' ");
	TwAddButton(m_mesh_bar, "Load Weights & Handles", load_weights, NULL, " group='Skin Weights' ");
	TwAddButton(m_mesh_bar, "Compute Weights (C)", compute_weights, NULL, " group='Skin Weights' key='c'");

	// !mesh and selection

	// skinning
	m_sim_bar = TwNewBar("Skinning");
	TwDefine(" 'Skinning' size='200 560' position='10 270' color='255 216 224' text=dark ");
	TwAddVarRW(m_sim_bar, "Attachment K", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_stiffness_attachment), " min=0 ");
	TwAddVarRW(m_sim_bar, "Mu", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_mu), " min=0 ");
	TwAddVarRW(m_sim_bar, "Lambda", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_lambda), " ");
	TwAddVarRW(m_sim_bar, "Non-inversion", TwType(sizeof(bool)), &(g_simulation->m_solver.m_enable_non_inversion), " true='Enable' false='Disable' ");
	TwEnumVal energyTypeEV[ENERGY_TYPE_TOTAL_NUM] = {{ENERGY_TYPE_COROT, "corotation"},
													 {ENERGY_TYPE_EXROT, "exrotation"},
	};
	TwType energyType = TwDefineEnum("Energy Type", energyTypeEV, ENERGY_TYPE_TOTAL_NUM);
	TwAddVarRW(m_sim_bar, "EnergyType", energyType, &(g_simulation->m_solver.m_energy_type), "");
	TwEnumVal barrierTypeEV[BARRIER_TYPE_TOTAL_NUM] = {{BARRIER_TYPE_LOG, "-log(x)"},
													   {BARRIER_TYPE_LOG_PLUS_LINEAR, "-log(x)+x"},
													   {BARRIER_TYPE_SPLINE, "spline"},
													   {BARRIER_TYPE_QUADRATIC, "Quadratic Penalty"},
													   {BARRIER_TYPE_MODIFIED_LOG, "log(x+1)"},
													   {BARRIER_TYPE_NR_TRANSFORMATION, "NR trans"},
													   {BARRIER_TYPE_LSL, "LSL"}
													  };
	TwType barrierType = TwDefineEnum("Barrier Type", barrierTypeEV, BARRIER_TYPE_TOTAL_NUM);
	TwAddVarRW(m_sim_bar, "BarrierType", barrierType, &(g_simulation->m_solver.m_barrier_type), "group='Barrier/Penalty'");
	TwEnumVal penaltyTypeEV[PENALTY_TYPE_TOTAL_NUM] = {{PENALTY_TYPE_QUADRATIC, "quadratic"},
													   {PENALTY_TYPE_CUBIC, "cubic"},
													   {PENALTY_TYPE_SPLINE, "spline"}
													  };
	TwType penaltyType = TwDefineEnum("penalty Type", penaltyTypeEV, PENALTY_TYPE_TOTAL_NUM);
	TwAddVarRW(m_sim_bar, "PenaltyType", penaltyType, &(g_simulation->m_solver.m_penalty_type), "group='Barrier/Penalty'");
	TwEnumVal ncTypeEV[NC_TOTAL_NUM] = {{NC_DETERMINANT_W, "det(W)"},
										{NC_DETERMINANT_F, "det(F)"},
										{NC_DETERMINANT_F_UPDATE_ROTATION, "det(F) Fix Rotation"}
									   };
	TwType ncType = TwDefineEnum("Noninversion Criteria", ncTypeEV, NC_TOTAL_NUM);
	TwAddVarRW(m_sim_bar, "NoninversionCriteria", ncType, &(g_simulation->m_solver.m_noninversion_criteria), "group='Barrier/Penalty'");
	TwAddVarRW(m_sim_bar, "Alpha", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_alpha), " group='Barrier/Penalty'");
	TwAddVarRW(m_sim_bar, "Beta", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_beta), " group='Barrier/Penalty'");
	TwAddVarRW(m_sim_bar, "Gamma", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_gamma), " group='Barrier/Penalty'");
	TwAddVarRW(m_sim_bar, "AutoRescaling", TwType(sizeof(bool)), &(g_simulation->m_solver.m_auto_multiplier), "group='Barrier/Penalty'");
	TwAddVarRW(m_sim_bar, "MultiplierMu", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_multiplier_mu), "min=1 group='Barrier/Penalty'");
	TwAddVarRW(m_sim_bar, "Multiplier", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_multiplier), "min=0 group='Barrier/Penalty'");

	TwEnumVal optimizeModeEV[OPTIMIZATION_TOTAL_NUM] =  {{OPTIMIZATION_LBS, "LBS"},\
														{OPTIMIZATION_LOCAL_GLOBAL, "Local Global"},\
														{OPTIMIZATION_PENALTY, "Penalty Method"},\
														{OPTIMIZATION_PENALTY_LOCAL_GLOBAL_BLEND, "Penalty Local Global Blend"},\
														{OPTIMIZATION_LOCALLY_INJECTIVE_MAPPING, "LIM"},\
														{OPTIMIZATION_MOSEK_WITH_ITERATIONS, "Mosek show iterations"},\
														{OPTIMIZATION_MOSEK_WITHOUT_ITERATIONS, "Mosek without iterations"},\
														{OPTIMIZATION_BARRIER_METHOD, "Barrier Method"},\
														{OPTIMIZATION_NONLINEAR_RESCALING, "void"},\
														{OPTIMIZATION_NEWTON_PRIMAL_DUAL, "Primal Dual"},\
														{OPTIMIZATION_PENALTY_ON_DETF, "Penalty On Det(F)"},\
														{OPTIMIZATION_SPECTRAL_SDP, "Spectral SDP"},\
														{OPTIMIZATION_PENNON, "PENNON"},\
														{OPTIMIZATION_LOCALIZED_SDP_SCHUR_COMPLEMENT, "void"},\
														{OPTIMIZATION_DISCONNECTED_MESH, "void"},\
														{OPTIMIZATION_COROT_NEWTON, "Corot Newton"},\
														{OPTIMIZATION_COROT_LOCAL_GLOBAL_STYLE, "Corot Local Global"},\
														{OPTIMIZATION_COROT_CONSTANT_HESSIAN_1, "Corot Constant Hessian"},\
														{OPTIMIZATION_COROT_CONSTANT_HESSIAN_2, "Corot Constant Hessian 2"},\
														{OPTIMIZATION_NEOHOOKEAN_GRADIENT_DESCENT, "Neohookean Gradient Descent"},\
														{OPTIMIZATION_NEWHOOKEAN_CONSTANT_HESSIAN, "Neohookean Constant Hessian"},\
														{OPTIMIZATION_NONINVERSION_CONSTANT_HESSIAN, "Noninversion Constant Hessian"},\
														{OPTIMIZATION_AUXILIARY_SOLVE, "void"},\
														{OPTIMIZATION_ALTERNATIVE_PROJECTION, "Alternating Projection"},\
														{OPTIMIZATION_ONE_TANGENT_PLANE, "One Tangent Plane"},\
														{OPTIMIZATION_EXTERIOR_POINTS, "void"},\
														{OPTIMIZATION_TAGENT_SPACE, "void"},\
														{OPTIMIZATION_ITERATIVE_QP, "void"}\
														};
	TwType optimizeMode = TwDefineEnum("Optimization", optimizeModeEV, OPTIMIZATION_TOTAL_NUM);
	TwAddVarRW(m_sim_bar, "Optimization", optimizeMode, &(g_simulation->m_solver.m_optimization_method), " group='OP' ");
	TwAddVarRW(m_sim_bar, "#InnerIterations", TW_TYPE_INT32, &(g_simulation->m_solver.m_inner_loop_iterations), "min=1 group='OP'");
	TwAddVarRW(m_sim_bar, "Substepping", TwType(sizeof(bool)), &(g_simulation->m_solver.m_enable_substepping), "group='OP'");
	TwAddVarRW(m_sim_bar, "Regularization", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_regularization_mu), "min=0 step=0.1 group='OP'");
	TwAddVarRW(m_sim_bar, "Line Search", TwType(sizeof(bool)), &(g_simulation->m_solver.m_enable_line_search), " true='Enable' false='Disable' group='OP'");
	TwAddVarRW(m_sim_bar, "LS stepsize", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_ls_stepsize), " min=0 max=1 group='LS'");
	TwAddVarRW(m_sim_bar, "LS alpha", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_ls_alpha), " min=0 max=1 group='LS'");
	TwAddVarRW(m_sim_bar, "LS beta", TW_TYPE_SCALAR_TYPE, &(g_simulation->m_solver.m_ls_beta), " min=0.000001 max=1 group='LS'");
	TwDefine(" 'Skinning'/'LS' group='OP'");

	// !skinning

	TwDefine(" TW_HELP visible=false ");
}

void AntTweakBarWrapper::Cleanup()
{
	m_control_panel_bar = NULL;
	m_mesh_bar = NULL;
	m_sim_bar = NULL;

	TwTerminate();
}

void AntTweakBarWrapper::Reset()
{
	Cleanup(); 
	Init();
}

void AntTweakBarWrapper::Hide()
{
	TwDefine(" 'Control Panel' visible=false ");
	TwDefine(" 'Mesh & Selection' visible=false ");
	TwDefine(" 'Skinning' visible=false ");
}

void AntTweakBarWrapper::Show()
{
	TwDefine(" 'Control Panel' visible=true ");
	TwDefine(" 'Mesh & Selection' visible=true ");
	TwDefine(" 'Skinning' visible=true ");
}

int AntTweakBarWrapper::Update()
{
	// update

	// control panel pos
	char control_bar_pos_string [255];
	sprintf(control_bar_pos_string, "'Control Panel' position='%d 10'", g_screen_width-210);
	TwDefine(control_bar_pos_string);

	// control panel settings
	if (g_record)
	{
		TwDefine(" 'Control Panel'/'Recording' visible=true");
	}
	else
	{
		g_recording_limit = false;
		TwDefine(" 'Control Panel'/'Recording' visible=false");
	}
#ifdef ENABLE_MATLAB_DEBUGGING
	// matlab display
	if (g_debugger->m_enable)
	{
		TwDefine(" 'Control Panel'/'Matlab Plot' visible=true");
		TwDefine(" 'Control Panel'/'Matlab Data' visible=true");
	}
	else
	{
		TwDefine(" 'Control Panel'/'Matlab Plot' visible=false");
		TwDefine(" 'Control Panel'/'Matlab Data' visible=false");
	}
#endif

	// mesh settings display
	if (g_camera_mode == MODE_2D)
	{
		TwDefine(" 'Mesh & Selection'/'Obj File' visible=true");
		TwDefine(" 'Mesh & Selection'/'Tet File' visible=false");
	}
	else
	{
		TwDefine(" 'Mesh & Selection'/'Obj File' visible=false");
		TwDefine(" 'Mesh & Selection'/'Tet File' visible=true");
	}

	// simulation related
	if (g_simulation->m_solver.m_enable_non_inversion)
	{
		TwDefine(" 'Skinning'/'Barrier/Penalty' visible=true");
	}
	else
	{
		TwDefine(" 'Skinning'/'Barrier/Penalty' visible=false");
	}
	if (g_simulation->m_solver.m_enable_line_search)
	{
		TwDefine(" 'Skinning'/'LS alpha' visible=true");
		TwDefine(" 'Skinning'/'LS beta' visible=true");
		TwDefine(" 'Skinning'/'LS stepsize' readonly=true");
	}
	else
	{
		TwDefine(" 'Skinning'/'LS alpha' visible=false");
		TwDefine(" 'Skinning'/'LS beta' visible=false");
		TwDefine(" 'Skinning'/'LS stepsize' readonly=false");
	}
	// rescaling parameter
	if (g_simulation->m_solver.m_auto_multiplier)
	{
		TwDefine(" 'Skinning'/'Multiplier' readonly=true");
	}
	else
	{
		TwDefine(" 'Skinning'/'Multiplier' readonly=false");
	}
	// substepping
	if (g_simulation->m_solver.m_enable_substepping)
	{
		TwDefine("'Skinning'/'Regularization' readonly=true");
	}
	else
	{
		TwDefine("'Skinning'/'Regularization' readonly=false");
	}

	// give feed back
	int atb_feedback = ATB_DEFAULT;
	if (g_old_screen_width!=g_screen_width || g_old_screen_height!=g_screen_height)
	{
		g_old_screen_width = g_screen_width;
		g_old_screen_height = g_screen_height;
		atb_feedback |= ATB_RESHAPE_WINDOW;
	}
	if (g_old_camera_mode != g_camera_mode)
	{
		g_old_camera_mode = g_camera_mode;
		atb_feedback |= ATB_CHANGE_CAMERA_MODE;
	}
	if (g_old_optimization_method != g_simulation->m_solver.m_optimization_method)
	{
		g_old_optimization_method = g_simulation->m_solver.m_optimization_method;
		atb_feedback |= ATB_CHANGE_METHOD;
	}
#ifdef ENABLE_MATLAB_DEBUGGING
	if (g_old_enable_matlab_debugger != g_debugger->m_enable)
	{
		g_old_enable_matlab_debugger = g_debugger->m_enable;

		if (g_debugger->m_enable)
		{
			atb_feedback |= ATB_INIT_MATLAB;
		}
	}
#endif
	
	return atb_feedback;
}

void AntTweakBarWrapper::SaveSettings()
{
	std::ofstream outfile;
	outfile.open(DEFAULT_CONFIG_FILE, std::ifstream::out);
	if (outfile.is_open())
	{
		// TODO: change it to memory dump.
		// global settings:
		outfile << "HasEnd              " << g_recording_limit << std::endl;
		outfile << "TotalFrame          " << g_total_frame << std::endl;
		outfile << "MeshBody            " << g_mesh_color_type << std::endl;
		outfile << "Wireframe           " << g_show_wireframe << std::endl;
		outfile << "WireframeLineWidth  " << g_wireframe_linewidth << std::endl;
		outfile << "Texture             " << g_show_texture << std::endl;
		outfile << "ScreenWidth         " << g_screen_width << std::endl;
		outfile << "ScreenHeight        " << g_screen_height << std::endl;
		outfile << std::endl;

		// mesh settings:
		outfile << "CameraMode          " << g_camera_mode << std::endl;
		outfile << "ObjPATH             " << g_obj_file_path << std::endl;
		outfile << "MeshPATH            " << g_mesh_file_path << std::endl;
		outfile << "MeshScale           " << g_mesh_scaling << std::endl;
		// selection
		outfile << "HandleColor         " << g_handle_color.x << " " \
										  << g_handle_color.y << " " \
										  << g_handle_color.z << std::endl;
		outfile << "RandomHandleColor   " << g_random_handle_color << std::endl;
		outfile << std::endl;

		//// simulation settings:
		outfile << "SimMethod           " << g_simulation->m_method << std::endl;
		outfile << "AutoPhaseIMethod    " << g_simulation->m_auto_phase_1_method << std::endl;
		outfile << "#Iterations         " << g_simulation->m_iteration_num_simulation << std::endl;
		outfile << "#InnerIterations    " << g_simulation->m_solver.m_inner_loop_iterations << std::endl;
		outfile << "#PyramidSides       " << g_simulation->m_solver.m_pyramid_side_num << std::endl; 
		outfile << "LowRank             " << g_simulation->m_solver.m_low_rank_update << std::endl;
		outfile << "AttachmentStiffness " << g_simulation->m_solver.m_stiffness_attachment << std::endl;
		outfile << "Mu                  " << g_simulation->m_solver.m_mu << std::endl;
		outfile << "Lambda              " << g_simulation->m_solver.m_lambda << std::endl;
		outfile << "EnableNonInversion  " << g_simulation->m_solver.m_enable_non_inversion << std::endl;
		outfile << "BarrierType         " << g_simulation->m_solver.m_barrier_type << std::endl;
		outfile << "NoninversionCrit    " << g_simulation->m_solver.m_noninversion_criteria << std::endl;
		outfile << "UsingExRotBarrier   " << g_simulation->m_solver.m_ex_rot_barrier << std::endl;
		outfile << "BarrierAlpha        " << g_simulation->m_solver.m_alpha << std::endl;
		outfile << "BarrierBeta         " << g_simulation->m_solver.m_beta << std::endl;
		outfile << "BarrierGamma        " << g_simulation->m_solver.m_gamma << std::endl;
		outfile << "AutoMultiplier      " << g_simulation->m_solver.m_auto_multiplier << std::endl;
		outfile << "BarrierMultiplier   " << g_simulation->m_solver.m_multiplier << std::endl;
		outfile << "BarrierSlackness    " << g_simulation->m_solver.m_slackness << std::endl;
		outfile << "OptimizeMethod      " << g_simulation->m_solver.m_optimization_method << std::endl;
		outfile << "LSEnable            " << g_simulation->m_solver.m_enable_line_search << std::endl;
		outfile << "LSStep              " << g_simulation->m_solver.m_ls_stepsize << std::endl;
		outfile << "LSAlpha             " << g_simulation->m_solver.m_ls_alpha << std::endl;
		outfile << "LSBeta              " << g_simulation->m_solver.m_ls_beta << std::endl;
		outfile << std::endl;

		outfile << "test1               " << test1 << std::endl;
		outfile << "test2               " << test2 << std::endl;
		outfile << "test3               " << test3 << std::endl;
		outfile << "test4               " << test4 << std::endl;
		outfile << "test5               " << test5 << std::endl;

		outfile.close();
	}
	else
	{
		std::cerr << "Warning: Can not write config file. Settings not saved." << std::endl; 
	}
}

void AntTweakBarWrapper::LoadSettings()
{
	bool successfulRead = false;

	//read file
	std::ifstream infile;
	infile.open(DEFAULT_CONFIG_FILE, std::ifstream::in);
	if (successfulRead = infile.is_open())
	{
		int tempEnum;
		char ignoreToken[256];

		// global settings:
		infile >> ignoreToken >> g_recording_limit;
		infile >> ignoreToken >> g_total_frame;
		infile >> ignoreToken >> g_mesh_color_type;
		infile >> ignoreToken >> g_show_wireframe;
		infile >> ignoreToken >> g_wireframe_linewidth;
		infile >> ignoreToken >> g_show_texture;
		infile >> ignoreToken >> g_screen_width;
		infile >> ignoreToken >> g_screen_height;

		// mesh settings:
		infile >> ignoreToken >> g_camera_mode;
		infile >> ignoreToken >> g_obj_file_path;
		infile >> ignoreToken >> g_mesh_file_path;
		infile >> ignoreToken >> g_mesh_scaling;
		// selection
		infile >> ignoreToken >> g_handle_color.x \
							  >> g_handle_color.y \
							  >> g_handle_color.z;
		infile >> ignoreToken >> g_random_handle_color;

		// simulation settings:
		infile >> ignoreToken >> tempEnum; g_simulation->m_method = SkinningMethod(tempEnum);
		infile >> ignoreToken >> g_simulation->m_auto_phase_1_method;
		infile >> ignoreToken >> g_simulation->m_iteration_num_simulation;
		infile >> ignoreToken >> g_simulation->m_solver.m_inner_loop_iterations;
		infile >> ignoreToken >> g_simulation->m_solver.m_pyramid_side_num;
		infile >> ignoreToken >> g_simulation->m_solver.m_low_rank_update;
		infile >> ignoreToken >> g_simulation->m_solver.m_stiffness_attachment;
		infile >> ignoreToken >> g_simulation->m_solver.m_mu;
		infile >> ignoreToken >> g_simulation->m_solver.m_lambda;
		infile >> ignoreToken >> g_simulation->m_solver.m_enable_non_inversion;
		infile >> ignoreToken >> tempEnum; g_simulation->m_solver.m_barrier_type=BarrierType(tempEnum);
		infile >> ignoreToken >> tempEnum; g_simulation->m_solver.m_noninversion_criteria=NoninversionCriteria(tempEnum);
		infile >> ignoreToken >> g_simulation->m_solver.m_ex_rot_barrier;
		infile >> ignoreToken >> g_simulation->m_solver.m_alpha;
		infile >> ignoreToken >> g_simulation->m_solver.m_beta;
		infile >> ignoreToken >> g_simulation->m_solver.m_gamma;
		infile >> ignoreToken >> g_simulation->m_solver.m_auto_multiplier;
		infile >> ignoreToken >> g_simulation->m_solver.m_multiplier;
		infile >> ignoreToken >> g_simulation->m_solver.m_slackness;
		infile >> ignoreToken >> tempEnum; g_simulation->m_solver.m_optimization_method = OptimizationMethod(tempEnum);
		infile >> ignoreToken >> g_simulation->m_solver.m_enable_line_search;
		infile >> ignoreToken >> g_simulation->m_solver.m_ls_stepsize;
		infile >> ignoreToken >> g_simulation->m_solver.m_ls_alpha;
		infile >> ignoreToken >> g_simulation->m_solver.m_ls_beta;

		infile >> ignoreToken >> test1;
		infile >> ignoreToken >> test2;
		infile >> ignoreToken >> test3;
		infile >> ignoreToken >> test4;
		infile >> ignoreToken >> test5;

		infile.close();
	}

	// setup default values
	if (!successfulRead)
	{
		std::cerr << "Waning: failed loading settings, set to defaults." << std::endl;
		DefaultSettings();
	}

	// init event related variables
	g_old_screen_width = g_screen_width;
	g_old_screen_height = g_screen_height;
}

void AntTweakBarWrapper::DefaultSettings()
{
	// global settings
	g_recording_limit = true;
	g_total_frame = 1000;
	g_mesh_color_type = 1;
	g_show_wireframe = false;
	g_wireframe_linewidth = 1;
	g_show_texture = false;
	g_screen_width = 1024;
	g_screen_height = 768;

	// mesh settings
	g_camera_mode = MODE_2D;
	strcpy(g_obj_file_path, DEFAULT_OBJ_MODEL);
	strcpy(g_mesh_file_path, DEFAULT_MESH_MODEL);
	g_mesh_scaling = 1.0;
	// selection
	g_handle_color = glm::vec3(0.3f, 1.0f, 0.3f);
	g_random_handle_color = false;

	//simulation settings
	g_simulation->m_method = SKINNING_EXROT;

	g_simulation->m_solver.m_stiffness_attachment = 100;
	g_simulation->m_auto_phase_1_method = false;
	g_simulation->m_iteration_num_simulation = 1;
	g_simulation->m_solver.m_inner_loop_iterations = 10;
	g_simulation->m_solver.m_pyramid_side_num = 3;
	g_simulation->m_solver.m_low_rank_update = true;
	g_simulation->m_solver.m_mu = 50;
	g_simulation->m_solver.m_lambda = 0;
	g_simulation->m_solver.m_enable_non_inversion = false;
	g_simulation->m_solver.m_barrier_type = BARRIER_TYPE_LOG;
	g_simulation->m_solver.m_noninversion_criteria = NC_DETERMINANT_W;
	g_simulation->m_solver.m_ex_rot_barrier = true;
	g_simulation->m_solver.m_alpha = 1;
	g_simulation->m_solver.m_beta = 1;
	g_simulation->m_solver.m_gamma = 1;
	g_simulation->m_solver.m_auto_multiplier = true;
	g_simulation->m_solver.m_multiplier = 1;
	g_simulation->m_solver.m_slackness = 0;
	g_simulation->m_solver.m_optimization_method = OPTIMIZATION_LOCALLY_INJECTIVE_MAPPING;
	g_simulation->m_solver.m_enable_line_search = true;
	g_simulation->m_solver.m_ls_stepsize = 1.0;
	g_simulation->m_solver.m_ls_alpha = 0.8;
	g_simulation->m_solver.m_ls_beta = 0.2;

}

void TW_CALL AntTweakBarWrapper::SaveSettings(void* atb_wrapper)
{
	AntTweakBarWrapper* atb_wrapper_ref = (AntTweakBarWrapper*) atb_wrapper;
	atb_wrapper_ref->SaveSettings();
}

void TW_CALL AntTweakBarWrapper::LoadSettings(void* atb_wrapper)
{
	AntTweakBarWrapper* atb_wrapper_ref = (AntTweakBarWrapper*) atb_wrapper;
	atb_wrapper_ref->LoadSettings();
	//resetSimulation(NULL);
}

void TW_CALL AntTweakBarWrapper::SetDefaultSettings(void* atb_wrapper)
{
	AntTweakBarWrapper* atb_wrapper_ref = (AntTweakBarWrapper*) atb_wrapper;
	atb_wrapper_ref->DefaultSettings();
	//resetSimulation(NULL);
}