// This validates a single attribute in the file given the value passed into the task, and the file attribute to look up.
        // The filename is only used for making the error message pretty.
        private bool ValidateFileEntry(string taskAttributeValue, AssemblyInfoWrapper assemblyInfo, string fileAttribute, string fileName)
        {
            if ((taskAttributeValue != null) && (assemblyInfo[fileAttribute] == null))
            {
                this.Log.LogError("Unable to update the {0} for {1}: No stub entry for {0} was found in the AssemblyInfo file.", fileAttribute, fileName);
                return false;
            }

            return true;
        }
        private void UpdateProperty(AssemblyInfoWrapper assemblyInfo, string propertyName)
        {
            PropertyInfo propInfo = this.GetType().GetProperty(propertyName);
            string value = (string)propInfo.GetValue(this, null);

            if (value != null)
            {
                assemblyInfo[propertyName] = value;
                this.Log.LogMessage(MessageImportance.Low, "\tUpdating {0} to \"{1}\"", propertyName, value);
            }
        }
        // There's an inherent limitation to this task in that it can only replace content for attributes
        // already present in the assemblyinfo file. If the stub isn't there then it can't be set. This method
        // goes through and validates that a stub is present in the file for any of the properties that were set
        // on the task.
        private bool ValidateFileEntries(AssemblyInfoWrapper assemblyInfo, string fileName)
        {
            if (((this.AssemblyBuildNumber != null) ||
                 (this.AssemblyRevision != null) ||
                 (this.AssemblyMajorVersion != null) ||
                 (this.AssemblyMinorVersion != null)) &&
                (assemblyInfo["AssemblyVersion"] == null))
            {
                this.Log.LogError("Unable to update the AssemblyVersion for {0}: No stub entry for AssemblyVersion was found in the AssemblyInfo file.", fileName);
                return false;
            }

            if (((this.AssemblyFileBuildNumber != null) ||
                 (this.AssemblyFileRevision != null) ||
                 (this.AssemblyFileMajorVersion != null) ||
                 (this.AssemblyFileMinorVersion != null)) &&
                (assemblyInfo["AssemblyFileVersion"] == null))
            {
                this.Log.LogError("Unable to update the AssemblyFileVersion for {0}: No stub entry for AssemblyFileVersion was found in the AssemblyInfo file.", fileName);
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyCompany, assemblyInfo, "AssemblyCompany", fileName))
            {
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyConfiguration, assemblyInfo, "AssemblyConfiguration", fileName))
            {
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyCopyright, assemblyInfo, "AssemblyCopyright", fileName))
            {
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyCulture, assemblyInfo, "AssemblyCulture", fileName))
            {
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyDescription, assemblyInfo, "AssemblyDescription", fileName))
            {
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyProduct, assemblyInfo, "AssemblyProduct", fileName))
            {
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyTitle, assemblyInfo, "AssemblyTitle", fileName))
            {
                return false;
            }

            if (!this.ValidateFileEntry(this.AssemblyTrademark, assemblyInfo, "AssemblyTrademark", fileName))
            {
                return false;
            }

            if (this.AssemblyIncludeSigningInformation)
            {
                if (!this.ValidateFileEntry(this.AssemblyDelaySign, assemblyInfo, "AssemblyDelaySign", fileName))
                {
                    return false;
                }

                if (!this.ValidateFileEntry(this.AssemblyKeyFile, assemblyInfo, "AssemblyKeyFile", fileName))
                {
                    return false;
                }

                if (!this.ValidateFileEntry(this.AssemblyKeyName, assemblyInfo, "AssemblyKeyName", fileName))
                {
                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// Executes the AssemblyInfo task.
        /// </summary>
        /// <returns>True if the task was run sucecssfully. False if the task failed.</returns>
        public override bool Execute()
        {
            FileInfo writerInfo = null;
            
            // Try and parse all the increment properties to ensure they are valid for the increment enum. If not,
            // bail out.
            if (!this.ParseIncrementProperties())
            {
                return false;
            }

            // Validate that the enum values set match with what was passed into the associated parameters. If not,
            // bail out.
            if (!this.ValidateIncrementProperties())
            {
                return false;
            }

            // Set the max versions before running through the loop
            this.MaxAssemblyVersion = "0.0.0.0";
            this.MaxAssemblyFileVersion = "0.0.0.0";

            foreach (ITaskItem item in this.AssemblyInfoFiles)
            {
                if (!File.Exists(item.ItemSpec))
                {
                    Log.LogError(string.Format(CultureInfo.CurrentUICulture, "File not found: {0}", item.ItemSpec));
                    return false;
                }

                AssemblyInfoWrapper assemblyInfo = new AssemblyInfoWrapper(item.ItemSpec);

                // Validate that stub file entries exist for any of the properties we've been asked to set.
                if (!this.ValidateFileEntries(assemblyInfo, item.ItemSpec))
                {
                    return false;
                }

                this.Log.LogMessage(MessageImportance.Low, "Updating assembly info for {0}", item.ItemSpec);
                if (!this.SkipVersioning)
                {
                    Version versionToUpdate;

                    try
                    {
                        versionToUpdate = new Version(assemblyInfo["AssemblyVersion"], true);
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(string.Format(CultureInfo.CurrentUICulture, "Unable to read current AssemblyVersion from file {0}: {1}", item.ItemSpec, ex.Message));
                        return false;
                    }

                    this.UpdateAssemblyVersion(versionToUpdate, this.assemblyVersionSettings);
                    assemblyInfo["AssemblyVersion"] = versionToUpdate.ToString();
                    if (this.UpdateAssemblyInformationalVersion)
                    {
                        if (this.ValidateFileEntry("AssemblyInformationalVersion", assemblyInfo, "AssemblyInformationalVersion", item.ItemSpec))
                        {
                            if (string.IsNullOrEmpty(this.AssemblyInformationalVersion))
                            {
                                assemblyInfo["AssemblyInformationalVersion"] = versionToUpdate.ToString();
                            }
                            else
                            {
                                assemblyInfo["AssemblyInformationalVersion"] = this.AssemblyInformationalVersion;
                            }
                        }
                    }
                    
                    UpdateMaxVersion(ref this.maxAssemblyVersion, assemblyInfo["AssemblyVersion"]);
                    try
                    {
                    versionToUpdate = new Version(assemblyInfo["AssemblyFileVersion"]);
                    this.UpdateAssemblyVersion(versionToUpdate, this.assemblyFileVersionSettings);
                    assemblyInfo["AssemblyFileVersion"] = versionToUpdate.ToString();
                    UpdateMaxVersion(ref this.maxAssemblyFileVersion, assemblyInfo["AssemblyFileVersion"]);
                    }
                    catch (ArgumentException)
                    {
                        Log.LogWarning(string.Format(CultureInfo.CurrentUICulture, "File {0} contains a verbatim AssemblyFileVersion - skipping", item.ItemSpec));
                    }
                }

                this.UpdateProperty(assemblyInfo, "AssemblyTitle");
                this.UpdateProperty(assemblyInfo, "AssemblyDescription");
                this.UpdateProperty(assemblyInfo, "AssemblyConfiguration");
                this.UpdateProperty(assemblyInfo, "AssemblyCompany");
                this.UpdateProperty(assemblyInfo, "AssemblyProduct");
                this.UpdateProperty(assemblyInfo, "AssemblyCopyright");
                this.UpdateProperty(assemblyInfo, "AssemblyTrademark");
                this.UpdateProperty(assemblyInfo, "AssemblyCulture");
                this.UpdateProperty(assemblyInfo, "Guid");
                if (this.AssemblyIncludeSigningInformation)
                {
                    this.UpdateProperty(assemblyInfo, "AssemblyKeyName");
                    this.UpdateProperty(assemblyInfo, "AssemblyKeyFile");
                    this.UpdateProperty(assemblyInfo, "AssemblyDelaySign");
                }

                this.UpdateProperty(assemblyInfo, "ComVisible");

                try
                {
                    writerInfo = this.GetTemporaryFileInfo();

                    if (!string.IsNullOrEmpty(this.TextEncoding))
                    {
                        try
                        {
                            this.fileEncoding = GetTextEncoding(this.TextEncoding);
                        }
                        catch (ArgumentException)
                        {
                            Log.LogError(string.Format(CultureInfo.CurrentCulture, "Error, {0} is not a supported encoding name.", this.TextEncoding));
                            return false;
                        }
                    }

                    using (StreamWriter writer = new StreamWriter(writerInfo.OpenWrite(), this.fileEncoding))
                    {
                        assemblyInfo.Write(writer);
                    }

                    bool changedAttribute = false;

                    // First make sure the file is writable.
                    FileAttributes fileAttributes = File.GetAttributes(item.ItemSpec);

                    // If readonly attribute is set, reset it.
                    if ((fileAttributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                    {
                        Log.LogMessage(MessageImportance.Low, "Making file writable");
                        File.SetAttributes(item.ItemSpec, fileAttributes ^ FileAttributes.ReadOnly);
                        changedAttribute = true;
                    }

                    File.Copy(writerInfo.FullName, item.ItemSpec, true);

                    if (changedAttribute)
                    {
                        Log.LogMessage(MessageImportance.Low, "Making file readonly");
                        File.SetAttributes(item.ItemSpec, FileAttributes.ReadOnly);
                    }
                }
                finally
                {
                    if (writerInfo != null)
                    {
                        writerInfo.Delete();
                    }
                }
            }

            return true;
        }