using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using VisualTraceRoute.Net;
namespace VisualTraceRoute.Text
{
///
/// Text parser for writing output to various data structures.
///
public class Parser
{
private List _blocks;
private FileInfo _templateFile;
///
/// Initializes a new instance of the Parser class.
///
public Parser()
{
this._blocks = new List();
this._templateFile = null;
}
///
/// Initializes a new instance of the Parser class.
///
/// Template file path.
public Parser(string TemplateFile)
: this(new FileInfo(TemplateFile))
{
// Stubble.
}
///
/// Initializes a new instance of the Parser class.
///
/// Template file.
public Parser(FileInfo TemplateFile)
{
this._blocks = new List();
this._templateFile = TemplateFile;
}
///
/// Read the associated template.
///
public void ReadTemplate()
{
// Clear previous text blocks stored.
this._blocks.Clear();
if (this._templateFile == null)
{
return;
}
if (this._templateFile.Exists)
{
using (TextReader reader = new StreamReader(this._templateFile.OpenRead()))
{
StringBuilder newBlock = new StringBuilder();
// Check if there is more content to read.
while (reader.Peek() >= 0)
{
// Read the latest line.
string line = reader.ReadLine();
// Determine if there are any tokens that need to be processed.
if (line.ToUpper().Contains("{ROUTES}"))
{
this._blocks.Add(new TextBlock(newBlock.ToString()));
newBlock.Clear();
}
else if (line.ToUpper().Contains("{/ROUTES}"))
{
int idx = line.IndexOf("{/ROUTES}", 0, StringComparison.CurrentCultureIgnoreCase);
int trashLength = idx + "{/ROUTES}".Length;
string postText = line.Substring(trashLength, line.Length - trashLength);
this._blocks.Add(new TextBlock(newBlock.ToString(), BlockType.Route, postText));
newBlock.Clear();
}
else if (line.ToUpper().Contains("{HOPS}"))
{
this._blocks.Add(new TextBlock(newBlock.ToString(), BlockType.Route));
newBlock.Clear();
}
else if (line.ToUpper().Contains("{/HOPS}"))
{
int idx = line.IndexOf("{/HOPS}", 0, StringComparison.CurrentCultureIgnoreCase);
int trashLength = idx + "{/HOPS}".Length;
string postText = line.Substring(trashLength, line.Length - trashLength);
this._blocks.Last().InnerBlocks.Add(new TextBlock(newBlock.ToString(), BlockType.Hop, postText));
newBlock.Clear();
}
else
{
newBlock.AppendLine(line);
}
}
// If there is anything still in the read buffer add it as a new block.
if (newBlock.Length > 0)
{
this._blocks.Add(new TextBlock(newBlock.ToString()));
newBlock.Clear();
}
}
}
}
///
/// Read the associated template.
///
/// Template file path.
public void ReadTemplate(string TemplateFile)
{
this.ReadTemplate(new FileInfo(TemplateFile));
}
///
/// Read the associated template.
///
/// Template file.
public void ReadTemplate(FileInfo TemplateFile)
{
this._templateFile = TemplateFile;
this.ReadTemplate();
}
///
/// Write data structure to a stream.
///
/// Output stream.
/// Array of trace route replies.
public void ToStream(Stream OutputStream, TraceRoute[] Routes)
{
using (StreamWriter writer = new StreamWriter(OutputStream))
{
foreach (TextBlock block in this._blocks)
{
switch (block.Type)
{
case BlockType.Route:
foreach (TraceRoute route in Routes)
{
// Work with the copy dummy.
string line = block.Text;
int idx;
// Search for destination tokens.
while ((idx = line.IndexOf("{destination}", StringComparison.CurrentCultureIgnoreCase)) > -1)
{
line = line.Replace(line.Substring(idx, "{destination}".Length), route.Destination);
}
// Finally...
writer.Write(line);
writer.Flush();
// Loop through any inner blocks.
foreach (TextBlock innerBlock in block.InnerBlocks)
{
this.WriteHops(writer, innerBlock, route.Hops.ToArray());
}
if (!string.IsNullOrEmpty(block.PostText))
{
// Add the separator if it is not the last route.
if (route != Routes.Last())
{
line += block.PostText;
}
// Finally...
writer.Write(line);
writer.Flush();
}
}
break;
case BlockType.Hop:
// Stub.
break;
default:
// Nothing to see here.
writer.Write(block.Text);
writer.Flush();
break;
}
}
}
}
///
/// Write data structure to a specific file.
///
/// Target output file path.
/// Array of trace route replies.
/// A value indicating whether to append data on existing file contents.
public void Write(string TargetFile, TraceRoute[] Routes, bool Append = false)
{
this.Write(new FileInfo(TargetFile), Routes, Append);
}
///
/// Write data structure to a specific file.
///
/// Target output file.
/// Array of trace route replies.
/// A value indicating whether to append data on existing file contents.
public void Write(FileInfo TargetFile, TraceRoute[] Routes, bool Append = false)
{
this.ToStream(TargetFile.Open(Append ? FileMode.Append : FileMode.Create), Routes);
}
private void WriteHops(StreamWriter writer, TextBlock block, Hop[] hops)
{
foreach (Hop hop in hops)
{
// Work with the copy dummy.
string line = block.Text;
int idx;
// Search for address tokens.
while ((idx = line.IndexOf("{address}", StringComparison.CurrentCultureIgnoreCase)) > -1)
{
line = line.Replace(line.Substring(idx, "{address}".Length), hop.Address);
}
// Search for hop tokens.
while ((idx = line.IndexOf("{hop}", StringComparison.CurrentCultureIgnoreCase)) > -1)
{
line = line.Replace(line.Substring(idx, "{hop}".Length), hop.HopCount.ToString());
}
// Search for host name tokens.
while ((idx = line.IndexOf("{hostname}", StringComparison.CurrentCultureIgnoreCase)) > -1)
{
line = line.Replace(line.Substring(idx, "{hostname}".Length), hop.HostName);
}
// Search for round trip tokens.
while ((idx = line.IndexOf("{roundtrip}", StringComparison.CurrentCultureIgnoreCase)) > -1)
{
line = line.Replace(line.Substring(idx, "{roundtrip}".Length), hop.RoundTrip.ToString());
}
if (!string.IsNullOrEmpty(block.PostText))
{
// Add the separator if it is not the last route.
if (hop != hops.Last())
{
line += block.PostText;
}
}
// Finally...
writer.Write(line);
writer.Flush();
}
}
}
}