private async Task ProcessChatMessageAsync(Chat.IChatMessage message)
        {
            switch (message)
            {
            case Chat.ChatMessage chat:
            {
                if (_isFirstConnection == false && _isInitialCommentsReceiving == true)
                {
                    //再接続時は初期コメントを無視する
                    return;
                }
                var  userId = chat.UserId;
                var  user   = GetUser(userId);
                bool isFirstComment;
                if (_userCommentCountDict.ContainsKey(userId))
                {
                    _userCommentCountDict[userId]++;
                    isFirstComment = false;
                }
                else
                {
                    _userCommentCountDict.AddOrUpdate(userId, 1, (s, n) => n);
                    isFirstComment = true;
                }
                //var comment = await Tools.CreateNicoComment(chat, user, _siteOptions, roomName, async userid => await API.GetUserInfo(_dataSource, userid), _logger);
                INicoMessage         comment;
                INicoMessageMetadata metadata;
                if (IsAd(chat))
                {
                    ///nicoad {"totalAdPoint":215500,"message":"シュガーさんが1700ptニコニ広告しました","version":"1"}
                    var     adJson = chat.Content.Replace("/nicoad", "");
                    dynamic d      = JsonConvert.DeserializeObject(adJson);
                    if ((string)d.version != "1")
                    {
                        throw new ParseException(chat.Raw);
                    }
                    var content = (string)d.message;
                    var ad      = new NicoAd(chat.Raw)
                    {
                        PostedAt = Common.UnixTimeConverter.FromUnixTime(chat.Date),
                        UserId   = userId,
                        Text     = content,
                    };
                    comment  = ad;
                    metadata = new AdMessageMetadata(ad, _options, _siteOptions)
                    {
                        IsInitialComment = _isInitialCommentsReceiving,
                        SiteContextGuid  = SiteContextGuid,
                    };
                }
                else if (IsGift(chat))
                {
                    var match = Regex.Match(chat.Content, "/gift (\\S+) (\\d+|NULL) \"(\\S+)\" (\\d+) \"(\\S*)\" \"(\\S+)\"(?: (\\d+))?");
                    if (!match.Success)
                    {
                        throw new ParseException(chat.Raw);
                    }
                    var giftId    = match.Groups[1].Value;
                    var userIdp   = match.Groups[2].Value;      //ギフトを投げた人。userId == "900000000"
                    var username  = match.Groups[3].Value;
                    var point     = match.Groups[4].Value;
                    var what      = match.Groups[5].Value;
                    var itemName  = match.Groups[6].Value;
                    var itemCount = match.Groups[7].Value;        //アイテムの個数?ギフト貢献n位?
                    var text      = $"{username}さんがギフト「{itemName}({point}pt)」を贈りました";
                    var gift      = new NicoGift(chat.Raw)
                    {
                        Text      = text,
                        PostedAt  = Common.UnixTimeConverter.FromUnixTime(chat.Date),
                        UserId    = userIdp == "NULL" ? "" : userIdp,
                        NameItems = Common.MessagePartFactory.CreateMessageItems(username),
                    };
                    comment  = gift;
                    metadata = new ItemMessageMetadata(gift, _options, _siteOptions)
                    {
                        IsInitialComment = _isInitialCommentsReceiving,
                        SiteContextGuid  = SiteContextGuid,
                    };
                }
                else if (IsSpi(chat))
                {
                    var spi = new NicoSpi(chat.Raw)
                    {
                        Text     = chat.Content,
                        PostedAt = Common.UnixTimeConverter.FromUnixTime(chat.Date),
                        UserId   = chat.UserId,
                    };
                    comment  = spi;
                    metadata = new SpiMessageMetadata(spi, _options, _siteOptions)
                    {
                        IsInitialComment = _isInitialCommentsReceiving,
                        SiteContextGuid  = SiteContextGuid,
                    };
                }
                else if (IsEmotion(chat))
                {
                    var content = chat.Content.Substring("/emotion ".Length);
                    var abc     = new NicoEmotion("")
                    {
                        ChatNo    = chat.No,
                        Anonymity = chat.Anonymity,
                        PostedAt  = Common.UnixTimeConverter.FromUnixTime(chat.Date),
                        Content   = content,
                        UserId    = chat.UserId,
                    };
                    comment  = abc;
                    metadata = new EmotionMessageMetadata(abc, _options, _siteOptions, user, this)
                    {
                        IsInitialComment = _isInitialCommentsReceiving,
                        SiteContextGuid  = SiteContextGuid,
                    };
                }
                else if (IsInfo(chat))
                {
                    var match = Regex.Match(chat.Content, "^/info (?<no>\\d+) (?<content>.+)$", RegexOptions.Singleline);
                    if (!match.Success)
                    {
                        throw new ParseException(chat.Raw);
                    }
                    else
                    {
                        var no      = int.Parse(match.Groups["no"].Value);
                        var content = match.Groups["content"].Value;
                        var info    = new NicoInfo(chat.Raw)
                        {
                            Text     = content,
                            PostedAt = Common.UnixTimeConverter.FromUnixTime(chat.Date),
                            UserId   = chat.UserId,
                            No       = no,
                        };
                        comment  = info;
                        metadata = new InfoMessageMetadata(info, _options, _siteOptions)
                        {
                            IsInitialComment = _isInitialCommentsReceiving,
                            SiteContextGuid  = SiteContextGuid,
                        };
                    }
                }
                else
                {
                    if (IsDisconnect(chat))        //NicoCommentではなく専用のクラスを作っても良いかも。
                    {
                        _chatProvider?.Disconnect();
                    }
                    string username;
                    if (IsRawUserId(chat.UserId) && chat.UserId != SystemUserId && _siteOptions.IsAutoGetUsername)
                    {
                        var userInfo = await Api.GetUserInfo(_server, _cc, chat.UserId);

                        username  = userInfo.Nickname;
                        user.Name = Common.MessagePartFactory.CreateMessageItems(username);
                    }
                    else
                    {
                        username = null;
                    }
                    if (_siteOptions.IsAutoSetNickname)
                    {
                        var nick = SitePluginCommon.Utils.ExtractNickname(chat.Content);
                        if (!string.IsNullOrEmpty(nick))
                        {
                            user.Nickname = nick;
                        }
                    }
                    var abc = new NicoComment("")
                    {
                        ChatNo   = chat.No,
                        Id       = chat.No.ToString(),
                        Is184    = chat.Anonymity == 1,
                        PostedAt = Common.UnixTimeConverter.FromUnixTime(chat.Date),
                        Text     = chat.Content,
                        UserId   = chat.UserId,
                        UserName = username,
                    };
                    comment  = abc;
                    metadata = new CommentMessageMetadata(abc, _options, _siteOptions, user, this, isFirstComment)
                    {
                        IsInitialComment = _isInitialCommentsReceiving,
                        SiteContextGuid  = SiteContextGuid,
                    };
                }


                var context = new NicoMessageContext(comment, metadata, new NicoMessageMethods());
                RaiseMessageReceived(context);
            }
            break;

            case Chat.Ping ping:
                if (ping.Content == "rs:0")
                {
                    _isInitialCommentsReceiving = true;
                }
                else if (ping.Content == "rf:0")
                {
                    _isInitialCommentsReceiving = false;
                }
                break;

            case Chat.UnknownMessage unknown:
                _logger.LogException(new ParseException(unknown.Raw));
                break;

            default:
                break;
            }
        }