#include "Debugger.h"


/* - GL debugger - */
void uniform_location()
{
	while (glGetError() != GL_NO_ERROR)
	{
		// do nothing
	}
}

bool GlLogCall(const char* filepath, int line, const char* function)
{
	while (GLenum error_code = glGetError())
	{
		std::cout << "[GL Error] " << filepath << "\n  Code : " << error_code << "\n  Line : "<< line << "\n  Function : " << function << std::endl;
		return false;
	}
	return true;
}


/* - Application debugger - */
// 싱글톤 패턴 구현을 위한 정적 포인터 변수를 미리 정의 후 초기화 (Static pointer for singleton pattern debug thread)
Debugger* Debugger::mp_debugInstance = NULL;


Debugger::Debugger()
{

}


Debugger::~Debugger()
{
	
}


/* - 디버그 클래스의 포인터 값을 반환하는 함수 (싱글톤 스레드) | Return the debug class instance - */
Debugger* Debugger::GetInstance()
{
	if (NULL == mp_debugInstance) // 포인터가 NULL일 경우
	{
		mp_debugInstance = new Debugger(); // 힙 영역에 동적 할당 후 포인터에 저장
	}
	return mp_debugInstance; // 포인터 리턴
}


/* - 디버그 클래스의 포인터를 제거하는 함수 | Delete the debug class instance - */
void Debugger::FreeInstance()
{
	if (NULL != mp_debugInstance) // 포인터가 비어있지 않다면
	{
		delete mp_debugInstance; // 메모리 해제
		mp_debugInstance = NULL;
	}
}


/* - 실행중인 프로그램 경로를 가져오는 함수 | Get program path - */
std::string Debugger::GetProgramPath(void)
{
	if (m_filepath.empty() == true) // 캐시된 파일 경로가 없는 경우
	{
		char* filePathBuffer; // 임시 파일경로 버퍼
		int cutPosition; // 임시 파일경로 버퍼의 자를 문자 위치
		//std::string m_filepath; // 캐시된 프로그램 경로
		std::string cutPath = "PROJECT"; // 자를 문자열(폴더)

		// 파일 경로 받아오기
		if ((filePathBuffer = _getcwd(NULL, 0)) == NULL)
		{
			WriteError("Unable to get the program path from _getcwd !");
		}
		else
		{
			// 최종 버퍼를 스트링으로 저장
			m_filepath = std::string(filePathBuffer);

			// 자를 문자열(폴더위치)이 몇번째 문자부터 시작하는지 뒤에서부터 찾았다가 위치 기억
			cutPosition = (int)m_filepath.rfind(cutPath);
			cutPosition += (int)cutPath.length();

			// 첫번째 폴더위치 까지만 남기고 나머지 경로 제거
			m_filepath.erase(cutPosition, m_filepath.length() - cutPosition);

			// 버퍼 비우기
			free(filePathBuffer);

			// _getcwd로 추출한 파일 경로 표시
			WriteMessage("Extracting the program path... \n" + m_filepath);
		}
	}

	return m_filepath; // 최종 파일경로 반환
}


/* - 그래픽 카드 정보를 출력하는 함수 | Show graphics card information - */
void Debugger::ShowGLInfo()
{
	std::cout << "[Info] Graphics card info // ";
	std::cout << glGetString(GL_VENDOR) << " // " << glGetString(GL_RENDERER) << " // " << glGetString(GL_VERSION) << std::endl;
}


/* - 디버깅용 콘솔을 띄우는 함수 | Open debug console - */
void Debugger::StartHelper()
{
	while (1)
	{
		// 도움말 표시
		WriteMessage(_DEBUGER_INFO_);
		WriteMessage("Write 0 and press the enter key to exit the program...");
		WriteMessage("Write 1 and press the enter key to open the help ...");
		WriteMessage("Write 2 and press the enter key to display the current FPS...");

		int menu_selector = INT_MAX; // 콘솔 명령을 받기 위한 변수
		std::cin >> menu_selector; // 콘솔 명령어 받기

		if (menu_selector == 0) // 만약 콘솔 명령어로 0이라는 숫자를 받았을때
		{
			exit(0); // 프로그램 정상 종료
		}
		else if (menu_selector == 1) // 만약 콘솔 명령어로 1이라는 숫자를 받았을때
		{
			continue; // while문 다시 시작 (도움말 표시)
		}
		else if (menu_selector == 2) // 만약 콘솔 명령어로 2이라는 숫자를 받았을때
		{
			if (m_showFps == false)
			{
				m_showFps = true; // FPS 표시 활성화
				WriteMessage("FPS counter enabled...");
			}
			else
			{
				m_showFps = false; // FPS 표시 비활성화
				WriteMessage("FPS counter disabled...");
			}
		}
		else // 만약 콘솔 명령어로 잘못된 값을 받았을때
		{
			WriteMessage("Invalid command...");

			// 잘못된 명령을 받은 경우 버퍼 비우기
			std::cin.clear(); // cin 상태 초기화
			std::cin.ignore(); // 입력 버퍼 초기화
		}
	}
}


/* - 디버깅용 메세지를 출력하는 함수 | Output debug information in debug console - */
void Debugger::WriteMessage(const std::string message)
{
	// 메세지 출력
	std::cout << "[Info] " << message << std::endl;
}


/* - 콘솔에 오류를 표시하는 함수 | Show fatal error in console - */
void Debugger::WriteError(const std::string error_message)
{
	// 소프트웨어 오류 내용 출력
	std::cout << "[App Error] \n" << error_message << std::endl;

	// 시스템 오류 내용 출력
	std::perror("[System Error] ");

	// 프로그램 종료 메세지 표시
	WriteMessage("Fatal error has occurred. Press any key to close this Program...");

	// 콘솔 임시 대기
	std::system("pause");

	exit(1); // 프로그램 비정상 종료
}
