using System; using System.Linq; using System.Collections.Generic; using System.Xml.Linq; using UAF; using UAF.WPF.Models; namespace DataFileAnalyzer { /// /// All we need to know about a UAF data file: /// path, key, dependencies, tags, etc... /// public class DataFile : ListViewItemData { protected DataFileKey m_key = DataFileKey.Invalid; protected string m_filePath = null; protected string m_normalizedPath = null; protected DateTime m_lastModificationTime = DateTimeExtensions.Invalid; protected long m_length = 0; protected DateTime m_lastCheckTime = DateTimeExtensions.Invalid; protected DateTime m_lastDependenciesCheckTime = DateTimeExtensions.Invalid; protected List m_children = new List(); protected List m_parents = new List(); protected List m_errors = new List(); protected List m_warnings = new List(); #region properties /// /// The key of the file /// public DataFileKey Key { get { return m_key; } set { m_key = value; } } /// /// The path of the file, relative to the data folder, keeping its original case. /// public string FilePath { get { return m_filePath; } set { m_filePath = value; } } /// /// The normalized path of the file, relative to the data folder. /// public string NormalizedPath { get { return m_normalizedPath; } set { m_normalizedPath = value; } } /// /// Last time the file was written (UTC) /// public DateTime LastModificationTime { get { return m_lastModificationTime; } set { m_lastModificationTime = value; } } /// /// Size of the file /// public long Length { get { return m_length; } set { m_length = value; } } /// /// Last time we checked on the file (UTC) /// public DateTime LastCheckTime { get { return m_lastCheckTime; } set { m_lastCheckTime = value; } } /// /// Last time we computed the dependencies of the file (UTC) /// public DateTime LastDependenciesCheckTime { get { return m_lastDependenciesCheckTime; } set { m_lastDependenciesCheckTime = value; } } /// /// The files referenced by this one /// public List Children { get { return m_children; } } /// /// The files referencing by this one /// public List Parents { get { return m_parents; } } /// /// Are the dependencies up-to-date? /// public bool DependenciesUpToDate { get { return !m_lastDependenciesCheckTime.IsInvalid() && m_lastDependenciesCheckTime > m_lastModificationTime; } } /// /// Is the file present on drive? /// public bool IsMissing { get { return Errors.Any(error => error.Code == DataFileError.Codes.MissingFile); } } /// /// Does the file have missing dependencies? /// public bool HasMissingDependencies { get { return Errors.Any(error => error.Code == DataFileError.Codes.UnresolvedDependencies); } } /// /// Is the file absent from Perforce depot? /// public bool AbsentFromPerforce { get { return ((DataFileAnalyzerModel)UAF.Application.Workspace.This.ActiveDocument).IsPerforceEnabled && Warnings.Any(error => error.Code == DataFileError.Codes.NotInPerforce); } } /// /// Is the file absent from Perforce depot? /// public bool IsOrphan { get { return Warnings.Any(error => error.Code == DataFileError.Codes.Orphan); } } /// /// Does the file must compute its dependencies? /// public bool MustComputeDependencies { get { return Warnings.Any(warning => warning.Code == DataFileError.Codes.NeedDependencies); } } /// /// Did the Data File Analyzer fail to compute dependencies? /// public bool ComputeDependenciesError { get { return Errors.Any(error => error.Code == DataFileError.Codes.ErrorComputingDependencies); } } /// /// The list of errors that occurred during file update /// public List Errors { get { return m_errors; } } /// /// The list of warnings that occurred during file update /// public List Warnings { get { return m_warnings; } } /// /// Does the file has errors? /// public bool HasErrors { get { return m_errors.Count > 0; } } /// /// Does the file has warnings? /// public bool HasWarnings { get { return m_warnings.Count > 0; } } #endregion #region Errors/Warnings management /// /// Add a warning /// public void AddWarning(DataFileError.Codes _code, string _message) { RemoveWarning(_code); m_warnings.Add(new DataFileError(_code, _message)); } /// /// Add a warning message with a generic code /// public void AddWarning(string _message) { RemoveWarning(DataFileError.Codes.Generic); m_warnings.Add(new DataFileError(_message)); } /// /// Add a warning code with the generic message /// public void AddWarning(DataFileError.Codes _code) { RemoveWarning(_code); m_warnings.Add(new DataFileError(_code)); } /// /// Remove the warning with this code /// public void RemoveWarning(DataFileError.Codes _code) { foreach (DataFileError warning in m_warnings) { if (warning.Code == _code) { m_warnings.Remove(warning); return; } } } /// /// Add an error /// public void AddError(DataFileError.Codes _code, string _message) { RemoveError(_code); m_errors.Add(new DataFileError(_code, _message)); } /// /// Add an error message with a generic code /// public void AddError(string _message) { RemoveError(DataFileError.Codes.Generic); m_errors.Add(new DataFileError(_message)); } /// /// Add an error code with the generic message /// public void AddError(DataFileError.Codes _code) { RemoveError(_code); m_errors.Add(new DataFileError(_code)); } /// /// Remove the error with this code /// public void RemoveError(DataFileError.Codes _code) { foreach (DataFileError error in m_errors) { if (error.Code == _code) { m_errors.Remove(error); return; } } } /// /// Remove all errors and all warnings /// public void ClearErrorsAndWarnings() { m_errors.Clear(); m_warnings.Clear(); } #endregion #region Load/Save /// /// Save into an XML node /// true if success /// public bool Save(XElement _node) { bool result = DataFileKey.Save(m_key, _node); _node.SetAttributeValue("Path", m_filePath); _node.SetAttributeValue("LastModificationTime", m_lastModificationTime.ToString("o")); _node.SetAttributeValue("Length", m_length); _node.SetAttributeValue("LastCheckTime", m_lastCheckTime.ToString("o")); _node.SetAttributeValue("LastDependenciesCheckTime", m_lastDependenciesCheckTime.ToString("o")); foreach (DataFileDependency dep in m_children) { XElement depElem = new XElement("Child"); result &= dep.Save(depElem); _node.Add(depElem); } foreach (DataFileError warning in m_warnings) { XElement warningElement = new XElement("Warning"); result &= warning.Save(warningElement); _node.Add(warningElement); } foreach (DataFileError error in m_errors) { XElement errorElement = new XElement("Error"); result &= error.Save(errorElement); _node.Add(errorElement); } return result; } /// /// Load from an XML node /// true if success /// public bool Load(XElement _node) { m_key = DataFileKey.Load(_node); bool result = !m_key.IsInvalid(); m_filePath = _node.Attribute("Path").Value; m_normalizedPath = PathUtils.Normalize(m_filePath); XAttribute attr = _node.Attribute("LastModificationTime"); if (attr == null || !DateTime.TryParse(attr.Value, out m_lastModificationTime)) m_lastModificationTime = DateTimeExtensions.Invalid; attr = _node.Attribute("Length"); if (attr == null || !long.TryParse(attr.Value, out m_length)) m_length = 0; attr = _node.Attribute("LastCheckTime"); if (attr == null || !DateTime.TryParse(attr.Value, out m_lastCheckTime)) m_lastCheckTime = DateTimeExtensions.Invalid; attr = _node.Attribute("LastDependenciesCheckTime"); if (attr == null || !DateTime.TryParse(attr.Value, out m_lastDependenciesCheckTime)) m_lastDependenciesCheckTime = DateTimeExtensions.Invalid; foreach (XElement depElement in _node.Elements("Child")) { DataFileDependency dep = new DataFileDependency(); if (dep.Load(depElement)) m_children.Add(dep); else result = false; } foreach (XElement warningElement in _node.Elements("Warning")) { DataFileError warning = new DataFileError(""); if (warning.Load(warningElement)) m_warnings.Add(warning); else result = false; } foreach (XElement errorElement in _node.Elements("Error")) { DataFileError error = new DataFileError(""); if (error.Load(errorElement)) m_errors.Add(error); else result = false; } return result; } #endregion #region Child/Parent management /// /// Get a child dependency by key /// null if not found /// public DataFileDependency GetChild(DataFileKey _key) { foreach (DataFileDependency dep in m_children) { if (dep.Key.Equals(_key)) return dep; } return null; } /// /// Get a child dependency by path /// null if not found /// public DataFileDependency GetChild(string _normalizedPath) { foreach (DataFileDependency dep in m_children) { if (dep.Path == _normalizedPath) return dep; } return null; } /// /// Get a parent dependency by key /// null if not found /// public DataFileDependency GetParent(DataFileKey _key) { foreach (DataFileDependency dep in m_parents) { if (dep.Key == _key) return dep; } return null; } /// /// Get a parent dependency by path /// null if not found /// public DataFileDependency GetParent(string _normalizedPath) { foreach (DataFileDependency dep in m_parents) { if (dep.Path == _normalizedPath) return dep; } return null; } /// /// Get the children by platform /// The list of dependencies on this platform /// public IEnumerable GetChildrenByPlatform(Platform _platform) { List result = new List(); foreach (DataFileDependency dep in m_children) { if (dep.Platforms.Contains(_platform)) result.Add(dep); } return result; } /// /// Add a child dependency on a platform /// public void AddChild(string _normalizedPath, DataFileKey _key, HashSet _platforms, bool _missing) { DataFileDependency dependency = _key.IsInvalid() ? GetChild(_normalizedPath) : GetChild(_key); if (dependency != null) { dependency.Platforms.UnionWith(_platforms); dependency.Missing = _missing; } else { DataFileDependency newDependency = new DataFileDependency() { Path = _normalizedPath, Key = _key, Missing = _missing }; newDependency.Platforms.UnionWith(_platforms); m_children.Add(newDependency); } } /// /// Add a parent dependency on the given platforms /// public void AddParent(string _normalizedPath, DataFileKey _key, HashSet _platforms) { DataFileDependency dependency = _key.IsInvalid() ? GetParent(_normalizedPath) : GetParent(_key); if (dependency != null) { dependency.Platforms.UnionWith(_platforms); } else { RemoveWarning(DataFileError.Codes.Orphan); DataFileDependency newDependency = new DataFileDependency() { Path = _normalizedPath, Key = _key }; newDependency.Platforms.UnionWith(_platforms); m_parents.Add(newDependency); } } /// /// Remove a child dependency on the given platforms /// public void RemoveChild(DataFileKey _key, HashSet _platforms) { DataFileDependency childDependency = GetChild(_key); if (childDependency != null) RemoveChild(childDependency, _platforms); } /// /// Remove a child dependency on the given platforms /// public void RemoveChild(DataFileDependency _dependency, HashSet _platforms) { _dependency.Platforms.ExceptWith(_platforms); if (_dependency.Platforms.Count == 0) m_children.Remove(_dependency); } /// /// Remove a parent dependency on the given platforms /// public void RemoveParent(DataFileKey _key, HashSet _platforms) { DataFileDependency parentDependency = GetParent(_key); if (parentDependency != null) RemoveParent(parentDependency, _platforms); } /// /// Remove a parent dependency on the given platforms /// public void RemoveParent(DataFileDependency _dependency, HashSet _platforms) { _dependency.Platforms.ExceptWith(_platforms); if (_dependency.Platforms.Count == 0) { m_parents.Remove(_dependency); if (m_parents.Count == 0) { string extension = UAF.PathUtils.GetExtension(NormalizedPath); if (!OrphanDetectionOperation.SkippedExtensions.Contains(extension)) { AddWarning(DataFileError.Codes.Orphan); } } } } /// /// A child file has been deleted /// public void OnChildDeleted(DataFileKey _childKey) { DataFileDependency dependency = GetChild(_childKey); if (dependency != null) { dependency.Missing = true; if (!HasMissingDependencies) AddError(DataFileError.Codes.UnresolvedDependencies); } } #endregion } }