//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//  
using System;
using System.IO;
using System.CodeDom;
using System.CodeDom.Compiler;

class GenerateCode
{
	public static void HelloWorldCode(CodeDomProvider provider, StreamWriter output)
	{
		// Generowanie kodu
		ICodeGenerator cg = provider.CreateGenerator(output);
		CodeGeneratorOptions op = new CodeGeneratorOptions();

		// Generowanie komentarzy na początku funkcji
		CodeCommentStatement comment = new CodeCommentStatement("Kod generujący Witaj świecie!");
		cg.GenerateCodeFromStatement(comment, output, op);
		comment = new CodeCommentStatement("Najpierw należy utworzyć przestrzeń nazw.");
		cg.GenerateCodeFromStatement(comment, output, op);

		// Przestrzeń nazw
		CodeNamespace codeNamespace = new CodeNamespace("HelloWorld");
		// Przestrzeń nazw
		CodeNamespaceImport import = new CodeNamespaceImport("System");
		codeNamespace.Imports.Add(import);
		// Klasa otrzymuje unikalną nazwę
		CodeTypeDeclaration mainClass = new CodeTypeDeclaration("HelloWorldMain");

		// Dodanie klasy do przestrzeni nazw
		codeNamespace.Types.Add(mainClass);

		// Utworzenie funkcji Main
		CodeEntryPointMethod main = new CodeEntryPointMethod();

		CodeParameterDeclarationExpression param = 
			new CodeParameterDeclarationExpression("System.String []", "args");

		comment = new CodeCommentStatement("Wyświetlenie powitania w konsoli");
		main.Statements.Add(comment);

		CodeVariableDeclarationStatement variable = new CodeVariableDeclarationStatement(typeof(string), "message", new CodePrimitiveExpression("Hello World!"));
		main.Statements.Add(variable);

		CodeVariableReferenceExpression[] arg = new CodeVariableReferenceExpression[1];
		arg[0] = new CodeVariableReferenceExpression(variable.Name);
		CodeMethodReferenceExpression type = new CodeMethodReferenceExpression();
		type.MethodName = "Console";
		CodeMethodInvokeExpression methodCall = new CodeMethodInvokeExpression(type,"WriteLine",arg);
		main.Statements.Add(methodCall);

		mainClass.Members.Add(main);

		cg.GenerateCodeFromNamespace(codeNamespace, output, op);

	}
	public static void CompileAndExecute(CodeDomProvider provider, string filename, string target)
	{
		// Użycie interfejsu CodeProvider
		CompilerParameters param = new CompilerParameters(null, target, true);
		param.GenerateExecutable = true;
		ICodeCompiler cc = provider.CreateCompiler();
		CompilerResults cr = cc.CompileAssemblyFromFile(param, filename);
		System.Collections.Specialized.StringCollection output = cr.Output;
		foreach(string s in output)
		{
			Console.WriteLine(s);
		}

		if(cr.Errors.Count != 0)
		{
			CompilerErrorCollection es = cr.Errors;
			foreach(System.CodeDom.Compiler.CompilerError e in es)
			{
				Console.WriteLine(e.ToString());
			}
		}
		else
		{
			// Ustawienie ApplicationBase na aktualny katalog
			AppDomainSetup info = new AppDomainSetup();
			info.ApplicationBase = "file:\\\\" + System.Environment.CurrentDirectory;
			// Utworzenie domeny aplikacji z pustym dowodem
			AppDomain dom = AppDomain.CreateDomain("HelloWorld", null, info);
			dom.ExecuteAssembly(target);
			// Oczyszczenie poprzez usunięcie domeny aplikacji z pamięci
			AppDomain.Unload(dom);  
		}
	}
}
