#ifndef PDB_HPP
#define PDB_HPP

#define EZ_PDB_BASE_OF_DLL (DWORD64)0x10000000

namespace pdb_interface
{
	inline auto random_string( int32_t len ) -> std::string {
		static const char strComp[ ] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.()_";
		static const uint32_t szStrComp = ( sizeof( strComp ) - 1 );

		std::string result;
		result.reserve( len );

		while ( len-- > 0 ) {
			char c = strComp[ rand( ) % szStrComp ];
			bool upper = rand( ) % 2;

			if ( isalpha( c ) )
				result.push_back( upper ? std::toupper( c ) : c );
			else
				result.push_back( c );
		}
		return result;
	}

	struct pdb_header
	{
		char signature[ 0x20 ];
		int page_size;
		int allocation_table_pointer;
		int file_page_count;
		int root_stream_size;
		int reserved;
		int root_stream_page_number_list_number;
	};

	struct root_stream
	{
		int num_streams;
		int stream_sizes[ 1 ]; //num_streams
	};

	struct guid_stream_data
	{
		int ver;
		int date;
		int age;
		GUID guid;
	};

	struct pdb_info
	{
		DWORD	signature;
		GUID	guid;
		DWORD	age;
		char	pdb_file_name[ 1 ];
	};

	typedef struct _pdb
	{
		HANDLE process;
		HANDLE pdb_file;
	}pdb, *pdb_context;

	class c_pdb {
	public:
		std::string download_pdb_to_temp( std::string service );

		bool load_pdb(
			std::string pdb_path,
			pdb_context pdb_object
		);

		std::uint64_t get_rva( pdb_context pdb_object, std::string symbol_name );
		std::uint64_t get_struct_property_offset( pdb_context pdb_object, std::string struct_name, std::wstring property_name );
		std::uint64_t get_struct_size( pdb_context pdb_object, std::string struct_name );

		void unload_pdb( pdb_context pdb_object );
	};
} inline auto g_pdb = std::make_unique<pdb_interface::c_pdb>( );

#endif // ! guard