using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Misuzilla.Net.Irc;
namespace Misuzilla.Applications.TwitterIrcGateway
{
///
/// Groupをチャンネル名で格納します。
///
public class Groups : SortedList
{
public Groups()
: base(StringComparer.InvariantCultureIgnoreCase)
{
}
private static Object _syncObject = new object();
private static XmlSerializer _serializer = null;
static Groups()
{
lock (_syncObject)
{
if (_serializer == null)
{
_serializer = new XmlSerializer(typeof(Group[]));
}
}
}
private static XmlSerializer Serializer
{
get
{
return _serializer;
}
}
public void Serialize(Stream stream)
{
Group[] groups = new Group[this.Values.Count];
this.Values.CopyTo(groups, 0);
using (XmlTextWriter xmlTextWriter = new XmlTextWriter(stream, Encoding.UTF8))
{
_serializer.Serialize(xmlTextWriter, groups);
}
}
public static Groups Deserialize(Stream stream)
{
Group[] groups = _serializer.Deserialize(stream) as Group[];
Groups retGroups = new Groups();
foreach (Group group in groups)
{
retGroups[group.Name] = group;
//group.IsJoined = false;
group.ChannelModes = group.ChannelModes == null ? new List() : group.ChannelModes;
}
return retGroups;
}
///
///
///
///
///
public static Groups Load(String path)
{
// group 読み取り
if (File.Exists(path))
{
TraceLogger.Server.Information(String.Format("Load Group: {0}", path));
try
{
using (FileStream fs = new FileStream(path, FileMode.Open))
{
try
{
Groups groups = Groups.Deserialize(fs);
if (groups != null)
return groups;
}
catch (XmlException xe) { TraceLogger.Server.Information(xe.Message); }
catch (InvalidOperationException ioe) { TraceLogger.Server.Information(ioe.Message); }
}
}
catch (IOException ie)
{
TraceLogger.Server.Information(ie.Message);
throw;
}
}
return new Groups();
}
///
///
///
///
public void Save(String path)
{
TraceLogger.Server.Information(String.Format("Save Group: {0}", path));
try
{
String dir = Path.GetDirectoryName(path);
Directory.CreateDirectory(dir);
using (FileStream fs = new FileStream(path, FileMode.Create))
{
try
{
this.Serialize(fs);
}
catch (XmlException xe) { TraceLogger.Server.Information(xe.Message); }
catch (InvalidOperationException ioe) { TraceLogger.Server.Information(ioe.Message); }
}
}
catch (IOException ie)
{
TraceLogger.Server.Information(ie.Message);
throw;
}
}
}
///
/// IRC上でチャンネルとして表現されるメッセージ送信対象のグループを表します。
///
public class Group : IComparable
{
///
/// チャンネル名を取得・設定します
///
public String Name { get; set; }
public String Mode { get; set; }
///
/// グループに属するユーザのリストを取得します
///
public List Members { get; set; }
///
/// JOINしているかどうかを取得・設定します
///
public Boolean IsJoined { get; set; }
///
/// 特別扱いされるチャンネルかどうかを取得・設定します。
/// 特別扱いされている場合、タイムラインステータスは送信されなくなります。
///
public Boolean IsSpecial { get; set; }
///
/// チャンネルのトピックを取得・設定します
///
public String Topic { get; set; }
///
/// チャンネルのモードを取得・設定します
///
public List ChannelModes { get; set; }
///
/// グループのインスタンスを初期化します。
///
public Group()
{
ChannelModes = new List();
}
///
/// グループを複製します。
///
///
public Group Clone()
{
Group g = new Group()
{
Name = this.Name,
ChannelModes = this.ChannelModes,
IsJoined = this.IsJoined,
IsSpecial = this.IsSpecial,
Members = new List(this.Members),
Mode = this.Mode,
Topic = this.Topic
};
return g;
}
///
/// 指定した名前でグループのインスタンスを初期化します。
///
/// #で始まるチャンネル名
public Group(String name)
{
if (!name.StartsWith("#") || name.Length < 2)
{
throw new ArgumentException("チャンネル名は#で始まる必要があります。");
}
Name = name;
Members = new List();
ChannelModes = new List();
}
///
/// 指定したユーザがグループのメンバかどうかを取得します。
///
/// ユーザのID
/// グループのメンバに属しているかどうかを表すBoolean値。
public Boolean Exists(String id)
{
Int32 pos;
lock (Members)
{
pos = Members.BinarySearch(id, StringComparer.InvariantCultureIgnoreCase);
}
return pos > -1;
}
///
/// グループのメンバに属するユーザを追加します。
///
/// ユーザのID
public void Add(String id)
{
lock (Members)
{
Members.Add(id);
Members.Sort(StringComparer.InvariantCultureIgnoreCase);
}
}
///
/// 指定したユーザをグループのメンバから削除します。
///
/// ユーザのID
public void Remove(String id)
{
lock (Members)
{
Members.Remove(id);
Members.Sort(StringComparer.InvariantCultureIgnoreCase);
}
}
///
/// グループに送信されたメッセージのエコーバックを無視するかどうかを取得します。
///
public Boolean IgnoreEchoBack
{
get
{
return ChannelModes.Exists(mode => mode.Mode == ChannelModeTypes.Private);
}
}
///
/// グループのトピックを利用したマッチがメンバとOR条件になっているかどうかを取得します。
///
public Boolean IsOrMatch
{
get
{
return String.IsNullOrEmpty(Topic) ? false : Topic.StartsWith("|");
}
}
///
/// TwitterIrcGatewayがトピックなどを考慮してメッセージ送信先として選択できるかどうかを取得します。
///
public Boolean IsRoutable
{
get { return !(IsSpecial || ChannelModes.Exists(mode => mode.Mode == ChannelModeTypes.InviteOnly)); }
}
public override string ToString()
{
return String.Format("Group: {0} ({1} members)", Name, Members.Count);
}
#region IComparable メンバ
public int CompareTo(object obj)
{
if (!(obj is Group))
return -1;
return String.Compare((obj as Group).Name, this.Name, true, CultureInfo.InvariantCulture);
}
#endregion
}
///
/// 送信先を決定した後を表すクラス
///
public class RoutedGroup : IComparable
{
///
/// 決定対象となったグループを取得します
///
public Group Group { get; set; }
///
/// 自分自身が送信したメッセージかどうかを取得します
///
public Boolean IsMessageFromSelf { get; set; }
///
/// チャンネルにユーザが存在しているか、0人のチャンネルだったのかを取得します
///
public Boolean IsExistsInChannelOrNoMembers { get; set; }
///
/// このチャンネルに送信されるIRCのメッセージの種類を取得または設定します
///
public String IRCMessageType { get; set; }
///
/// このチャンネルに送信されるテキストを取得または設定します
///
public String Text { get; set; }
public RoutedGroup()
{
IRCMessageType = "PRIVMSG";
}
#region IComparable メンバ
public int CompareTo(object obj)
{
if (!(obj is RoutedGroup))
return -1;
return String.Compare((obj as RoutedGroup).Group.Name, this.Group.Name, true, CultureInfo.InvariantCulture);
}
#endregion
}
}