//
// CodeTranslationFileDescriptionTemplate.cs: Template that translates .NET 
// 		code using CodeDom.
//
// Authors:
//   Michael Hutchinson <m.j.hutchinson@gmail.com>
//
// Copyright (C) 2006 Michael Hutchinson
//
//
// This source code is licenced under The MIT License:
//
// 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.
//

using System;
using System.Collections;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Xml;
using System.IO;

using MonoDevelop.Core;
using MonoDevelop.Ide.Templates;
using MonoDevelop.Projects;
using MonoDevelop.Projects.CodeGeneration;

namespace MonoDevelop.Ide.Templates
{
	
	public class CodeTranslationFileDescriptionTemplate : SingleFileDescriptionTemplate
	{
		string content;
		ICodeParser parser;
		string tempSubstitutedContent;
		
		public override void Load (XmlElement filenode)
		{
			base.Load (filenode);
			content = filenode.InnerText;
			
			string sourceLang = filenode.GetAttribute ("SourceLanguage");
			if ((sourceLang == null) || (sourceLang.Length == 0))
				sourceLang = "C#";
			
			CodeDomProvider provider = null;
			IDotNetLanguageBinding sourceBinding = GetLanguageBinding (sourceLang) as IDotNetLanguageBinding;
			if (sourceBinding != null)
				provider = sourceBinding.GetCodeDomProvider ();
			if (provider == null)
				throw new InvalidOperationException ("Invalid Code Translation template: the source language '" + sourceLang + "' does not have support for CodeDom.");
			
			parser = provider.CreateParser ();
			if (parser == null)
				throw new InvalidOperationException ("Invalid Code Translation template: the CodeDomProvider of the source language '" + sourceLang + "' has not implemented the CreateParser () method.");
		}
		
		//Adapted from CodeDomFileDescriptionTemplate.cs
		//TODO: Remove need to have a namespace and type (i.e. translate fragments)
		public override string CreateContent (string language)
		{
			//get target language's ICodeGenerator
			if (language == null || language == "")
				throw new InvalidOperationException ("Language not defined in CodeDom based template.");
			
			CodeDomProvider provider = null;
			IDotNetLanguageBinding binding = GetLanguageBinding (language) as IDotNetLanguageBinding;
			if (binding != null)
				provider = binding.GetCodeDomProvider ();
			if (provider == null)
				throw new InvalidOperationException ("The language '" + language + "' does not have support for CodeDom.");
			
			//parse the source code
			if (tempSubstitutedContent == null)
				throw new Exception ("Expected ModifyTags to be called before CreateContent");
			
			StringReader sr = new StringReader (tempSubstitutedContent);
			CodeCompileUnit ccu = parser.Parse (sr);
			sr.Close ();
			
			tempSubstitutedContent = null;
			
			//and generate the code
			CodeGeneratorOptions options = new CodeGeneratorOptions();
			options.IndentString = "\t";
			options.BracingStyle = "C";
			
			StringWriter sw = new StringWriter ();
			provider.GenerateCodeFromCompileUnit (ccu, sw, options);
			string txt = sw.ToString ();
			sw.Close ();
			
			//remove auto-generation notice
			int i = txt.IndexOf ("</autogenerated>");
			if (i == -1) return txt;
			i = txt.IndexOf ('\n', i);
			if (i == -1) return txt;
			i = txt.IndexOf ('\n', i + 1);
			if (i == -1) return txt;
			
			return txt.Substring (i+1);
		}
		
		public override void ModifyTags (Project project, string language, string identifier, string fileName, ref Hashtable tags)
		{
			//prevent parser breakage from missing tags, which SingleFile only provides for DotNetProject
			//if ((project as DotNetProject) == null)
			//	throw new InvalidOperationException ("CodeTranslationFileDescriptionTemplate can only be used with a DotNetProject");
			
			base.ModifyTags (project, language, identifier, fileName, ref tags);
			
			//This is a bit hacky doing it here instead of in CreateContent, but need to
			//substitute all tags in code before language is translated, because language
			//translation gets confused by unsubstituted  substitution tokens.
			StringParserService sps = (StringParserService) ServiceManager.GetService (typeof (StringParserService));
			string [,] tagsArr = HashtableToStringArray (tags);
			tempSubstitutedContent = sps.Parse (content, tagsArr);
		}
	}
}
