context: /*
  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 UnityEngine;
  using UnityEditor;
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Threading;
  using System.Text;
  using System.Text.RegularExpressions;
  
  /// <summary> 
  /// <para>A small data structure class hold values for making Doxygen config files </para>
  /// </summary>
  public class DoxygenConfig
  {
  	public string Project = PlayerSettings.productName;
  	public string Synopsis = "";
  	public string Version = "";
  	public string ScriptsDirectory = Application.dataPath;
  	public string DocDirectory = Application.dataPath.Replace("Assets", "Docs");
  	public string PathtoDoxygen = "";
  
  }
  
  /// <summary>
  /// <para> A Editor Plugin for automatic doc generation through Doxygen</para>
  /// <para> Author: Jacob Pennock (http://Jacobpennock.com)</para>
  /// <para> Version: 1.0</para>	 
  /// </summary>
  public class DoxygenWindow : EditorWindow 
  {
  	public static DoxygenWindow Instance;
  	public enum WindowModes{Generate,Configuration,About}
  	public string UnityProjectID = PlayerSettings.productName+":";
  	public string AssestsFolder = Application.dataPath;
  	public string[] Themes = new string[3] {"Default", "Dark and Colorful", "Light and Clean"};
  	public int SelectedTheme = 1;
  	WindowModes DisplayMode = WindowModes.Generate;
  	static DoxygenConfig Config;
  	static bool DoxyFileExists = false;
  	StringReader reader;
  	TextAsset basefile;
  	float DoxyfileCreateProgress = -1.0f;
  	float DoxyoutputProgress = -1.0f;
  	string CreateProgressString = "Creating Doxyfile..";
  	public string BaseFileString = null;
  	public string DoxygenOutputString = null;
  	public string CurentOutput = null;
  	DoxyThreadSafeOutput DoxygenOutput = null; 
  	List<string> DoxygenLog = null;
  	bool ViewLog = false;
  	Vector2 scroll;
  	bool DocsGenerated = false;
  
  	[MenuItem( "Window/Documentation with Doxygen" )]
  	public static void Init()
  	{
  		Instance = (DoxygenWindow)EditorWindow.GetWindow( typeof( DoxygenWindow ), false, "Documentation" );
  		Instance.minSize = new Vector2( 420, 245 );
  		Instance.maxSize = new Vector2( 420, 720 );
  
  	}
  
  	void OnEnable()
  	{
  		LoadConfig();
  		DoxyoutputProgress = 0;
  	}
  
  	void OnDisable()
  	{
  		DoxyoutputProgress = 0;
  		DoxygenLog = null;
  	}
  
  	void OnGUI()
  	{
  		DisplayHeadingToolbar();
  		switch(DisplayMode)
  		{
  			case WindowModes.Generate:
  				GenerateGUI();
  			break;
  
  			case WindowModes.Configuration:
  				ConfigGUI();
  			break;
  
  			case WindowModes.About:
  				AboutGUI();
  			break;
  		}
  	}
  
  	void DisplayHeadingToolbar()
  	{
  		GUIStyle normalButton = new GUIStyle( EditorStyles.toolbarButton );
  		normalButton.fixedWidth = 140;
  		GUILayout.Space (5);
  		EditorGUILayout.BeginHorizontal( EditorStyles.toolbar );
  		{
  			if( GUILayout.Toggle( DisplayMode == WindowModes.Generate, "Generate Documentation", normalButton ) )
  			{
  				DoxyfileCreateProgress = -1;
  				DisplayMode = WindowModes.Generate;
  			}
  			if( GUILayout.Toggle( DisplayMode == WindowModes.Configuration, "Settings/Configuration", normalButton ) )
  			{
  				DisplayMode = WindowModes.Configuration;
  			}
  			if( GUILayout.Toggle( DisplayMode == WindowModes.About, "About", normalButton ) )
  			{
  				DoxyfileCreateProgress = -1;
  				DisplayMode = WindowModes.About;
  			}
  		}
  		EditorGUILayout.EndHorizontal();
  	}	
  
  	void ConfigGUI()
  	{
  		GUILayout.Space (10);
  		if(Config.Project == "Enter your Project name (Required)" || Config.Project == "" || Config.PathtoDoxygen == "" )
  			GUI.enabled = false;
  		if(GUILayout.Button ("Save Configuration and Build new DoxyFile", GUILayout.Height(40)))
  		{
  			MakeNewDoxyFile(Config);
  		}
  		if(DoxyfileCreateProgress >= 0)
  		{
  			Rect r = EditorGUILayout.BeginVertical();
  			EditorGUI.ProgressBar(r, DoxyfileCreateProgress, CreateProgressString);
  			GUILayout.Space(16);
  			EditorGUILayout.EndVertical();
  		}
  		GUI.enabled = true;
  
  		GUILayout.Space (20);
  		GUILayout.Label("Set Path to Doxygen Install",EditorStyles.boldLabel);
  		GUILayout.Space (5);
  		EditorGUILayout.BeginHorizontal();
  		Config.PathtoDoxygen = EditorGUILayout.TextField("Doxygen.exe : ",Config.PathtoDoxygen);
  		if(GUILayout.Button ("...",EditorStyles.miniButtonRight, GUILayout.Width(22)))
  			 Config.PathtoDoxygen = EditorUtility.OpenFilePanel  ("Where is doxygen.exe installed?","", "");
  		EditorGUILayout.EndHorizontal();
  
  
  		GUILayout.Space (20);
  		GUILayout.Label("Provide some details about the project",EditorStyles.boldLabel);
  		GUILayout.Space (5);
  		Config.Project = EditorGUILayout.TextField("Project Name: ",Config.Project);
  		Config.Synopsis = EditorGUILayout.TextField("Project Brief: ",Config.Synopsis);
  		Config.Version = EditorGUILayout.TextField("Project Version: ",Config.Version);
  		
  		GUILayout.Space (15);
  		GUILayout.Label("Select Theme",EditorStyles.boldLabel);
  		GUILayout.Space (5);
  		SelectedTheme = EditorGUILayout.Popup(SelectedTheme,Themes) ;		
  
  		GUILayout.Space (20);
  		GUILayout.Label("Setup the Directories",EditorStyles.boldLabel);
  		GUILayout.Space (5);
  		EditorGUILayout.BeginHorizontal();
  		Config.ScriptsDirectory = EditorGUILayout.TextField("Scripts folder: ",Config.ScriptsDirectory);
  		if(GUILayout.Button ("...",EditorStyles.miniButtonRight, GUILayout.Width(22)))
  			 Config.ScriptsDirectory = EditorUtility.OpenFolderPanel("Select your scripts folder", Config.ScriptsDirectory, "");
  		EditorGUILayout.EndHorizontal();
  		GUILayout.Space (5);
  		EditorGUILayout.BeginHorizontal();
  		Config.DocDirectory = EditorGUILayout.TextField("Output folder: ",Config.DocDirectory);
  		if(GUILayout.Button ("...",EditorStyles.miniButtonRight, GUILayout.Width(22)))
  			 Config.DocDirectory = EditorUtility.OpenFolderPanel("Select your ouput Docs folder", Config.DocDirectory, "");
  		EditorGUILayout.EndHorizontal();
  		GUILayout.Space (5);
  		EditorGUILayout.BeginHorizontal();
  		GUILayout.Space (5);
  		GUILayout.Space (30);
  		GUILayout.Label("By default Doxygen will search through your whole Assets folder for C# script files to document. Then it will output the documentation it generates into a folder called \"Docs\" that is placed in your project folder next to the Assets folder. If you would like to set a specific script or output folder you can do so above. ",EditorStyles.wordWrappedMiniLabel);
  		GUILayout.Space (30);
  		EditorGUILayout.EndHorizontal();
  	}
  
  	void AboutGUI()
  	{
  		GUIStyle CenterLable = new GUIStyle(EditorStyles.largeLabel);
  		GUIStyle littletext = new GUIStyle(EditorStyles.miniLabel) ;
  		CenterLable.alignment = TextAnchor.MiddleCenter;
  		GUILayout.Space (20);
  		GUILayout.Label( "Automatic C# Documentation Generation through Doxygen",CenterLable);
  		GUILayout.Label( "Version: 1.0",CenterLable);
  		GUILayout.Label( "By: Jacob Pennock",CenterLable);
  
  		GUILayout.Space (20);
  		EditorGUILayout.BeginHorizontal();
  		GUILayout.Space (20);
  		GUILayout.Label( "Follow me for more Unity tips and tricks",littletext);
  		GUILayout.Space (15);
  		if(GUILayout.Button( "twitter"))
  			Application.OpenURL("http://twitter.com/@JacobPennock");
  		GUILayout.Space (20);
  		EditorGUILayout.EndHorizontal();
  
  		GUILayout.Space (10);
  		EditorGUILayout.BeginHorizontal();
  		GUILayout.Space (20);
  		GUILayout.Label( "Visit my site for more plugins and tutorials",littletext);
  		if(GUILayout.Button( "JacobPennock.com"))
  			Application.OpenURL("http://www.jacobpennock.com/Blog/?cat=19");
  		GUILayout.Space (20);
  		EditorGUILayout.EndHorizontal();
  	}
  
  	void GenerateGUI()
  	{
  		if(DoxyFileExists)
  		{
  			//UnityEngine.Debug.Log(DoxyoutputProgress);
  			GUILayout.Space (10);
  			if(!DocsGenerated)
  				GUI.enabled = false;
  			if(GUILayout.Button ("Browse Documentation", GUILayout.Height(40)))
  				Application.OpenURL("File://"+Config.DocDirectory+"/html/annotated.html");
  			GUI.enabled = true;	
  
  			if(DoxygenOutput == null)
  			{
  				if(GUILayout.Button ("Run Doxygen", GUILayout.Height(40)))
  				{
  					DocsGenerated = false;
  					RunDoxygen();
  				}
  					
  				if(DocsGenerated && DoxygenLog != null)
  				{
  					if(GUILayout.Button( "View Doxygen Log",EditorStyles.toolbarDropDown))
  						ViewLog = !ViewLog;
  					if(ViewLog)
  					{
  						scroll = EditorGUILayout.BeginScrollView(scroll, GUILayout.ExpandHeight(true));
  						foreach(string logitem in DoxygenLog)
  						{
  							EditorGUILayout.SelectableLabel(logitem,EditorStyles.miniLabel,GUILayout.ExpandWidth(true));
  						}
  		            	EditorGUILayout.EndScrollView();
  					}
  				}
  			}
  			else
  			{
  				if(DoxygenOutput.isStarted() && !DoxygenOutput.isFinished())
  				{
  					string currentline = DoxygenOutput.ReadLine();
  					DoxyoutputProgress = DoxyoutputProgress + 0.1f;
  					if(DoxyoutputProgress >= 0.9f)
  						DoxyoutputProgress = 0.75f;
  					Rect r = EditorGUILayout.BeginVertical();
  					EditorGUI.ProgressBar(r, DoxyoutputProgress,currentline );
  					GUILayout.Space(40);
  					EditorGUILayout.EndVertical();
  				}
  	        	if(DoxygenOutput.isFinished())
  	        	{
  	        		if (Event.current.type == EventType.Repaint)
  					{
  						/*
  						If you look at what SetTheme is doing, I know, it seems a little scary to be 
  						calling file moving operations from inside a an OnGUI call like this. And 
  						maybe it would be a better choice to call SetTheme and update these other vars
  						from inside of the OnDoxygenFinished callback. But since the callback is static
  						that would require a little bit of messy singleton instance checking to make sure
  						the call back was calling into the right functions. I did try to do it that way
  						but for some reason the file operations failed every time. I'm not sure why.
  						This is what I was getting from the debugger:
  						
  						Error in file: C:/BuildAgent/work/842f9551727e852/Runtime/Mono/MonoManager.cpp at line 2212
  						UnityEditor.FileUtil:DeleteFileOrDirectory(String)
  						UnityEditor.FileUtil:ReplaceFile(String, String) (at C:\BuildAgent\work\842f9557127e852\Editor\MonoGenerated\Editor\FileUtil.cs:42)
  
  						Doing them here seems to work every time and the Repaint event check ensures that they will only be done once.
  						*/
  						SetTheme(SelectedTheme);
  		        		DoxygenLog = DoxygenOutput.ReadFullLog();
  		        		DoxyoutputProgress = -1.0f;
  		        		DoxygenOutput = null;
  	        			DocsGenerated = true;
  	        			EditorPrefs.SetBool(UnityProjectID+"DocsGenerated",DocsGenerated);
  					}
  	        	}
  			}
  		}
  		else
  		{
  			GUIStyle ErrorLabel = new GUIStyle(EditorStyles.largeLabel);
  			ErrorLabel.alignment = TextAnchor.MiddleCenter;
  			GUILayout.Space(20);
  			GUI.contentColor = Color.red;
  			GUILayout.Label("You must set the path to your Doxygen install and \nbuild a new Doxyfile before you can generate documentation",ErrorLabel);
  		}
  	}
  
  	public void readBaseConfig()
  	{
  		basefile = (TextAsset)Resources.Load("BaseDoxyfile", typeof(TextAsset));
  		reader = new StringReader(basefile.text);
  		if ( reader == null )
  		   UnityEngine.Debug.LogError("BaseDoxyfile not found or not readable");
  		else
  		   BaseFileString = reader.ReadToEnd();
  	}
  
  	public void MakeNewDoxyFile(DoxygenConfig config)
  	{
  		SaveConfigtoEditor(config);
  		CreateProgressString = "Creating Output Folder";
  		DoxyfileCreateProgress = 0.1f;
  		System.IO.Directory.CreateDirectory(config.DocDirectory);
  
  		DoxyfileCreateProgress = 0.1f;
  		string newfile = BaseFileString.Replace("PROJECT_NAME           =", "PROJECT_NAME           = "+"\""+config.Project+"\"");
  		DoxyfileCreateProgress = 0.2f;
  		newfile = newfile.Replace("PROJECT_NUMBER         =", "PROJECT_NUMBER         = "+config.Version);
  		DoxyfileCreateProgress = 0.3f;
  		newfile = newfile.Replace("PROJECT_BRIEF          =", "PROJECT_BRIEF          = "+"\""+config.Synopsis+"\"");
  		DoxyfileCreateProgress = 0.4f;
  		newfile = newfile.Replace("OUTPUT_DIRECTORY       =", "OUTPUT_DIRECTORY       = "+"\""+config.DocDirectory+"\"");
  		DoxyfileCreateProgress = 0.5f;
  		newfile = newfile.Replace("INPUT                  =", "INPUT                  = "+"\""+config.ScriptsDirectory+"\"");
  		DoxyfileCreateProgress = 0.6f;
  
  		switch(SelectedTheme)
  		{
  			case 0:
  				newfile = newfile.Replace("GENERATE_TREEVIEW      = NO", "GENERATE_TREEVIEW      = YES");
  			break;
  			case 1:
  				newfile = newfile.Replace("SEARCHENGINE           = YES", "SEARCHENGINE           = NO");
  				newfile = newfile.Replace("CLASS_DIAGRAMS         = YES", "CLASS_DIAGRAMS         = NO");
  			break;
  		}
  
  		CreateProgressString = "New Options Set";
  
  		StringBuilder sb = new StringBuilder();
  		sb.Append(newfile);
          StreamWriter NewDoxyfile = new StreamWriter(config.DocDirectory + @"\Doxyfile");
          
          NewDoxyfile.Write(sb.ToString());
          NewDoxyfile.Close();
          DoxyfileCreateProgress = 1.0f;
          CreateProgressString = "New Doxyfile Created!";
          DoxyFileExists = true;
          EditorPrefs.SetBool(UnityProjectID+"DoxyFileExists",DoxyFileExists);
  	}
  
  	void SaveConfigtoEditor(DoxygenConfig config)
  	{
  		EditorPrefs.SetString(UnityProjectID+"DoxyProjectName",config.Project);
  		EditorPrefs.SetString(UnityProjectID+"DoxyProjectNumber",config.Version);
  		EditorPrefs.SetString(UnityProjectID+"DoxyProjectBrief",config.Synopsis);
  		EditorPrefs.SetString(UnityProjectID+"DoxyProjectFolder",config.ScriptsDirectory);
  		EditorPrefs.SetString(UnityProjectID+"DoxyProjectOutput",config.DocDirectory);
  		EditorPrefs.SetString("DoxyEXE", config.PathtoDoxygen);
  		EditorPrefs.SetInt(UnityProjectID+"DoxyTheme", SelectedTheme);
  	}
  
  	void LoadConfig()
  	{
  		if(BaseFileString == null)
  			readBaseConfig();
  
gt: 		if(Config == null)