540 lines
19 KiB
C#
540 lines
19 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Web.UI;
|
|
using HtmlAttr = System.Web.UI.HtmlTextWriterAttribute;
|
|
using HtmlTag = System.Web.UI.HtmlTextWriterTag;
|
|
using Server.Misc;
|
|
|
|
namespace Server.Engines.Reports
|
|
{
|
|
public class HtmlRenderer
|
|
{
|
|
private static readonly string FtpHost = null;
|
|
private static readonly string FtpUsername = null;
|
|
private static readonly string FtpPassword = null;
|
|
private static readonly string FtpStatsDirectory = null;
|
|
private static readonly string FtpStaffDirectory = null;
|
|
private readonly string m_Type;
|
|
private readonly string m_Title;
|
|
private readonly string m_OutputDirectory;
|
|
private readonly DateTime m_TimeStamp;
|
|
private readonly ObjectCollection m_Objects;
|
|
public HtmlRenderer(string outputDirectory, Snapshot ss, SnapshotHistory history)
|
|
: this(outputDirectory)
|
|
{
|
|
this.m_TimeStamp = ss.TimeStamp;
|
|
|
|
this.m_Objects = new ObjectCollection();
|
|
|
|
for (int i = 0; i < ss.Children.Count; ++i)
|
|
this.m_Objects.Add(ss.Children[i]);
|
|
|
|
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Clients", 1, 100, 6));
|
|
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Items", 24, 9, 1));
|
|
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Players", 24, 9, 1));
|
|
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "NPCs", 24, 9, 1));
|
|
this.m_Objects.Add(BarGraph.DailyAverage(history, "General Stats", "Clients"));
|
|
this.m_Objects.Add(BarGraph.Growth(history, "General Stats", "Clients"));
|
|
}
|
|
|
|
public HtmlRenderer(string outputDirectory, StaffHistory history)
|
|
: this(outputDirectory)
|
|
{
|
|
this.m_TimeStamp = DateTime.UtcNow;
|
|
|
|
this.m_Objects = new ObjectCollection();
|
|
|
|
history.Render(this.m_Objects);
|
|
}
|
|
|
|
private HtmlRenderer(string outputDirectory)
|
|
{
|
|
this.m_Type = outputDirectory;
|
|
this.m_Title = (this.m_Type == "staff" ? "Staff" : "Stats");
|
|
this.m_OutputDirectory = Path.Combine(Core.BaseDirectory, Config.Get("Reports.Path", "reports"));
|
|
|
|
if (!Directory.Exists(this.m_OutputDirectory))
|
|
Directory.CreateDirectory(this.m_OutputDirectory);
|
|
|
|
this.m_OutputDirectory = Path.Combine(this.m_OutputDirectory, outputDirectory);
|
|
|
|
if (!Directory.Exists(this.m_OutputDirectory))
|
|
Directory.CreateDirectory(this.m_OutputDirectory);
|
|
}
|
|
|
|
public static string SafeFileName(string name)
|
|
{
|
|
return name.ToLower().Replace(' ', '_');
|
|
}
|
|
|
|
public void Render()
|
|
{
|
|
Console.WriteLine("Reports: {0}: Render started", this.m_Title);
|
|
|
|
this.RenderFull();
|
|
|
|
for (int i = 0; i < this.m_Objects.Count; ++i)
|
|
this.RenderSingle(this.m_Objects[i]);
|
|
|
|
Console.WriteLine("Reports: {0}: Render complete", this.m_Title);
|
|
}
|
|
|
|
public void Upload()
|
|
{
|
|
if (FtpHost == null)
|
|
return;
|
|
|
|
Console.WriteLine("Reports: {0}: Upload started", this.m_Title);
|
|
|
|
string filePath = Path.Combine(this.m_OutputDirectory, "upload.ftp");
|
|
|
|
using (StreamWriter op = new StreamWriter(filePath))
|
|
{
|
|
op.WriteLine("open \"{0}\"", FtpHost);
|
|
op.WriteLine(FtpUsername);
|
|
op.WriteLine(FtpPassword);
|
|
op.WriteLine("cd \"{0}\"", (this.m_Type == "staff" ? FtpStaffDirectory : FtpStatsDirectory));
|
|
op.WriteLine("mput \"{0}\"", Path.Combine(this.m_OutputDirectory, "*.html"));
|
|
op.WriteLine("mput \"{0}\"", Path.Combine(this.m_OutputDirectory, "*.css"));
|
|
op.WriteLine("binary");
|
|
op.WriteLine("mput \"{0}\"", Path.Combine(this.m_OutputDirectory, "*.png"));
|
|
op.WriteLine("disconnect");
|
|
op.Write("quit");
|
|
}
|
|
|
|
ProcessStartInfo psi = new ProcessStartInfo();
|
|
|
|
psi.FileName = "ftp";
|
|
psi.Arguments = String.Format("-i -s:\"{0}\"", filePath);
|
|
|
|
psi.CreateNoWindow = true;
|
|
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
|
//psi.UseShellExecute = true;
|
|
|
|
try
|
|
{
|
|
Process p = Process.Start(psi);
|
|
|
|
p.WaitForExit();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
Console.WriteLine("Reports: {0}: Upload complete", this.m_Title);
|
|
|
|
try
|
|
{
|
|
File.Delete(filePath);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
public void RenderFull()
|
|
{
|
|
string filePath = Path.Combine(this.m_OutputDirectory, "reports.html");
|
|
|
|
using (StreamWriter op = new StreamWriter(filePath))
|
|
{
|
|
using (HtmlTextWriter html = new HtmlTextWriter(op, "\t"))
|
|
this.RenderFull(html);
|
|
}
|
|
|
|
string cssPath = Path.Combine(this.m_OutputDirectory, "styles.css");
|
|
|
|
if (File.Exists(cssPath))
|
|
return;
|
|
|
|
using (StreamWriter css = new StreamWriter(cssPath))
|
|
{
|
|
css.WriteLine("body { background-color: #FFFFFF; font-family: verdana, arial; font-size: 11px; }");
|
|
css.WriteLine("a { color: #28435E; }");
|
|
css.WriteLine("a:hover { color: #4878A9; }");
|
|
css.WriteLine("td.header { background-color: #9696AA; font-weight: bold; font-size: 12px; }");
|
|
css.WriteLine("td.lentry { background-color: #D7D7EB; width: 10%; }");
|
|
css.WriteLine("td.rentry { background-color: #FFFFFF; width: 90%; }");
|
|
css.WriteLine("td.entry { background-color: #FFFFFF; }");
|
|
css.WriteLine("td { font-size: 11px; }");
|
|
css.Write(".tbl-border { background-color: #46465A; }");
|
|
}
|
|
}
|
|
|
|
public void RenderFull(HtmlTextWriter html)
|
|
{
|
|
html.RenderBeginTag(HtmlTag.Html);
|
|
|
|
html.RenderBeginTag(HtmlTag.Head);
|
|
|
|
html.RenderBeginTag(HtmlTag.Title);
|
|
html.Write("{0} Statistics", ServerList.ServerName);
|
|
html.RenderEndTag();
|
|
|
|
html.AddAttribute("rel", "stylesheet");
|
|
html.AddAttribute(HtmlAttr.Type, "text/css");
|
|
html.AddAttribute(HtmlAttr.Href, "styles.css");
|
|
html.RenderBeginTag(HtmlTag.Link);
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
|
|
html.RenderBeginTag(HtmlTag.Body);
|
|
|
|
for (int i = 0; i < this.m_Objects.Count; ++i)
|
|
{
|
|
this.RenderDirect(this.m_Objects[i], html);
|
|
html.Write("<br><br>");
|
|
}
|
|
|
|
html.RenderBeginTag(HtmlTag.Center);
|
|
TimeZoneInfo tz = TimeZoneInfo.Local;
|
|
bool isDaylight = tz.IsDaylightSavingTime(this.m_TimeStamp);
|
|
TimeSpan utcOffset = tz.GetUtcOffset(this.m_TimeStamp);
|
|
|
|
html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", this.m_TimeStamp, tz.StandardName);
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
}
|
|
|
|
public void RenderSingle(PersistableObject obj)
|
|
{
|
|
string filePath = Path.Combine(this.m_OutputDirectory, SafeFileName(this.FindNameFrom(obj)) + ".html");
|
|
|
|
using (StreamWriter op = new StreamWriter(filePath))
|
|
{
|
|
using (HtmlTextWriter html = new HtmlTextWriter(op, "\t"))
|
|
this.RenderSingle(obj, html);
|
|
}
|
|
}
|
|
|
|
public void RenderSingle(PersistableObject obj, HtmlTextWriter html)
|
|
{
|
|
html.RenderBeginTag(HtmlTag.Html);
|
|
|
|
html.RenderBeginTag(HtmlTag.Head);
|
|
|
|
html.RenderBeginTag(HtmlTag.Title);
|
|
html.Write("{0} Statistics - {1}", ServerList.ServerName, this.FindNameFrom(obj));
|
|
html.RenderEndTag();
|
|
|
|
html.AddAttribute("rel", "stylesheet");
|
|
html.AddAttribute(HtmlAttr.Type, "text/css");
|
|
html.AddAttribute(HtmlAttr.Href, "styles.css");
|
|
html.RenderBeginTag(HtmlTag.Link);
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
|
|
html.RenderBeginTag(HtmlTag.Body);
|
|
|
|
html.RenderBeginTag(HtmlTag.Center);
|
|
|
|
this.RenderDirect(obj, html);
|
|
|
|
html.Write("<br>");
|
|
|
|
TimeZoneInfo tz = TimeZoneInfo.Local;
|
|
bool isDaylight = tz.IsDaylightSavingTime(this.m_TimeStamp);
|
|
TimeSpan utcOffset = tz.GetUtcOffset(this.m_TimeStamp);
|
|
|
|
html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", this.m_TimeStamp, tz.StandardName);
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
}
|
|
|
|
public void RenderDirect(PersistableObject obj, HtmlTextWriter html)
|
|
{
|
|
if (obj is Report)
|
|
this.RenderReport(obj as Report, html);
|
|
else if (obj is BarGraph)
|
|
this.RenderBarGraph(obj as BarGraph, html);
|
|
else if (obj is PieChart)
|
|
this.RenderPieChart(obj as PieChart, html);
|
|
}
|
|
|
|
private string FindNameFrom(PersistableObject obj)
|
|
{
|
|
if (obj is Report)
|
|
return (obj as Report).Name;
|
|
else if (obj is Chart)
|
|
return (obj as Chart).Name;
|
|
|
|
return "Invalid";
|
|
}
|
|
|
|
private void RenderPieChart(PieChart chart, HtmlTextWriter html)
|
|
{
|
|
PieChartRenderer pieChart = new PieChartRenderer(Color.White);
|
|
|
|
pieChart.ShowPercents = chart.ShowPercents;
|
|
|
|
string[] labels = new string[chart.Items.Count];
|
|
string[] values = new string[chart.Items.Count];
|
|
|
|
for (int i = 0; i < chart.Items.Count; ++i)
|
|
{
|
|
ChartItem item = chart.Items[i];
|
|
|
|
labels[i] = item.Name;
|
|
values[i] = item.Value.ToString();
|
|
}
|
|
|
|
pieChart.CollectDataPoints(labels, values);
|
|
|
|
Bitmap bmp = pieChart.Draw();
|
|
|
|
string fileName = chart.FileName + ".png";
|
|
bmp.Save(Path.Combine(this.m_OutputDirectory, fileName), ImageFormat.Png);
|
|
|
|
html.Write("<!-- ");
|
|
|
|
html.AddAttribute(HtmlAttr.Href, "#");
|
|
html.AddAttribute(HtmlAttr.Onclick, String.Format("javascript:window.open('{0}.html','ChildWindow','width={1},height={2},resizable=no,status=no,toolbar=no')", SafeFileName(this.FindNameFrom(chart)), bmp.Width + 30, bmp.Height + 80));
|
|
html.RenderBeginTag(HtmlTag.A);
|
|
html.Write(chart.Name);
|
|
html.RenderEndTag();
|
|
|
|
html.Write(" -->");
|
|
|
|
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
|
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
|
html.AddAttribute(HtmlAttr.Border, "0");
|
|
html.RenderBeginTag(HtmlTag.Table);
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
|
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
|
html.RenderBeginTag(HtmlTag.Table);
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
|
|
html.AddAttribute(HtmlAttr.Colspan, "10");
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Align, "center");
|
|
html.AddAttribute(HtmlAttr.Class, "header");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
html.Write(chart.Name);
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
|
|
html.AddAttribute(HtmlAttr.Colspan, "10");
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Align, "center");
|
|
html.AddAttribute(HtmlAttr.Class, "entry");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
|
|
html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString());
|
|
html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString());
|
|
html.AddAttribute(HtmlAttr.Src, fileName);
|
|
html.RenderBeginTag(HtmlTag.Img);
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
|
|
bmp.Dispose();
|
|
}
|
|
|
|
private void RenderBarGraph(BarGraph graph, HtmlTextWriter html)
|
|
{
|
|
BarGraphRenderer barGraph = new BarGraphRenderer(Color.White);
|
|
|
|
barGraph.RenderMode = graph.RenderMode;
|
|
|
|
barGraph._regions = graph.Regions;
|
|
barGraph.SetTitles(graph.xTitle, null);
|
|
|
|
if (graph.yTitle != null)
|
|
barGraph.VerticalLabel = graph.yTitle;
|
|
|
|
barGraph.FontColor = Color.Black;
|
|
barGraph.ShowData = (graph.Interval == 1);
|
|
barGraph.VerticalTickCount = graph.Ticks;
|
|
|
|
string[] labels = new string[graph.Items.Count];
|
|
string[] values = new string[graph.Items.Count];
|
|
|
|
for (int i = 0; i < graph.Items.Count; ++i)
|
|
{
|
|
ChartItem item = graph.Items[i];
|
|
|
|
labels[i] = item.Name;
|
|
values[i] = item.Value.ToString();
|
|
}
|
|
|
|
barGraph._interval = graph.Interval;
|
|
barGraph.CollectDataPoints(labels, values);
|
|
|
|
Bitmap bmp = barGraph.Draw();
|
|
|
|
string fileName = graph.FileName + ".png";
|
|
bmp.Save(Path.Combine(this.m_OutputDirectory, fileName), ImageFormat.Png);
|
|
|
|
html.Write("<!-- ");
|
|
|
|
html.AddAttribute(HtmlAttr.Href, "#");
|
|
html.AddAttribute(HtmlAttr.Onclick, String.Format("javascript:window.open('{0}.html','ChildWindow','width={1},height={2},resizable=no,status=no,toolbar=no')", SafeFileName(this.FindNameFrom(graph)), bmp.Width + 30, bmp.Height + 80));
|
|
html.RenderBeginTag(HtmlTag.A);
|
|
html.Write(graph.Name);
|
|
html.RenderEndTag();
|
|
|
|
html.Write(" -->");
|
|
|
|
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
|
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
|
html.AddAttribute(HtmlAttr.Border, "0");
|
|
html.RenderBeginTag(HtmlTag.Table);
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
|
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
|
html.RenderBeginTag(HtmlTag.Table);
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
|
|
html.AddAttribute(HtmlAttr.Colspan, "10");
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Align, "center");
|
|
html.AddAttribute(HtmlAttr.Class, "header");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
html.Write(graph.Name);
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
|
|
html.AddAttribute(HtmlAttr.Colspan, "10");
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Align, "center");
|
|
html.AddAttribute(HtmlAttr.Class, "entry");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
|
|
html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString());
|
|
html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString());
|
|
html.AddAttribute(HtmlAttr.Src, fileName);
|
|
html.RenderBeginTag(HtmlTag.Img);
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
|
|
bmp.Dispose();
|
|
}
|
|
|
|
private void RenderReport(Report report, HtmlTextWriter html)
|
|
{
|
|
html.AddAttribute(HtmlAttr.Width, report.Width);
|
|
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
|
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
|
html.AddAttribute(HtmlAttr.Border, "0");
|
|
html.RenderBeginTag(HtmlTag.Table);
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
|
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
|
html.RenderBeginTag(HtmlTag.Table);
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
html.AddAttribute(HtmlAttr.Colspan, "10");
|
|
html.AddAttribute(HtmlAttr.Width, "100%");
|
|
html.AddAttribute(HtmlAttr.Align, "center");
|
|
html.AddAttribute(HtmlAttr.Class, "header");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
html.Write(report.Name);
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
|
|
bool isNamed = false;
|
|
|
|
for (int i = 0; i < report.Columns.Count && !isNamed; ++i)
|
|
isNamed = (report.Columns[i].Name != null);
|
|
|
|
if (isNamed)
|
|
{
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
|
|
for (int i = 0; i < report.Columns.Count; ++i)
|
|
{
|
|
ReportColumn column = report.Columns[i];
|
|
|
|
html.AddAttribute(HtmlAttr.Class, "header");
|
|
html.AddAttribute(HtmlAttr.Width, column.Width);
|
|
html.AddAttribute(HtmlAttr.Align, column.Align);
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
|
|
html.Write(column.Name);
|
|
|
|
html.RenderEndTag();
|
|
}
|
|
|
|
html.RenderEndTag();
|
|
}
|
|
|
|
for (int i = 0; i < report.Items.Count; ++i)
|
|
{
|
|
ReportItem item = report.Items[i];
|
|
|
|
html.RenderBeginTag(HtmlTag.Tr);
|
|
|
|
for (int j = 0; j < item.Values.Count; ++j)
|
|
{
|
|
if (!isNamed && j == 0)
|
|
html.AddAttribute(HtmlAttr.Width, report.Columns[j].Width);
|
|
|
|
html.AddAttribute(HtmlAttr.Align, report.Columns[j].Align);
|
|
html.AddAttribute(HtmlAttr.Class, "entry");
|
|
html.RenderBeginTag(HtmlTag.Td);
|
|
|
|
if (item.Values[j].Format == null)
|
|
html.Write(item.Values[j].Value);
|
|
else
|
|
html.Write(int.Parse(item.Values[j].Value).ToString(item.Values[j].Format));
|
|
|
|
html.RenderEndTag();
|
|
}
|
|
|
|
html.RenderEndTag();
|
|
}
|
|
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
html.RenderEndTag();
|
|
}
|
|
}
|
|
}
|