/// <summary>
        /// Creates the new type of the variable based on the given parameters.
        /// After getting all of the correct templates, they will be copied
        /// into the folder specified by targetPath.
        ///
        /// Some templates must be placed in an Editor folder. If one does not
        /// exist, one might be created. However, this function will avoid
        /// overwriting files. Once it is done, it will refresh the project.
        ///
        /// Note that not all of the listen exceptions may get thrown. There
        /// are others which may get thrown by the file IO methods.
        /// </summary>
        ///
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Thrown if any of the arguments are invalid. (See each argument
        /// for details.)
        /// </exception>
        ///
        /// <exception cref="System.IO.DirectoryNotFoundException">
        /// If the targetPath is invalid.
        /// </exception>
        ///
        /// <exception cref="System.IO.IOException">
        /// Thrown if the Editor folder cannot be created. Also thrown if any
        /// of the files we run into a pre-existing file.
        /// </exception>
        ///
        /// <param name="readableName">
        /// The human readable name. Must be a legal C# name, and must be legal
        /// when used as a filename. The first character should be uppercase.
        /// If any of the checks fail or if the name is already taken
        /// by another variable object, then an ArgumentOutOfRangeException is
        /// thrown.
        /// </param>
        /// <param name="typeName">
        /// The name of the pre-existing C# type to be represtented. If the
        /// string fails the checks, then an ArgumentOutOfRangeException is thrown.
        /// </param>
        /// <param name="referability">
        /// Whether the C# type refered to by typeName is referable or not.
        /// If ReferabilityMode.Unknown is passed, ArgumentOutOfRangeException is thrown.
        /// </param>
        /// <param name="targetPath">
        /// Path used when attempting to create the new files. If this isn't a
        /// valid path, a DirectoryNotFoundException is thrown. If the
        /// target folder is nested in an Editor folder (or is an Editor folder
        /// itself), a ArgumentOutOfRangeException is thrown instead.
        /// </param>
        public static void CreateNewVariableType(
            string readableName,
            string typeName,
            ReferabilityMode referability,
            string targetPath
            )
        {
            // We'll use this to track any new files we make at any point,
            // which makes it easy to clean up after ourselves if things
            // go awry.
            List <string> newFilePaths = new List <string>();

            string editorPath = UnityPathUtils.GetEditorFolder(targetPath);

            if (!IsValidName(readableName))
            {
                throw new System.ArgumentOutOfRangeException(
                          "readableName",
                          "Either contains invalid characters or could conflict with" +
                          " a C# keyword."
                          );
            }
            else if (ScriptFileManager.IsNameTaken(readableName))
            {
                throw new System.ArgumentOutOfRangeException(
                          "readableName",
                          "Is already taken by another VariableObject type."
                          );
            }
            else if (!IsValidName(typeName))
            {
                throw new System.ArgumentOutOfRangeException(
                          "typeName",
                          "Either contains invalid characters or could conflict with" +
                          " a C# keyword."
                          );
            }
            else if (referability == ReferabilityMode.Unknown)
            {
                throw new System.ArgumentOutOfRangeException(
                          "referability",
                          "Must be something other than ReferabilityMode.unknown."
                          );
            }
            else if (!AssetDatabase.IsValidFolder(targetPath))
            {
                throw new DirectoryNotFoundException(
                          "targetPath must be pointing to a pre-existing folder. If" +
                          " you want to create a new folder to put the scripts in," +
                          " you must do it before calling CreateNewVariableType."
                          );
            }
            else if (UnityPathUtils.IsInEditorAssembly(targetPath))
            {
                // If we tried putting all of our scripts in an Editor folder,
                // it would be mostly pointless because then we cannot use our
                // variable objects in the final build.
                throw new System.ArgumentOutOfRangeException(
                          "targetPath",
                          "Must not be nested in an Editor folder."
                          );
            }
            else if (File.Exists(editorPath) && !AssetDatabase.IsValidFolder(editorPath))
            {
                throw new IOException(
                          editorPath + " exists as a file, so we cannot make a folder there!"
                          );
            }


            // It's still possible that the editor folder doesn't exist.
            // However, we are sure that there isn't a file with that name,
            // so we can go ahead and create it if necessary.
            if (!AssetDatabase.IsValidFolder(editorPath))
            {
                editorPath = AssetDatabase.GUIDToAssetPath(
                    AssetDatabase.CreateFolder(targetPath, "Editor")
                    );

                newFilePaths.Add(editorPath);
            }

            // At this point, everything is valid. Barring some kind of error
            // when writting to the disk, everything should be good to go.
            //
            // The only thing we are not going to check is if the files already
            // exist. We could check this before-hand, but this makes it a bit
            // more complex overall. We don't even gain very much in doing this;
            // we still need to handle an exception thrown by the file-writing
            // code, which may require cleaning up files.
            //
            // We shall build a list of all of the files which we create. That
            // way, we can delete them if something goes wrong.
            //
            //
            // Until after the AssetDatabase.Refresh in the finally block,
            // we cannot rely on Unity's AssetDatabase class. This only works
            // on files which are part of the project. However, if start we
            // refreshing, it'll refresh asynchroniously. Deleting files
            // during a refresh is risky, and may lead to errors and even lock
            // up Unity's reloading mechanisms.
            //
            // Fortunately, C# has enough tools to get the job done.

            try {
                EditorApplication.LockReloadAssemblies();

                foreach (TemplateInfo template in TemplateFileManager.Templates)
                {
                    string newScriptPath = CreateScriptFromTemplate(
                        readableName, typeName, referability,
                        template, targetPath, editorPath
                        );

                    // Add it to the start so that, when iterating through
                    // later on, the new folder would be at the back.
                    if (!string.IsNullOrEmpty(newScriptPath))
                    {
                        newFilePaths.Insert(0, newScriptPath);
                    }
                }         // End foreach(TemplateInfo template in Files.Templates)
            }             // End try
            catch (System.Exception e) {
                foreach (string path in newFilePaths)
                {
                    if ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory)
                    {
                        Directory.Delete(path);
                    }
                    else
                    {
                        File.Delete(path);
                    }

                    if (File.Exists(path + ".meta"))
                    {
                        File.Delete(path + ".meta");
                    }
                }

                throw e;
            }
            finally {
                EditorApplication.UnlockReloadAssemblies();
                AssetDatabase.Refresh();
            }

            SetFileLabels(newFilePaths.ToArray());
        }         // End CreateNewVariableType
        private void OnWizardUpdate()
        {
            string errorMsg = "";
            string helpMsg  = "";

            bool validName = false;
            bool validType = false;

            // We need to check for null, because the string is occasionally
            // null upon wizard's creation
            if (string.IsNullOrEmpty(humanReadableName))
            {
                helpMsg += "Please enter the Human Readable Name.";
            }
            else if (!VariableTypeBuilder.IsValidName(humanReadableName))
            {
                errorMsg +=
                    "The Human Readable Name is not a valid C# variable" +
                    " name!\n";
            }
            else if (ScriptFileManager.IsNameTaken(humanReadableName))
            {
                errorMsg +=
                    "The Human Readable Name conflicts with another," +
                    " already existing variable type!\n";
            }
            else
            {
                validName = true;
            }

            helpMsg += '\n';                    // Force push the next line into a blank field.


            if (string.IsNullOrEmpty(dataType))
            {
                helpMsg += "Please enter the Data Type.";
            }
            else if (!VariableTypeBuilder.IsValidName(dataType))
            {
                errorMsg += "The Data Type is not a valid C# variable name!";
            }
            else
            {
                validType = true;
            }


            helpMsg += '\n';                    // Force push the next line into a blank field.


            if (referability == ReferabilityMode.Unknown)
            {
                helpMsg += "Please choose a referability mode.";
            }


            // We use Trim here because having extra newlines looks ugly.
            errorString = errorMsg.Trim();
            helpString  = helpMsg;

            isValid = (
                validName &&
                validType &&
                referability != ReferabilityMode.Unknown
                );
        }