#region Copyright
// Diagnostic Explorer, a .Net diagnostic toolset
// Copyright (C) 2010 Cameron Elliot
//
// This file is part of Diagnostic Explorer.
//
// Diagnostic Explorer is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Diagnostic Explorer is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Diagnostic Explorer. If not, see <http://www.gnu.org/licenses/>.
//
// http://diagexplorer.sourceforge.net/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reflection;
namespace DiagnosticExplorer
{
internal class PropertyGetter
{
protected PropertyInfo prop;
public const int MAX_CONCAT_ITEMS = 10;
protected PropertyGetter()
{
}
public PropertyGetter(PropertyInfo prop)
{
this.prop = prop;
Name = prop.Name;
PropertyAttribute attr = GetPropertyAttribute(prop);
if (attr != null)
{
Name = attr.Name ?? Name;
Category = attr.Category;
Description = attr.Description;
FormatString = attr.FormatString ?? GetDefaultFormatString(prop.PropertyType);
}
}
protected static string MaxLengthString(string s, int maxLength)
{
if (s == null) return s;
if (s.Length <= maxLength) return s;
return s.Substring(0, maxLength);
}
public virtual IEnumerable<Property> GetProperties(object obj)
{
Property prop = new Property();
prop.Category = Category;
prop.Name = Name;
prop.Description = Description;
prop.Value = MaxLengthString(GetValue(obj), 8092);
yield return prop;
}
private string GetDefaultFormatString(Type type)
{
if (type == typeof(float))
return "{0:N2}";
if (type == typeof(double))
return "{0:N2}";
if (type == typeof(decimal))
return "{0:N2}";
if (type == typeof(DateTime) || type == typeof(DateTime?))
return "{0:d MMM yyyy H:mm:ss}";
return null;
}
private static PropertyAttribute GetPropertyAttribute(PropertyInfo info)
{
object[] attr = info.GetCustomAttributes(typeof(PropertyAttribute), false);
return attr.Length == 0 ? null : (PropertyAttribute)attr[0];
}
public string Name { get; protected set; }
public string Description { get; protected set; }
protected string FormatString { get; private set; }
public string Category { get; private set; }
public string GetValue(object obj)
{
return GetValue(obj, prop);
}
protected string FormatEnumerable(IEnumerable col, string separator, int maxItems)
{
IEnumerable<object> asObject = col.Cast<object>();
int count = asObject.Count();
if (count == 0)
return "0 items";
List<string> values = new List<string>();
if (maxItems <= 0)
maxItems = MAX_CONCAT_ITEMS;
int remaining = count - maxItems;
foreach (object o in asObject.Take(maxItems))
values.Add(FormatValue(o));
if (remaining > 0)
values.Add(string.Format("... ({0} more item{1})", remaining, remaining == 1 ? "" : "s"));
string pre = string.Format("{0} item{1}: ", count, count == 1 ? "" : "s");
return pre + string.Join(separator, values.ToArray());
}
public string GetValue(object obj, PropertyInfo propInfo)
{
try
{
object val = propInfo.GetValue(obj, null);
if (val == null)
return null;
return FormatValue(val);
}
catch (Exception ex)
{
return string.Format("<{0}>", ex.Message);
}
}
protected string FormatValue(object val)
{
if (val is TimeSpan)
return FormatTimeSpan((TimeSpan)val);
if (val is ICollection)
return FormatEnumerable((ICollection)val, Environment.NewLine, MAX_CONCAT_ITEMS);
if (FormatString != null)
return string.Format(FormatString, val);
return val.ToString();
}
protected static string FormatTimeSpan(TimeSpan span)
{
string sign= span < TimeSpan.Zero ? "-" : "";
string format = "{0}{2:D2}:{3:D2}:{4:D2}";
if (span.Days != 0)
format = "{0}{1}.{2:D2}:{3:D2}:{4:D2}";
if (Math.Abs(span.TotalSeconds) < 1)
format += ".{5:D2}";
return string.Format(format, sign,
Math.Abs(span.Days), Math.Abs(span.Hours),
Math.Abs(span.Minutes), Math.Abs(span.Seconds),
Math.Abs(span.Milliseconds));
}
}
}