/*
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 *
 * Author: Martin Hentschel <info@cl-soft.de>
 *
 */

using System.Collections.Generic;
using CCodeGeneration;
using System;
using System.IO;

namespace LwipSnmpCodeGeneration
{
	public class MibCFile
	{
		#region Fields

		private const string PreservedSectionMarker = "LWIP MIB generator - preserved section begin";
		private const string PreservedSectionHeader = 
			"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" +
			PreservedSectionMarker + "\n" +
			"Code below is preserved on regeneration. Remove these comment lines to regenerate code.\n" +
			"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";

		private readonly List<CodeElement> includes = new List<CodeElement>();
		private readonly List<CodeElement> defines = new List<CodeElement>();
		private readonly List<CodeElement> declarations = new List<CodeElement>();
		private readonly List<CodeElement> implementation = new List<CodeElement>();
		private readonly List<CodeElement> preservedCode = new List<CodeElement>();

		#endregion

		public MibCFile()
		{
		}

		#region Accessors

		public List<CodeElement> Includes
		{
			get { return this.includes; }
		}

		public List<CodeElement> Defines
		{
			get { return this.defines; }
		}

		public List<CodeElement> Declarations
		{
			get { return this.declarations; }
		}

		public List<CodeElement> Implementation
		{
			get { return this.implementation; }
		}

		public List<CodeElement> PreservedCode
		{
			get { return this.preservedCode; }
		}

		#endregion

		#region Methods

		public void Save(CGenerator cGenerator)
		{
			CFile cFile = new CFile();

			cFile.AddElement(new Comment("Generated by LwipMibCompiler"));
			cFile.AddElement(EmptyLine.SingleLine);

			cFile.AddElement(new PP_Include(LwipDefs.Incl_SnmpOpts));
			CodeContainerBase e = cFile.AddElement(new PP_If(LwipDefs.Opt_SnmpEnabled)) as CodeContainerBase;
			e.AddElement(EmptyLine.SingleLine);

			// include header file
			string file = cGenerator.FileName;
			if (!String.IsNullOrWhiteSpace(file))
			{
				string ext = System.IO.Path.GetExtension(file);

				string headerFile = !String.IsNullOrEmpty(ext) ? file.Substring(0, file.Length - ext.Length) : file;
				headerFile += ".h";

				e.AddElement(new PP_Include(headerFile));								
			}

			// include common snmp files
			e.AddElement(new PP_Include("lwip/apps/snmp.h"));
			e.AddElement(new PP_Include("lwip/apps/snmp_core.h"));
			e.AddElement(new PP_Include("lwip/apps/snmp_scalar.h"));
			e.AddElement(new PP_Include("lwip/apps/snmp_table.h"));

			if (this.includes.Count > 0)
			{
				e.AddElement(EmptyLine.SingleLine);
				e.AddElements(this.includes);
			}

			if (this.defines.Count > 0)
			{
				e.AddElement(EmptyLine.SingleLine);
				e.AddElements(this.defines);
			}

			if (this.declarations.Count > 0)
			{
				e.AddElement(EmptyLine.TwoLines);
				e.AddElements(this.declarations);
			}

			if (this.implementation.Count > 0)
			{
				e.AddElement(EmptyLine.TwoLines);
				e.AddElements(this.implementation);
			}

			if (this.preservedCode.Count > 0)
			{
				e.AddElement(EmptyLine.TwoLines);
				e.AddElement(new Comment(PreservedSectionHeader));
				e.AddElement(EmptyLine.SingleLine);
				e.AddElements(this.preservedCode);
			}

			cFile.Save(cGenerator);
		}

		public static string GetPreservedCode(string file)
		{
			if (File.Exists(file))
			{
				using (StreamReader fileStream = new StreamReader(file))
				{
					while (!fileStream.EndOfStream)
					{
						string line = fileStream.ReadLine();
						if (line == PreservedSectionMarker)
						{
							break;
						}
					}

					if (!fileStream.EndOfStream)
					{
						// skip the rest of the comment + spacer line
						fileStream.ReadLine(); // "Code below is preserved...
						fileStream.ReadLine(); // "+++++++++++++++++++++++...
						fileStream.ReadLine(); // */
						fileStream.ReadLine(); //

						string preservedCode = fileStream.ReadToEnd();

						int lastEndif    = preservedCode.LastIndexOf("#endif", StringComparison.Ordinal);
						preservedCode    = preservedCode.Remove(lastEndif);

						return preservedCode;
					}
				}
			}

			return null;
		}

		#endregion
	}
}
