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
}
}