451 lines
14 KiB
C#
451 lines
14 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
|
|
namespace Server.Engines.Reports
|
|
{
|
|
public class StaffHistory : PersistableObject
|
|
{
|
|
#region Type Identification
|
|
public static readonly PersistableType ThisTypeID = new PersistableType("stfhst", new ConstructCallback(Construct));
|
|
|
|
private static PersistableObject Construct()
|
|
{
|
|
return new StaffHistory();
|
|
}
|
|
|
|
public override PersistableType TypeID
|
|
{
|
|
get
|
|
{
|
|
return ThisTypeID;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
private PageInfoCollection m_Pages;
|
|
private QueueStatusCollection m_QueueStats;
|
|
|
|
private Hashtable m_UserInfo;
|
|
private Hashtable m_StaffInfo;
|
|
|
|
public PageInfoCollection Pages
|
|
{
|
|
get
|
|
{
|
|
return this.m_Pages;
|
|
}
|
|
set
|
|
{
|
|
this.m_Pages = value;
|
|
}
|
|
}
|
|
public QueueStatusCollection QueueStats
|
|
{
|
|
get
|
|
{
|
|
return this.m_QueueStats;
|
|
}
|
|
set
|
|
{
|
|
this.m_QueueStats = value;
|
|
}
|
|
}
|
|
|
|
public Hashtable UserInfo
|
|
{
|
|
get
|
|
{
|
|
return this.m_UserInfo;
|
|
}
|
|
set
|
|
{
|
|
this.m_UserInfo = value;
|
|
}
|
|
}
|
|
public Hashtable StaffInfo
|
|
{
|
|
get
|
|
{
|
|
return this.m_StaffInfo;
|
|
}
|
|
set
|
|
{
|
|
this.m_StaffInfo = value;
|
|
}
|
|
}
|
|
|
|
public void AddPage(PageInfo info)
|
|
{
|
|
lock (SaveLock)
|
|
this.m_Pages.Add(info);
|
|
|
|
info.History = this;
|
|
}
|
|
|
|
public StaffHistory()
|
|
{
|
|
this.m_Pages = new PageInfoCollection();
|
|
this.m_QueueStats = new QueueStatusCollection();
|
|
|
|
this.m_UserInfo = new Hashtable(StringComparer.OrdinalIgnoreCase);
|
|
this.m_StaffInfo = new Hashtable(StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public StaffInfo GetStaffInfo(string account)
|
|
{
|
|
lock (RenderLock)
|
|
{
|
|
if (account == null || account.Length == 0)
|
|
return null;
|
|
|
|
StaffInfo info = this.m_StaffInfo[account] as StaffInfo;
|
|
|
|
if (info == null)
|
|
this.m_StaffInfo[account] = info = new StaffInfo(account);
|
|
|
|
return info;
|
|
}
|
|
}
|
|
|
|
public UserInfo GetUserInfo(string account)
|
|
{
|
|
if (account == null || account.Length == 0)
|
|
return null;
|
|
|
|
UserInfo info = this.m_UserInfo[account] as UserInfo;
|
|
|
|
if (info == null)
|
|
this.m_UserInfo[account] = info = new UserInfo(account);
|
|
|
|
return info;
|
|
}
|
|
|
|
public static readonly object RenderLock = new object();
|
|
public static readonly object SaveLock = new object();
|
|
|
|
public void Save()
|
|
{
|
|
lock (SaveLock)
|
|
{
|
|
string path = Path.Combine(Core.BaseDirectory, "staffHistory.xml");
|
|
PersistenceWriter pw = new XmlPersistenceWriter(path, "Staff");
|
|
|
|
pw.WriteDocument(this);
|
|
|
|
pw.Close();
|
|
}
|
|
}
|
|
|
|
public void Load()
|
|
{
|
|
string path = Path.Combine(Core.BaseDirectory, "staffHistory.xml");
|
|
|
|
if (!File.Exists(path))
|
|
return;
|
|
|
|
PersistenceReader pr = new XmlPersistenceReader(path, "Staff");
|
|
|
|
pr.ReadDocument(this);
|
|
|
|
pr.Close();
|
|
}
|
|
|
|
public override void SerializeChildren(PersistenceWriter op)
|
|
{
|
|
for (int i = 0; i < this.m_Pages.Count; ++i)
|
|
this.m_Pages[i].Serialize(op);
|
|
|
|
for (int i = 0; i < this.m_QueueStats.Count; ++i)
|
|
this.m_QueueStats[i].Serialize(op);
|
|
}
|
|
|
|
public override void DeserializeChildren(PersistenceReader ip)
|
|
{
|
|
DateTime min = DateTime.UtcNow - TimeSpan.FromDays(8.0);
|
|
|
|
while (ip.HasChild)
|
|
{
|
|
PersistableObject obj = ip.GetChild();
|
|
|
|
if (obj is PageInfo)
|
|
{
|
|
PageInfo pageInfo = obj as PageInfo;
|
|
|
|
pageInfo.UpdateResolver();
|
|
|
|
if (pageInfo.TimeSent >= min || pageInfo.TimeResolved >= min)
|
|
{
|
|
this.m_Pages.Add(pageInfo);
|
|
pageInfo.History = this;
|
|
}
|
|
else
|
|
{
|
|
pageInfo.Sender = null;
|
|
pageInfo.Resolver = null;
|
|
}
|
|
}
|
|
else if (obj is QueueStatus)
|
|
{
|
|
QueueStatus queueStatus = obj as QueueStatus;
|
|
|
|
if (queueStatus.TimeStamp >= min)
|
|
this.m_QueueStats.Add(queueStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
public StaffInfo[] GetStaff()
|
|
{
|
|
StaffInfo[] staff = new StaffInfo[this.m_StaffInfo.Count];
|
|
int index = 0;
|
|
|
|
foreach (StaffInfo staffInfo in this.m_StaffInfo.Values)
|
|
staff[index++] = staffInfo;
|
|
|
|
return staff;
|
|
}
|
|
|
|
public void Render(ObjectCollection objects)
|
|
{
|
|
lock (RenderLock)
|
|
{
|
|
objects.Add(this.GraphQueueStatus());
|
|
|
|
StaffInfo[] staff = this.GetStaff();
|
|
|
|
BaseInfo.SortRange = TimeSpan.FromDays(7.0);
|
|
Array.Sort(staff);
|
|
|
|
objects.Add(this.GraphHourlyPages(this.m_Pages, PageResolution.None, "New pages by hour", "graph_new_pages_hr"));
|
|
objects.Add(this.GraphHourlyPages(this.m_Pages, PageResolution.Handled, "Handled pages by hour", "graph_handled_pages_hr"));
|
|
objects.Add(this.GraphHourlyPages(this.m_Pages, PageResolution.Deleted, "Deleted pages by hour", "graph_deleted_pages_hr"));
|
|
objects.Add(this.GraphHourlyPages(this.m_Pages, PageResolution.Canceled, "Canceled pages by hour", "graph_canceled_pages_hr"));
|
|
objects.Add(this.GraphHourlyPages(this.m_Pages, PageResolution.Logged, "Logged-out pages by hour", "graph_logged_pages_hr"));
|
|
|
|
BaseInfo.SortRange = TimeSpan.FromDays(1.0);
|
|
Array.Sort(staff);
|
|
|
|
objects.Add(this.ReportTotalPages(staff, TimeSpan.FromDays(1.0), "1 Day"));
|
|
objects.AddRange((PersistableObject[])this.ChartTotalPages(staff, TimeSpan.FromDays(1.0), "1 Day", "graph_daily_pages"));
|
|
|
|
BaseInfo.SortRange = TimeSpan.FromDays(7.0);
|
|
Array.Sort(staff);
|
|
|
|
objects.Add(this.ReportTotalPages(staff, TimeSpan.FromDays(7.0), "1 Week"));
|
|
objects.AddRange((PersistableObject[])this.ChartTotalPages(staff, TimeSpan.FromDays(7.0), "1 Week", "graph_weekly_pages"));
|
|
|
|
BaseInfo.SortRange = TimeSpan.FromDays(30.0);
|
|
Array.Sort(staff);
|
|
|
|
objects.Add(this.ReportTotalPages(staff, TimeSpan.FromDays(30.0), "1 Month"));
|
|
objects.AddRange((PersistableObject[])this.ChartTotalPages(staff, TimeSpan.FromDays(30.0), "1 Month", "graph_monthly_pages"));
|
|
|
|
for (int i = 0; i < staff.Length; ++i)
|
|
objects.Add(this.GraphHourlyPages(staff[i]));
|
|
}
|
|
}
|
|
|
|
public static int GetPageCount(StaffInfo staff, DateTime min, DateTime max)
|
|
{
|
|
return GetPageCount(staff.Pages, PageResolution.Handled, min, max);
|
|
}
|
|
|
|
public static int GetPageCount(PageInfoCollection pages, PageResolution res, DateTime min, DateTime max)
|
|
{
|
|
int count = 0;
|
|
|
|
for (int i = 0; i < pages.Count; ++i)
|
|
{
|
|
if (res != PageResolution.None && pages[i].Resolution != res)
|
|
continue;
|
|
|
|
DateTime ts = pages[i].TimeResolved;
|
|
|
|
if (ts >= min && ts < max)
|
|
++count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
private BarGraph GraphQueueStatus()
|
|
{
|
|
int[] totals = new int[24];
|
|
int[] counts = new int[24];
|
|
|
|
DateTime max = DateTime.UtcNow;
|
|
DateTime min = max - TimeSpan.FromDays(7.0);
|
|
|
|
for (int i = 0; i < this.m_QueueStats.Count; ++i)
|
|
{
|
|
DateTime ts = this.m_QueueStats[i].TimeStamp;
|
|
|
|
if (ts >= min && ts < max)
|
|
{
|
|
DateTime date = ts.Date;
|
|
TimeSpan time = ts.TimeOfDay;
|
|
|
|
int hour = time.Hours;
|
|
|
|
totals[hour] += this.m_QueueStats[i].Count;
|
|
counts[hour]++;
|
|
}
|
|
}
|
|
|
|
BarGraph barGraph = new BarGraph("Average pages in queue", "graph_pagequeue_avg", 10, "Time", "Pages", BarGraphRenderMode.Lines);
|
|
|
|
barGraph.FontSize = 6;
|
|
|
|
for (int i = 7; i <= totals.Length + 7; ++i)
|
|
{
|
|
int val;
|
|
|
|
if (counts[i % totals.Length] == 0)
|
|
val = 0;
|
|
else
|
|
val = (totals[i % totals.Length] + (counts[i % totals.Length] / 2)) / counts[i % totals.Length];
|
|
|
|
int realHours = i % totals.Length;
|
|
int hours;
|
|
|
|
if (realHours == 0)
|
|
hours = 12;
|
|
else if (realHours > 12)
|
|
hours = realHours - 12;
|
|
else
|
|
hours = realHours;
|
|
|
|
barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val);
|
|
}
|
|
|
|
return barGraph;
|
|
}
|
|
|
|
private BarGraph GraphHourlyPages(StaffInfo staff)
|
|
{
|
|
return this.GraphHourlyPages(staff.Pages, PageResolution.Handled, "Average pages handled by " + staff.Display, "graphs_" + staff.Account.ToLower() + "_avg");
|
|
}
|
|
|
|
private BarGraph GraphHourlyPages(PageInfoCollection pages, PageResolution res, string title, string fname)
|
|
{
|
|
int[] totals = new int[24];
|
|
int[] counts = new int[24];
|
|
|
|
DateTime[] dates = new DateTime[24];
|
|
|
|
DateTime max = DateTime.UtcNow;
|
|
DateTime min = max - TimeSpan.FromDays(7.0);
|
|
|
|
bool sentStamp = (res == PageResolution.None);
|
|
|
|
for (int i = 0; i < pages.Count; ++i)
|
|
{
|
|
if (res != PageResolution.None && pages[i].Resolution != res)
|
|
continue;
|
|
|
|
DateTime ts = (sentStamp ? pages[i].TimeSent : pages[i].TimeResolved);
|
|
|
|
if (ts >= min && ts < max)
|
|
{
|
|
DateTime date = ts.Date;
|
|
TimeSpan time = ts.TimeOfDay;
|
|
|
|
int hour = time.Hours;
|
|
|
|
totals[hour]++;
|
|
|
|
if (dates[hour] != date)
|
|
{
|
|
counts[hour]++;
|
|
dates[hour] = date;
|
|
}
|
|
}
|
|
}
|
|
|
|
BarGraph barGraph = new BarGraph(title, fname, 10, "Time", "Pages", BarGraphRenderMode.Lines);
|
|
|
|
barGraph.FontSize = 6;
|
|
|
|
for (int i = 7; i <= totals.Length + 7; ++i)
|
|
{
|
|
int val;
|
|
|
|
if (counts[i % totals.Length] == 0)
|
|
val = 0;
|
|
else
|
|
val = (totals[i % totals.Length] + (counts[i % totals.Length] / 2)) / counts[i % totals.Length];
|
|
|
|
int realHours = i % totals.Length;
|
|
int hours;
|
|
|
|
if (realHours == 0)
|
|
hours = 12;
|
|
else if (realHours > 12)
|
|
hours = realHours - 12;
|
|
else
|
|
hours = realHours;
|
|
|
|
barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val);
|
|
}
|
|
|
|
return barGraph;
|
|
}
|
|
|
|
private Report ReportTotalPages(StaffInfo[] staff, TimeSpan ts, string title)
|
|
{
|
|
DateTime max = DateTime.UtcNow;
|
|
DateTime min = max - ts;
|
|
|
|
Report report = new Report(title + " Staff Report", "400");
|
|
|
|
report.Columns.Add("65%", "left", "Staff Name");
|
|
report.Columns.Add("35%", "center", "Page Count");
|
|
|
|
for (int i = 0; i < staff.Length; ++i)
|
|
report.Items.Add(staff[i].Display, GetPageCount(staff[i], min, max));
|
|
|
|
return report;
|
|
}
|
|
|
|
private PieChart[] ChartTotalPages(StaffInfo[] staff, TimeSpan ts, string title, string fname)
|
|
{
|
|
DateTime max = DateTime.UtcNow;
|
|
DateTime min = max - ts;
|
|
|
|
PieChart staffChart = new PieChart(title + " Staff Chart", fname + "_staff", true);
|
|
|
|
int other = 0;
|
|
|
|
for (int i = 0; i < staff.Length; ++i)
|
|
{
|
|
int count = GetPageCount(staff[i], min, max);
|
|
|
|
if (i < 12 && count > 0)
|
|
staffChart.Items.Add(staff[i].Display, count);
|
|
else
|
|
other += count;
|
|
}
|
|
|
|
if (other > 0)
|
|
staffChart.Items.Add("Other", other);
|
|
|
|
PieChart resChart = new PieChart(title + " Resolutions", fname + "_resol", true);
|
|
|
|
int countTotal = GetPageCount(this.m_Pages, PageResolution.None, min, max);
|
|
int countHandled = GetPageCount(this.m_Pages, PageResolution.Handled, min, max);
|
|
int countDeleted = GetPageCount(this.m_Pages, PageResolution.Deleted, min, max);
|
|
int countCanceled = GetPageCount(this.m_Pages, PageResolution.Canceled, min, max);
|
|
int countLogged = GetPageCount(this.m_Pages, PageResolution.Logged, min, max);
|
|
int countUnres = countTotal - (countHandled + countDeleted + countCanceled + countLogged);
|
|
|
|
resChart.Items.Add("Handled", countHandled);
|
|
resChart.Items.Add("Deleted", countDeleted);
|
|
resChart.Items.Add("Canceled", countCanceled);
|
|
resChart.Items.Add("Logged Out", countLogged);
|
|
resChart.Items.Add("Unresolved", countUnres);
|
|
|
|
return new PieChart[] { staffChart, resChart };
|
|
}
|
|
}
|
|
} |