// footnotesorter.cs created with MonoDevelop
// User: Lukas Elsner at 3:23 PM 9/3/2008
//
//

using System;
using System.IO;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace footnotesort
{

	
    public class Footnotesorter
    {
		private struct Footnote
		{
			private int _nIndex;
			private string _strValue;
			
			public Footnote(int iIndex, string iValue)
			{
				_nIndex = iIndex;
				_strValue = iValue;
			}
			
			public int Index {
				get{return _nIndex;}
				set{_nIndex = value;}
			}
			public string Value {
				get{return _strValue;}
				set{_strValue = value;}
			}
		}		
		
        string _strFilename = String.Empty;
		/* Every Footnote gets a Hash for faster searching if it already exists */
        Dictionary<int, Footnote> _dictHashToFootnote = new Dictionary<int, Footnote>();
		/* Footnote values will be cached for printing the right order on the bottom */ 
		Dictionary<int, string> _dictIndexToValue = new Dictionary<int, string>();
		/* Regular Expression for finding footnotes */
        Regex _Regex = new Regex(@"\[(\d+)\]", RegexOptions.Compiled);

		/* Constructor */
        public Footnotesorter(string iFilename)
        {
            _strFilename = iFilename;
            if (!File.Exists(_strFilename)) throw new FileNotFoundException("File not found", _strFilename);
        }
		
  		public void ParseFile()
		{
			/* Create filestream and streamreader for reading the file line by line */
            FileStream fs = new FileStream(_strFilename, FileMode.Open);
			StreamReader sr = new StreamReader(fs);
			/* Read the Streamreader and print the text with ordered footnotes */
            PrintFootnoteText(sr);
			Console.WriteLine("@footnote:");
			/* Sort the footnotes... */
			SortFootnoteNotes(sr);
			/* ...and print them ordered */
			PrintFootnoteNotes();
			/* Close and Dispose Filestream (Optional) */
            fs.Close();
            fs.Dispose();
		}

        private void PrintFootnoteText(StreamReader iStreamreader)
        {
            while (!iStreamreader.EndOfStream)
            {
				/* Read the stream line by line */
				string s = iStreamreader.ReadLine();
                /* Exit the function if footnote section begins */
				if (s.Contains("@footnote:")) return;
                
				MatchEvaluator me = new MatchEvaluator(MatchReplace);
				/* Each match calls the MatchReplace function and replaces with its returnvalue */				
				s = _Regex.Replace(s, me);
                Console.WriteLine(s);
            }
        }
		
        /* Callback for the MatchEvaluator function */
		private string MatchReplace(Match m)
		{
			string strRetval = m.ToString();
            /* If it already exists, get the new number and replace the old one */
			if (_dictHashToFootnote.ContainsKey(m.Value.GetHashCode()))
				strRetval = strRetval.Replace(m.Value, "[" + _dictHashToFootnote[m.Value.GetHashCode()].Index + "]");
			else 
			{
                /* If not, get new number, add it to the Hashlist and replace the old one */
				Footnote f = new Footnote(_dictHashToFootnote.Count + 1, m.Value);
				_dictHashToFootnote.Add(m.Value.GetHashCode(), f);
				strRetval = strRetval.Replace(m.Value, "[" + f.Index + "]");
			}
			return strRetval;
		}
		
        private void SortFootnoteNotes(StreamReader iStreamreader)
        {
            while (!iStreamreader.EndOfStream)
				{
				/* Read the stream line by line */
                string s = iStreamreader.ReadLine();
				/* Check line against the Regex */				
				Match m = _Regex.Match(s);
				if (m.Success)
				{
					/* Remove the matching string from line */
					s = s.Remove(0, m.Value.Length);
					/* If footnote exists in Hashlist, get the new index and add it to the valuelist*/
					if(_dictHashToFootnote.ContainsKey(m.Value.GetHashCode()))
					{
					_dictIndexToValue.Add(_dictHashToFootnote[m.Value.GetHashCode()].Index, s);
					}
					/* If not, create new Footnote! (Instead of this it can be ignored, because it is not nessecary to print it!!) */
					else 
					{	
						Footnote f = new Footnote(_dictHashToFootnote.Count + 1, m.Value);
						_dictHashToFootnote.Add(m.Value.GetHashCode(), f);
						_dictIndexToValue.Add(_dictHashToFootnote.Count, s);
					}
                }
            }			 
        }
		
		/* Simply print all the Footnotes at the bottom in the right order*/	    
		private void PrintFootnoteNotes()
	    {
			for(int i = 1; i < _dictIndexToValue.Count + 1; i++)
			{	
				try
				{
					Console.WriteLine("[" + i + "] " + _dictIndexToValue[i]);
				}
				catch(KeyNotFoundException ex){Console.WriteLine(ex.Message + ": " + i);}
			}
		}
    }
}
