#pragma once

#include "Types.h"
#include <map>
#include <vector>
#include <functional>
#include <string>

class CMIPS;

class CMIPSAnalysis
{
public:
	struct SUBROUTINE
	{
		uint32 start;
		uint32 end;
		uint32 stackAllocStart;
		uint32 stackAllocEnd;
		uint32 stackSize;
		uint32 returnAddrPos;
	};

	typedef std::vector<uint32> CallStackItemArray;

	CMIPSAnalysis(CMIPS*);
	void Analyse(uint32, uint32, uint32 = -1);
	const SUBROUTINE* FindSubroutine(uint32) const;
	void Clear();

	void InsertSubroutine(uint32, uint32, uint32, uint32, uint32, uint32);
	void ChangeSubroutineStart(uint32, uint32);
	void ChangeSubroutineEnd(uint32, uint32);

	static CallStackItemArray GetCallStack(CMIPS*, uint32 pc, uint32 sp, uint32 ra);
	static bool TryGetStringAtAddress(CMIPS*, uint32, std::string&);
	static bool TryGetSJISLatinStringAtAddress(CMIPS*, uint32, std::string&);

private:
	typedef std::map<uint32, SUBROUTINE, std::greater<uint32>> SubroutineList;

	uint32 GetInstruction(uint32) const;

	void AnalyseSubroutines(uint32, uint32, uint32);
	void AnalyseStringReferences();

	void FindSubroutinesByStackAllocation(uint32, uint32);
	void FindSubroutinesByJumpTargets(uint32, uint32, uint32);
	void ExpandSubroutines(uint32, uint32);

	CMIPS* m_ctx = nullptr;
	SubroutineList m_subroutines;
};
