#ifndef OTHER_CPP
#define OTHER_CPP

#include <core/inc.hpp>

auto cheat_interface::c_visual::render_other( ) -> void
{
	try {

		if ( !g_ctx ) return;

		if ( !g_ctx->view_state ) return;

		if ( g_vars->visuals.china_hat )
		{
			auto do_hat = [ & ] ( ) -> void
			{
				ImColor set_hat_color = ImColor(
					g_vars->colors.hat_color [ 0 ], g_vars->colors.hat_color [ 1 ], g_vars->colors.hat_color [ 2 ], g_vars->colors.hat_color [ 3 ]
				);

				ImColor set_hat_col = g_framework->get_color( set_hat_color.Value.x, set_hat_color.Value.y, set_hat_color.Value.z,
					static_cast< enums::ColorMode >( g_vars->visuals.china_mode )
				);

				set_hat_col.Value.w = g_vars->colors.hat_color [ 3 ];

				if ( g_ctx->in_lobby ) return;
				if ( !g_ctx->localplayer.player_pawn->is_valid( ) ) return;

				auto local_mesh = g_ctx->localplayer.player_pawn->mesh( );
				if ( !local_mesh->is_valid( ) ) return;

				auto local_head_bone = g_engine->get_bone( local_mesh->get_current_class( ), enums::c_bones::head );
				if ( !local_head_bone ) return;

				local_head_bone.z += 23.f;

				g_framework->chinese_hat_points( 
					local_head_bone,
					g_vars->visuals.hat_points,
					g_vars->visuals.hat_radius,
					g_vars->visuals.hat_height,
					g_vars->visuals.china_outline,
					g_vars->visuals.fading_hat,
					set_hat_col
				);
			};

			do_hat( );
		}

		if ( g_vars->misc.movement_tracers )
		{
			std::unique_lock<std::mutex> lock( g_misc->movement_mutex );
			std::vector<object::movements>& tracer = g_misc->g_movement_positions;

			math::vector3 previous_position;
			bool has_previous = false;

			for ( auto it = tracer.begin( ); it != tracer.end( );) {
				auto now = std::chrono::high_resolution_clock::now( );
				auto duration = std::chrono::duration_cast< std::chrono::milliseconds >( now - it->timestamp );

				const int max_duration = g_vars->misc.movement_tracers_lifetime * 1000;
				if ( duration.count( ) > max_duration ) {
					it = tracer.erase( it );
					continue;
				}

				math::vector3 current_position = g_engine->world_to_screen( it->position );

				if ( !g_engine->in_screen(current_position ) ) {
					++it;
					continue;
				}

				ImVec2 start = ImVec2( previous_position.x, previous_position.y );
				ImVec2 end = ImVec2( current_position.x, current_position.y );

				ImColor color = g_framework->get_color( g_vars->colors.movement_tracers_color [ 0 ], g_vars->colors.movement_tracers_color [ 1 ], g_vars->colors.movement_tracers_color [ 2 ],
					static_cast< enums::ColorMode >( g_vars->misc.movement_tracers_mode ),
					g_vars->ui.rgb_speed
				);

				float fade_factor = 1.00f;

				if ( g_vars->misc.movement_tracers_fade ) {
					fade_factor = 1.0f - static_cast< float >( duration.count( ) ) / ( max_duration * g_vars->misc.movement_tracers_fade_speed );
					color.Value.w = fade_factor;
				}

				ImColor outline_color = ImColor( 0.00f, 0.00f, 0.00f, fade_factor );

				if ( has_previous )
				{
					switch ( g_vars->misc.movement_tracers_line_mode ) {
					case SOLID:
						if ( g_vars->misc.movement_tracers_outline ) g_framework->line( start, end, outline_color, g_vars->misc.movement_tracers_thickness + 0.4f );
						g_framework->line( start, end, color, g_vars->misc.movement_tracers_thickness );
						break;
					case DOTTED:
						if ( g_vars->misc.movement_tracers_outline ) g_framework->dotted_line( start, end, outline_color, g_vars->misc.movement_tracers_thickness + 0.4f, g_vars->ui.dotted_gap );
						g_framework->dotted_line( start, end, color, g_vars->misc.movement_tracers_thickness, g_vars->ui.dotted_gap );
						break;
					case DASHED:
						if ( g_vars->misc.movement_tracers_outline ) g_framework->dashed_line( start, end, outline_color, g_vars->misc.movement_tracers_thickness + 0.4f, g_vars->ui.dashed_gap );
						g_framework->dashed_line( start, end, color, g_vars->misc.movement_tracers_thickness, g_vars->ui.dashed_gap );
						break;
					}
				}

				previous_position = current_position;
				has_previous = true;

				++it;
			}

			lock.unlock( );
		}

		if ( g_vars->misc.bullet_tracers )
		{
			std::unique_lock<std::mutex> lock( g_misc->projectiles_mutex );
			std::vector<object::projcetiles>& tracer = g_misc->g_projectiles;

			for ( auto it = tracer.begin( ); it != tracer.end( ); )
			{
				auto now = std::chrono::high_resolution_clock::now( );
				auto duration = std::chrono::duration_cast< std::chrono::milliseconds >( now - it->timestamp );

				const int max_duration = g_vars->misc.bullet_tracers_lifetime * 1000;
				if ( duration.count( ) > max_duration ) {
					it = tracer.erase( it );
					continue;
				}

				math::vector3 bullet_start = g_engine->world_to_screen( it->start_point );
				if ( !g_engine->in_screen( bullet_start ) ) {
					++it;
					continue;
				}

				math::vector3 bullet_end = g_engine->world_to_screen( it->hit_point );
				if ( !g_engine->in_screen( bullet_end ) ) {
					++it;
					continue;
				}

				ImVec2 start = ImVec2( bullet_start.x, bullet_start.y );
				ImVec2 end = ImVec2( bullet_end.x, bullet_end.y );

				ImColor color = g_framework->get_color( g_vars->colors.bullet_tracers_color [ 0 ], g_vars->colors.bullet_tracers_color [ 1 ], g_vars->colors.bullet_tracers_color [ 2 ],
					static_cast< enums::ColorMode >( g_vars->misc.bullet_tracers_mode ),
					g_vars->ui.rgb_speed
				);

				float fade_factor = 1.00f;

				if ( g_vars->misc.bullet_tracers_fade_effect ) {
					fade_factor = 1.0f - static_cast< float >( duration.count( ) ) / ( max_duration * g_vars->misc.bullet_tracers_fade_speed );
					color.Value.w = fade_factor;
				}

				ImColor outline_color = ImColor( 0.00f, 0.00f, 0.00f, fade_factor );

				switch ( g_vars->misc.bullet_tracers_line_mode ) {
				case SOLID:
					if ( g_vars->misc.bullet_tracers_outline ) g_framework->line( start, end, outline_color, g_vars->misc.bullet_tracers_thickness + 0.4f );
					g_framework->line( start, end, color, g_vars->misc.bullet_tracers_thickness );
					break;
				case DOTTED:
					if ( g_vars->misc.bullet_tracers_outline ) g_framework->dotted_line( start, end, outline_color, g_vars->misc.bullet_tracers_thickness + 0.4f, g_vars->ui.dotted_gap );
					g_framework->dotted_line( start, end, color, g_vars->misc.bullet_tracers_thickness, g_vars->ui.dotted_gap );
					break;
				case DASHED:
					if ( g_vars->misc.bullet_tracers_outline ) g_framework->dashed_line( start, end, outline_color, g_vars->misc.bullet_tracers_thickness + 0.4f, g_vars->ui.dashed_gap );
					g_framework->dashed_line( start, end, color, g_vars->misc.bullet_tracers_thickness, g_vars->ui.dashed_gap );
					break;
				}

				it++;
			}

			lock.unlock( );
		}
	}
	catch ( const std::exception& e ) {
		m_log->set_text_point( hash_str( "exception caught in entity render thread" ) );
		return;
	}
	catch ( ... ) {
		m_log->set_text_point( hash_str( "exception caught in entity render thread" ) );
		return;
	}
}

#endif