/******************************************************************************
 * The MIT License (MIT)
 * 
 * Copyright (c) 2014 Crytek
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/


#include <string>
#include <utility>
#include <vector>
#include <map>
using std::vector;
using std::pair;
using std::string;
using std::map;

#pragma once

#include "dxbc_disassemble.h"

namespace DXBC
{
	
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Partial (and by that I mean very partial) spec of the SDBG debug information chunk in shader bytecode.
//
// Very much work in progress, feel free to contribute if you figure out what some of the fields are or have
// a correction.
//
// I've documented assumptions/guesses/suppositions where relevant. There are plenty of them.
//
// Current completely understood structures:
//  * SDBGHeader
//  * SDBGFileHeader
//  * SDBGSymbol
//  * SDBGType
//  * SDBGScope
//
// Structures that are understood but with unknown elements:
//  * SDBGAsmInstruction
//
// Structures that are partly understood, but their place/purpose is still vague:
//  * SDBGVariable
//  * SDBGInputRegister
////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct CountOffset
{
	int32_t count;
	int32_t offset;
};

// Completely understood
struct SDBGHeader
{
	int32_t version;				// Always 0x00000054 it seems. Probably a version number, might be some other ID
	
	int32_t compilerSigOffset;	// offset from asciiOffset at the end of this structure.
	int32_t entryFuncOffset;		// offset from asciiOffset at the end of this structure.
	int32_t profileOffset;		// offset from asciiOffset at the end of this structure.

	uint32_t shaderFlags;			// Shader flags - same as from reflection.

	// All offsets are after this header.
	CountOffset files;			// total unique files opened and used via #include
	CountOffset instructions;	// assembly instructions
	CountOffset variables;		// Looks to be the variables (one per component) used in the shader
	CountOffset inputRegisters;	// This lists which bits of which inputs are used - e.g. the components in input
								// signature elements and cbuffers.
	CountOffset symbolTable;	// This is a symbol table definitely, also includes 'virtual' symbols to match
								// up ASM instructions to lines.
	CountOffset scopes;			// These are scopes - like for structures/functions. Also Globals/Locals lists of variables
								// in scope for reference in ASM instructions
	CountOffset types;			// Type specifications

	int32_t int32DBOffset;		// offset after this header. Same principle as ASCII db, but for int32s

	int32_t asciiDBOffset;		// offset after this header to the ASCII data. This is a general "ascii database section"
								// or similar because it has file sources, generated symbol names, etc. Hefty deduping goes
								// on here, so if the hlsl source is included then offsets for symbols etc in that source
								// point inside that source - only generated names like "structure::member" that don't exist
								// in the source are duplicated after. Same goes for hlsl include file names, they're always
								// obviously in the source somewhere.
};



// Completely understood
// one per included file (unique). First always exists and is the hlsl file passed to the compiler
struct SDBGFileHeader
{
	int32_t filenameOffset;		// offset into the ascii Database where the filename sits.
	int32_t filenameLen;			// filename path. Absolute for root file, relative for other headers

	int32_t sourceOffset;			// offset into the ascii Database where this file's source lives
	int32_t sourceLen;			// bytes in source file. Valid for all file headers
};

// Partly understood, many unknown/guessed elements. Completely understood how this fits in in the overall structure
// Details of each assembly instruction
struct SDBGAsmInstruction
{
	int32_t instructionNum;

	OpcodeType opCode;

	int32_t unknown_a[2];
	int32_t destRegister;
	int32_t unknown_b;

	int32_t destXMask;				// 00 if writing to this component in dest register, -1 if not writing
	int32_t destYMask;				// 01		"				"				"				"
	int32_t destZMask;				// 02		"				"				"				"
	int32_t destWMask;				// 03		"				"				"				"

	struct Component
	{
		int32_t varID;				// matches SDBGVariable below
		float lowBounds[2];		// what's this? defaults  0.0 to -QNAN. Some kind of bound.
		float highBounds[2];	// what's this?			 -0.0 to  QNAN. Some kind of bound.
		float minBound;			// min value this components's dest can be
		float maxBound;			// max value	"			"			"
		int32_t unknown_a[2];
	} component[4];

	int32_t unknown_c[9];

	// I don't know what this is, but it's 9 int32s and 4 of them, so sounds like
	// something that's per-component
	struct Something
	{
		int32_t unknown[9];
	} somethings[4];

	int32_t unknown_d[2];

	int32_t symbol;				// symbol, usually virtual I think, that links this instruction
								// to somewhere in hlsl - e.g. a line number and such

	int32_t callstackDepth;		// 0-indexed current level of the callstack. ie. 0 is in the main function, 1 is in a sub-function, etc etc.

	CountOffset scopes;			// The scopeIDs that show the call trace in each instruction (or rather, where this instruction takes place).
								// it has several elements: N Locals entries, with different locals for different scopes or branches
								// (this doesn't quite make sense yet. Some Locals lists can contain variables from if AND else branches,
								// or include variables that have gone out of scope). Then it contains a single element pointing to the current
								// function, then a globals list showing all variables and return-value functions in global scope at this point.
	CountOffset varTypes;		// The Type IDs of variables involved in this instruction. Possibly in source,source,dest order but
								// maybe not.
};

// Mostly understood, a couple of unknown elements and/or not sure how it fits together in the grand scheme
struct SDBGVariable
{
	int32_t symbolID;				// Symbol this assignment depends on
	VariableType type;
	int32_t unknown[2];
	int32_t typeID;				// refers to SDBGType. -1 if a constant
	union
	{
		int32_t component;			// x=0,y=1,z=2,w=3
		float value;			// const value
	};
};

// Mostly understood, a couple of unknown elements and/or not sure how it fits together in the grand scheme
struct SDBGInputRegister
{
	int32_t varID;
	int32_t type;					// 2 = from cbuffer, 0 = from input signature, 6 = from texture, 7 = from sampler
	int32_t cbuffer_register;		// -1 if input signature
	int32_t cbuffer_packoffset;	// index of input signature
	int32_t component;				// x=0,y=1,z=2,w=3
	int32_t initValue;				// I think this is a value? -1 or some value. Or maybe an index.
};

// Completely understood
struct SDBGSymbol
{
	int32_t fileID;				// index into SDBGFileHeader array
	int32_t lineNum;
	int32_t characterNum;			// not column, so after a tab would just be 1.
	CountOffset symbol;			// offset can be 0 for 'virtual' symbols
};

// Almost entirely understood, there is sometimes redundancy in that the same scope appears with
// different tree entries that overlap and are supersets. Seems like MAYBE each new instruction it
// shows all the variables in scope up to that point, but the scope tree is inconsistent e.g. in what
// ends up in Globals. Still useful for resolving types though
struct SDBGScope
{
	int32_t type;					// what kind of type I have no idea. 0 = Globals, 1 = Locals, 3 = Structure, 4 = Function
	int32_t symbolNameOffset;		// offset from start of ascii Database
	int32_t symbolNameLength;
	CountOffset scopeTree;
};

// Completely understood
struct SDBGType
{
	int32_t symbolID;
	int32_t isFunction;			// 0 / 1
	int32_t type;					// 0 == scalar, 1 == vector, 3 == matrix, 4 == texture/sampler
	int32_t typeNumRows;			// number of floats in the height of the base type (mostly for matrices)
	int32_t typeNumColumns;		// number of floats in the width of the base type. 0 for functions or structure types
	int32_t scopeID;				// if type is a complex type (including function return type), the scope of this type.
	int32_t arrayDimension;		// 0, 1, 2, ...
	int32_t arrayLenOffset;		// offset into the int32 database. Contains an array length for each dimension
	int32_t stridesOffset;		// offset into the int32 database. Contains the stride for that level, for each dimension.
								// so with array[a][b][c] it has b*c*baseSize, then c*baseSize then baseSize
	int32_t numFloats;			// number of floats in this type (or maybe 32bit words, not sure).
	int32_t varID;				// Variable ID, or -1 if this variable isn't used.
};


// SDBG chunk gets its own class since it's so complex. Deliberately fairly leaky too
// since the data + use is a bit unclear still
class SDBGChunk : public DXBCDebugChunk
{
	public:
		SDBGChunk(void *data);
		
		string GetCompilerSig() const { return m_CompilerSig; }
		string GetEntryFunction() const { return m_Entry; }
		string GetShaderProfile() const { return m_Profile; }

		uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; }

		void GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const;
		
		DXBCDebugChunk *Clone() const { return new SDBGChunk(*this); }
	private:
		bool m_HasDebugInfo;

		string GetSymbolName(int symbolID);
		string GetSymbolName(int32_t symbolOffset, int32_t symbolLength);

		vector<SDBGAsmInstruction> m_Instructions;
		vector<SDBGVariable> m_Variables;
		vector<SDBGInputRegister> m_Inputs;
		vector<SDBGSymbol> m_SymbolTable;
		vector<SDBGScope> m_Scopes;
		vector<SDBGType> m_Types;
		vector<int32_t> m_Int32Database;

		uint32_t m_ShaderFlags;

		string m_CompilerSig;
		string m_Entry;
		string m_Profile;

		SDBGChunk();

		// these don't need to be exposed, a more processed and friendly
		// version is exposed
		SDBGHeader m_Header;
		vector<SDBGFileHeader> m_FileHeaders;

		vector<char> m_RawData;
};

};
