reactos/irc/TechBot/TechBot.Commands.MSDN/ApiCommand.cs
Marc Piulachs a46601a21c - miscellaneous small fixes
- add support for preventing all commands to be run on the channel by default. Now TechBot only answers some of the commands in PM
- add back the error Command

svn path=/trunk/; revision=34079
2008-06-25 13:23:59 +00:00

310 lines
8.4 KiB
C#

using System;
using System.IO;
using System.Data;
using System.Text.RegularExpressions;
using HtmlHelp;
using HtmlHelp.ChmDecoding;
using TechBot.Library;
namespace TechBot.Commands.MSDN
{
[Command("api", Help = "!api <apiname>")]
public class ApiCommand : Command
{
private bool IsVerbose = false;
private HtmlHelpSystem chm;
public ApiCommand()
{
LoadCHM();
}
[CommandParameter("api", "The API name")]
public string API
{
get { return Parameters; }
set { Parameters = value; }
}
private void WriteIfVerbose(string message)
{
if (IsVerbose)
Say(message);
}
private void LoadCHM()
{
string CHMFilename = Path.Combine(Settings.Default.ChmPath, Settings.Default.MainChm);
chm = new HtmlHelpSystem();
chm.OpenFile(CHMFilename, null);
Console.WriteLine(String.Format("Loaded main CHM: {0}",
Path.GetFileName(CHMFilename)));
foreach (string filename in Directory.GetFiles(Settings.Default.ChmPath))
{
if (!Path.GetExtension(filename).ToLower().Equals(".chm"))
continue;
if (Path.GetFileName(filename).ToLower().Equals(Settings.Default.MainChm))
continue;
Console.WriteLine(String.Format("Loading CHM: {0}",
Path.GetFileName(filename)));
try
{
chm.MergeFile(filename);
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Could not load CHM: {0}. Exception {1}",
Path.GetFileName(filename),
ex));
}
}
Console.WriteLine(String.Format("Loaded {0} CHMs",
chm.FileList.Length));
}
public override void ExecuteCommand()
{
if (Name.Trim().Equals(String.Empty))
{
Say("Please give me a keyword.");
}
else
{
Search(Name);
}
}
private bool SearchIndex(
string keyword)
{
if (chm.HasIndex)
{
IndexItem item = chm.Index.SearchIndex(keyword,
IndexType.KeywordLinks);
if (item != null && item.Topics.Count > 0)
{
WriteIfVerbose(String.Format("Keyword {0} found in index",
item.KeyWord));
IndexTopic indexTopic = item.Topics[0] as IndexTopic;
return DisplayResult( keyword,
indexTopic);
}
else
{
WriteIfVerbose(String.Format("Keyword {0} not found in index",
keyword));
return false;
}
}
else
return false;
}
private void SearchFullText(string keyword)
{
string sort = "Rating ASC";
WriteIfVerbose(String.Format("Searching fulltext database for {0}",
keyword));
bool partialMatches = false;
bool titlesOnly = true;
int maxResults = 100;
DataTable results = chm.PerformSearch(keyword,
maxResults,
partialMatches,
titlesOnly);
WriteIfVerbose(String.Format("results.Rows.Count = {0}",
results != null ?
results.Rows.Count.ToString() : "(none)"));
if (results != null && results.Rows.Count > 0)
{
results.DefaultView.Sort = sort;
if (!DisplayResult(keyword,
results))
{
Say("No result");
}
}
else
{
Say("No result");
}
}
private void Search(string keyword)
{
if (!SearchIndex(keyword))
SearchFullText(keyword);
}
private bool DisplayResult(string keyword,
IndexTopic indexTopic)
{
keyword = keyword.Trim().ToLower();
string url = indexTopic.URL;
WriteIfVerbose(String.Format("URL from index search {0}",
url));
string prototype = ExtractPrototype(url);
if (prototype == null || prototype.Trim().Equals(String.Empty))
return false;
string formattedPrototype = FormatPrototype(prototype);
Say(formattedPrototype);
return true;
}
private bool DisplayResult(string keyword,
DataTable results)
{
keyword = keyword.Trim().ToLower();
for (int i = 0; i < results.DefaultView.Count; i++)
{
DataRowView row = results.DefaultView[i];
string title = row["Title"].ToString();
WriteIfVerbose(String.Format("Examining {0}", title));
if (title.Trim().ToLower().Equals(keyword))
{
string location = row["Location"].ToString();
string rating = row["Rating"].ToString();
string url = row["Url"].ToString();
string prototype = ExtractPrototype(url);
if (prototype == null || prototype.Trim().Equals(String.Empty))
continue;
string formattedPrototype = FormatPrototype(prototype);
Say(formattedPrototype);
return true;
}
}
return false;
}
private void DisplayNoResult(MessageContext context,
string keyword)
{
TechBot.ServiceOutput.WriteLine(context,
String.Format("I don't know about keyword {0}",
keyword));
}
private string ReplaceComments(string s)
{
return Regex.Replace(s, "//(.+)\r\n", "");
}
private string ReplaceLineEndings(string s)
{
return Regex.Replace(s, "(\r\n)+", " ");
}
private string ReplaceSpaces(string s)
{
return Regex.Replace(s, @" +", " ");
}
private string ReplaceSpacesBeforeLeftParenthesis(string s)
{
return Regex.Replace(s, @"\( ", @"(");
}
private string ReplaceSpacesBeforeRightParenthesis(string s)
{
return Regex.Replace(s, @" \)", @")");
}
private string ReplaceSemicolon(string s)
{
return Regex.Replace(s, @";", @"");
}
private string FormatPrototype(string prototype)
{
string s = ReplaceComments(prototype);
s = ReplaceLineEndings(s);
s = ReplaceSpaces(s);
s = ReplaceSpacesBeforeLeftParenthesis(s);
s = ReplaceSpacesBeforeRightParenthesis(s);
s = ReplaceSemicolon(s);
return s;
}
private string ExtractPrototype(string url)
{
string page = GetPage(url);
Match match = Regex.Match(page,
"<PRE class=\"?syntax\"?>(.+)</PRE>",
RegexOptions.Multiline |
RegexOptions.Singleline);
if (match.Groups.Count > 1)
{
string prototype = match.Groups[1].ToString();
return StripHtml(StripAfterSlashPre(prototype));
}
return "";
}
private string StripAfterSlashPre(string html)
{
int index = html.IndexOf("</PRE>");
if (index != -1)
{
return html.Substring(0, index);
}
else
return html;
}
private string StripHtml(string html)
{
return Regex.Replace(html, @"<(.|\n)*?>", String.Empty);
}
private string GetPage(string url)
{
string CHMFileName = "";
string topicName = "";
string anchor = "";
CHMStream.CHMStream baseStream;
if (!chm.BaseStream.GetCHMParts(url, ref CHMFileName, ref topicName, ref anchor))
{
baseStream = chm.BaseStream;
CHMFileName = baseStream.CHMFileName;
topicName = url;
anchor = "";
}
else
{
baseStream = GetBaseStreamFromCHMFileName(CHMFileName);
}
if ((topicName == "") || (CHMFileName == "") || (baseStream == null))
{
return "";
}
return baseStream.ExtractTextFile(topicName);
}
private CHMStream.CHMStream GetBaseStreamFromCHMFileName(string CHMFileName)
{
foreach (CHMFile file in chm.FileList)
{
WriteIfVerbose(String.Format("Compare: {0} <> {1}",
file.ChmFilePath,
CHMFileName));
if (file.ChmFilePath.ToLower().Equals(CHMFileName.ToLower()))
{
return file.BaseStream;
}
}
WriteIfVerbose(String.Format("Could not find loaded CHM file in list: {0}",
CHMFileName));
return null;
}
}
}