//============================================================
// <T>转换脚本。</T>
//
// @param pOutputScript 输出脚本
// @param pInputScript 输入脚本
// @return 处理结果
//============================================================
TResult FPoRenderShaderTransformer::Convert(MString* pOutputScript, MString* pInputScript){
   Hlsl2Glsl_Initialize();
   ShHandle parser = Hlsl2Glsl_ConstructCompiler(EShLangVertex);
   TInt parseOk = Hlsl2Glsl_Parse(parser, pInputScript->MemoryC(), ETargetGLSL_120, ETranslateOpIntermediate);
	TCharC* pInfo = Hlsl2Glsl_GetInfoLog(parser);
   if(parseOk){
   	TInt translateOk = Hlsl2Glsl_Translate(parser, "main", ETargetGLSL_120, ETranslateOpIntermediate);
		TCharC* infoLog = Hlsl2Glsl_GetInfoLog( parser );
		if(translateOk){
      	TCharC* pGlslScript = Hlsl2Glsl_GetShader(parser);
         pOutputScript->Assign(pGlslScript);
      }
   }
   Hlsl2Glsl_DestructCompiler(parser);
	Hlsl2Glsl_Shutdown();
   return ESuccess;
}
static bool TestFileFailure (TestRun type,
	const std::string& inputPath,
	const std::string& outputPath)
{
	std::string input;
	if (!ReadStringFromFile (inputPath.c_str(), input))
	{
		printf ("  failed to read input file\n");
		return false;
	}

	ShHandle parser = Hlsl2Glsl_ConstructCompiler (kTypeLangs[type]);
	const ETargetVersion version = kTargets1[type];

	const char* sourceStr = input.c_str();

	bool res = true;

	unsigned options = 0;
	if (kDumpShaderAST)
		options |= ETranslateOpIntermediate;
	int parseOk = Hlsl2Glsl_Parse (parser, sourceStr, version, NULL, options);
	
	if (parseOk)
	{
		int translateOk = Hlsl2Glsl_Translate (parser, "main", version, options);
		
		if (translateOk) 
		{
			printf ("  translation was expected to fail\n");
		    res = false;
		}
    }
    
	std::string text = Hlsl2Glsl_GetInfoLog( parser );
	if (!res)
	{
		text += "\n// compiled shader:\n";
		text += Hlsl2Glsl_GetShader (parser);
	}
	std::string output;
	
	if (res)
	{
	    ReadStringFromFile (outputPath.c_str(), output);
    }
    
	if (!res || (text != output))
	{
		// write output
		FILE* f = fopen (outputPath.c_str(), "wb");
		fwrite (text.c_str(), 1, text.size(), f);
		fclose (f);
		printf ("  does not match expected output\n");
		res = false;
	}

	Hlsl2Glsl_DestructCompiler (parser);

	return res;
}
static bool TestFile (TestRun type,
					  const std::string& inputPath,
					  const std::string& outputPath,
					  const char* entryPoint,
					  ETargetVersion version,
					  unsigned options,
					  bool doCheckGLSL)
{
	assert(version != ETargetVersionCount);
	
	std::string input;
	if (!ReadStringFromFile (inputPath.c_str(), input))
	{
		printf ("  failed to read input file\n");
		return false;
	}
	
	ShHandle parser = Hlsl2Glsl_ConstructCompiler (kTypeLangs[type]);

	const char* sourceStr = input.c_str();

	bool res = true;

	if (kDumpShaderAST)
		options |= ETranslateOpIntermediate;
	
	IncludeContext includeCtx;
	includeCtx.currentFolder = inputPath.substr(0, inputPath.rfind('/'));
	Hlsl2Glsl_ParseCallbacks includeCB;
	includeCB.includeOpenCallback = IncludeOpenCallback;
	includeCB.includeCloseCallback = NULL;
	includeCB.data = &includeCtx;
		
	int parseOk = Hlsl2Glsl_Parse (parser, sourceStr, version, &includeCB, options);
	const char* infoLog = Hlsl2Glsl_GetInfoLog( parser );
	if (kDumpShaderAST)
	{
		// write output
		FILE* f = fopen ((outputPath+"-ir.txt").c_str(), "wb");
		fwrite (infoLog, 1, strlen(infoLog), f);
		fclose (f);
	}
	if (parseOk)
	{
		static EAttribSemantic kAttribSemantic[] = {
			EAttrSemTangent,
		};
		static const char* kAttribString[] = {
			"TANGENT",
		};
		Hlsl2Glsl_SetUserAttributeNames (parser, kAttribSemantic, kAttribString, 1);
		
		int translateOk = Hlsl2Glsl_Translate (parser, entryPoint, version, options);
		const char* infoLog = Hlsl2Glsl_GetInfoLog( parser );
		if (translateOk)
		{
			std::string text = GetCompiledShaderText(parser);
			
			for (size_t i = 0, n = text.size(); i != n; ++i)
			{
			   char c = text[i];
			   
			   if (!isascii(c))
			   {
				   printf ("  contains non-ascii '%c' (0x%02X)\n", c, c);
				   res = false;
			   }
			}

			std::string output;
			ReadStringFromFile (outputPath.c_str(), output);

			if (text != output)
			{
				// write output
				FILE* f = fopen (outputPath.c_str(), "wb");
				fwrite (text.c_str(), 1, text.size(), f);
				fclose (f);
				printf ("  does not match expected output\n");
				res = false;
			}
			if (doCheckGLSL && !CheckGLSL (kIsVertexShader[type], version, text))
			{
				res = false;
			}
		}
		else
		{
			printf ("  translate error: %s\n", infoLog);
			res = false;
		}
	}
	else
	{
		printf ("  parse error: %s\n", infoLog);
		res = false;
	}

	Hlsl2Glsl_DestructCompiler (parser);

	return res;
}
static bool TestFile (bool vertex,
	const std::string& inputPath,
	const std::string& outputPath,
	bool usePrecision,
	bool doCheckGLSL)
{
	std::string input;
	if (!ReadStringFromFile (inputPath.c_str(), input))
	{
		printf ("  failed to read input file\n");
		return false;
	}

	ShHandle parser = Hlsl2Glsl_ConstructCompiler (vertex ? EShLangVertex : EShLangFragment);

	const char* sourceStr = input.c_str();

	bool res = true;

	int options = 0;
	if (kDumpShaderAST)
		options |= ETranslateOpIntermediate;
	if (usePrecision)
		options |= ETranslateOpUsePrecision;
	int parseOk = Hlsl2Glsl_Parse (parser, sourceStr, options);
	const char* infoLog = Hlsl2Glsl_GetInfoLog( parser );
	if (kDumpShaderAST)
	{
		// write output
		FILE* f = fopen ((outputPath+"-ir.txt").c_str(), "wb");
		fwrite (infoLog, 1, strlen(infoLog), f);
		fclose (f);
	}
	if (parseOk)
	{
		static EAttribSemantic kAttribSemantic[] = {
			EAttrSemTangent,
		};
		static const char* kAttribString[] = {
			"TANGENT",
		};
		Hlsl2Glsl_SetUserAttributeNames (parser, kAttribSemantic, kAttribString, 1);
		Hlsl2Glsl_UseUserVaryings (parser, true);
		int translateOk = Hlsl2Glsl_Translate (parser, "main", options);
		const char* infoLog = Hlsl2Glsl_GetInfoLog( parser );
		if (translateOk)
		{
			std::string text = Hlsl2Glsl_GetShader (parser);

			std::string output;
			ReadStringFromFile (outputPath.c_str(), output);

			if (text != output)
			{
				// write output
				FILE* f = fopen (outputPath.c_str(), "wb");
				fwrite (text.c_str(), 1, text.size(), f);
				fclose (f);
				printf ("  does not match expected output\n");
				res = false;
			}
			if (doCheckGLSL && !CheckGLSL (vertex, text.c_str()))
			{
				res = false;
			}
		}
		else
		{
			printf ("  translate error: %s\n", infoLog);
			res = false;
		}
	}
	else
	{
		printf ("  parse error: %s\n", infoLog);
		res = false;
	}

	Hlsl2Glsl_DestructCompiler (parser);

	return res;
}
int C_DECL main(int argc, char* argv[])
{
   bool parseFailed = false;
   bool translateFailed = false;
   int debugOptions = 0;
	 std::map<EShLanguage, std::string> Entrys;
	 std::map<EShLanguage, ShHandle> parsers;
   std::map<EShLanguage, std::string> parsersIns;
	 std::map<EShLanguage, std::string> Outs;
   char *uOut = 0;
   char *shaderHeader = 0;

   //ShHandle    translator = 0;
   //ShHandle    uniformMap = 0;
   bool        bUseUserVaryings = false;
   int             attribSemanticCount = 0;
   EAttribSemantic attribSemanticEnums[EAttrSemCount];
   char*           attribSemanticNames[EAttrSemCount];

	for ( int i = 0; i < EAttrSemCount; i++ )
	{
		attribSemanticEnums[i] = EAttrSemUnknown;
		attribSemanticNames[i] = NULL;
	};

	Hlsl2Glsl_Initialize();
	argc--;
	argv++;    
   
	for (; argc >= 1; argc--, argv++)
	{
		if (argv[0][0] == '-' || argv[0][0] == '/')
		{
			switch (argv[0][1])
			{
				case 'f': Entrys.insert(std::pair<EShLanguage, std::string>(EShLangFragment, (++argv)[0])); argc--;             break;
				case 'v': Entrys.insert(std::pair<EShLanguage, std::string>(EShLangVertex, (++argv)[0])); argc--;             break;
				case 'o':
					if (strlen(argv[0]) > 2)
					{
                switch (argv[0][2])
                {
                case 'f':
										Outs.insert(std::pair<EShLanguage, std::string>(EShLangFragment, (++argv)[0]));
                    argc--;
                    break;
                case 'v':
										Outs.insert(std::pair<EShLanguage, std::string>(EShLangVertex, (++argv)[0]));
                    argc--;
                    break;
                case 'u':
                    uOut = (++argv)[0]; argc--;
                    break;
                default: 
                    usage();
                    return EFailUsage;
                    break;
                }
					}
					break;

				case 'i':
					if (strlen(argv[0]) > 2)
					{
						EShLanguage language = EShLangFragment;

						switch (argv[0][2])
						{
						case 'f':
								language = EShLangFragment;
								break;
						case 'v':
								language = EShLangVertex;
								break;
						default: 
								usage();
								return EFailUsage;
								break;
						};

						ShHandle l_parser = Hlsl2Glsl_ConstructCompiler(language);

						if (l_parser == 0)
								return EFailParserCreate;

						argv++;
						argc--;

						parsers.insert(std::pair<EShLanguage, ShHandle>(language, l_parser));
						parsersIns.insert(std::pair<EShLanguage, std::string>(language, argv[0]));
					}
					break;

				case 'u':
          bUseUserVaryings = true;
          break;

				case 'a':
					{
						char *configFileName = (++argv)[0];
						argc--;

						// Load a configuration file specifying user attributes
						if ( !LoadUserAttribConfigFile ( configFileName, attribSemanticEnums, attribSemanticNames, &attribSemanticCount ) )
						{
								printf ( "Error loading attribute configuration file '%s'.\n", configFileName );
								return EFailUsage;
						}                  
					}
					break;

				case 'h':
              {
                char *shaderHeaderName = (++argv)[0];
                argc--;

                shaderHeader = ReadFileData ( shaderHeaderName );
              }
              break;

				default:  
					usage();                       
					return EFailUsage;
			}
		}
		else
		{
					EShLanguage language = FindLanguage(argv[0]);
					ShHandle l_parser = Hlsl2Glsl_ConstructCompiler(language);

          if (l_parser == 0)
              return EFailParserCreate;

					parsers.insert(std::pair<EShLanguage, ShHandle>(language, l_parser));
					parsersIns.insert(std::pair<EShLanguage, std::string>(language, argv[0]));
		}
	}

	if (parsers.size() == 0)
	{
		usage();
		return EFailUsage;
	}

/*
    translator = Hlsl2Glsl_ConstructTranslator(debugOptions);
    if (translator == 0)
        return EFailTranslatorCreate;
*/
	if ( bUseUserVaryings )
	{
		// Set the translator up to use user varyings
		for(std::map<EShLanguage, ShHandle>::iterator it = parsers.begin(); it != parsers.end(); ++it)
		{
			Hlsl2Glsl_UseUserVaryings (it->second, bUseUserVaryings );
		};
	};

/*
	if ( shaderHeader != NULL )
	{
		// Set a shader header if requested
		Hlsl2Glsl_SetShaderHeader ( translator, true, shaderHeader );
	}
*/

	if ( attribSemanticCount > 0 )
	{
			for(std::map<EShLanguage, ShHandle>::iterator it = parsers.begin(); it != parsers.end(); ++it)
			{
				// Use user attributes if the user specified user attribute configuration file
				if ( !Hlsl2Glsl_SetUserAttributeNames (it->second, attribSemanticEnums, (const char**)&attribSemanticNames[0], attribSemanticCount ) )
				{
						printf ("ERROR: Setting user attribute names\n");                        
				};
			};
	};


	if (parsers.size() > 0)
	{
		int l_i = -1;

		for(std::map<EShLanguage, ShHandle>::iterator it = parsers.begin(); it != parsers.end(); ++it)
		{
			EShLanguage l_language = it->first;
			ShHandle l_parser = it->second;

			std::string l_parsedfile = parsersIns[l_language];
			l_i += 1;

			if(ParseFile(l_parsedfile.c_str(), l_parser, debugOptions))
			{
				if(Entrys.find(l_language) != Entrys.end())
				{					
					std::string l_entrypointname = Entrys[l_language];

					//TODO
					if (Hlsl2Glsl_Translate(l_parser, l_entrypointname.c_str() , ETargetGLSL_120, 0))
					{
						if(Outs.find(l_language) != Outs.end())
						{
							SaveShader(Outs[l_language].c_str(), l_parser, shaderHeader);
						};

						if (uOut)
							SaveUniforms(uOut, l_parser);
					}
					else
					{
						translateFailed = true;
					};
				}
			}
			else
			{
				parseFailed = true;
			};

			InfoLogMsg("BEGIN", "COMPILER", l_i);
			puts(Hlsl2Glsl_GetInfoLog(l_parser));
			InfoLogMsg("END", "COMPILER", l_i);
		};
	};
/*
    InfoLogMsg("BEGIN", "LINKER", -1);
    puts(Hlsl2Glsl_GetInfoLog(translator));
    InfoLogMsg("END", "LINKER", -1);
    if (!translateFailed )
    {
        if (fOut)
          SaveShader( fOut, translator, EShLangFragment);
        if (vOut)
          SaveShader( vOut, translator, EShLangVertex);
        if (uOut)
          SaveUniforms( uOut, translator);
    }
*/

	for(std::map<EShLanguage, ShHandle>::iterator it = parsers.begin(); it != parsers.end(); ++it)
	{
		Hlsl2Glsl_DestructCompiler(it->second);
	};

//      Hlsl2Glsl_Destruct(translator);
//      Hlsl2Glsl_Destruct(uniformMap);

	for ( int i = 0; i < EAttrSemCount; i++ )
	{
		if ( attribSemanticNames[i] != NULL )
		{
			delete[] attribSemanticNames[i];
			attribSemanticNames[i] = NULL;
		};
	};

	if ( shaderHeader )
	{
		FreeFileData ( shaderHeader );
	};

	if (parseFailed)
		return EFailParse;

	if (translateFailed)
		return EFailTranslate;

	return 0;
}