public static void Show(Clickable clickableOrigin, NotifyInformation notifyInformation)
 {
     if (IsNeededToShowThisPopUp(notifyInformation))
     {
         ShowThisObject();
         LoadNotifyInformation(notifyInformation);
         HideOptionsThatAreNull(notifyInformation);
         ShowOptionsThatAreShowable(notifyInformation);
         UpdateLocationToMousePosition();
         UpdateCollider();
         Draw();
         MakeChildAnimation(Animate.FadeIn);
     }
 }
 private static void ShowOptionsThatAreShowable(NotifyInformation notifyInformation)
 {
     if (!IsNeededToHideExaminate(notifyInformation))
     {
         ShowExaminate();
     }
     if (!IsNeededToHideLook(notifyInformation))
     {
         ShowLook();
     }
     if (!IsNeededToHideWand(notifyInformation))
     {
         ShowWand();
     }
 }
 private static void HideOptionsThatAreNull(NotifyInformation notifyInformation)
 {
     if (IsNeededToHideExaminate(notifyInformation))
     {
         HideExaminate();
     }
     if (IsNeededToHideLook(notifyInformation))
     {
         HideLook();
     }
     if (IsNeededToHideWand(notifyInformation))
     {
         HideWand();
     }
 }
 private static bool IsNeededToShowThisPopUp(NotifyInformation notifyInformation)
 {
     return(notifyInformation.isClickable);
 }
 private static void LoadNotifyInformation(NotifyInformation notifyInformation)
 {
     singleton.lastObjectNotifyInformation = notifyInformation;
 }
 private static bool IsNeededToHideExaminate(NotifyInformation notifyInformation)
 {
     return(notifyInformation.textOnExaminateClick.Equals(string.Empty));
 }
 private static bool IsNeededToHideWand(NotifyInformation notifyInformation)
 {
     return(notifyInformation.textOnWandClick.Equals(string.Empty));
 }
        /// <summary>
        /// セクションを探す前に初期化を行い、別スレッドでセクションを探すように設定します。
        /// 
        /// セクションを探している間に新しいポストを受け付けると、
        /// 規制通知のための情報がおかしくなるので、ここでIsFindingフラグをtrueにセットし、
        /// セクションを探している間は新しいポストをバッファに貯めるようにしています。
        /// 
        /// セクションを探し終えたら、セクションを探している最中に受信したポストをすべて処理します。
        /// </summary>
        private void StartFindSection(Action<AggregateException> callback)
        {
            NotifyInfo = new NotifyInformation();
            NotifyInfo.PostInSection = new Dictionary<long, PostClass>();
            NotifyInfo.PostInFinding = new List<PostClass>();
            NotifyInfo.IsFinding = true;
            NotifyInfo.IsNoticed = false;
            NotifyInfo.IsAccuracy = false;

            var notifyInfo = NotifyInfo;

            var t = Task.Factory.StartNew(
                () =>
                    {
                        FindSection(notifyInfo);
                    });

            // セクションを探し中に例外が発生した場合は、Stopメソッドを呼び出して規制通知を停止します。
            // 再度規制通知の開始を試みるかは使用者に委ねられます。
            t.ContinueWith(
                (task) =>
                {
                    Stop();
                    Utility.DelegateUtility.CallAction<AggregateException>(callback, task.Exception);
                    Utility.DelegateUtility.CallEvent<Event.AggregateExceptionEventArgs>
                        (FindingError, this, new Event.AggregateExceptionEventArgs(task.Exception));
                }, TaskContinuationOptions.OnlyOnFaulted);
            t.ContinueWith(
                (task) =>
                {
                    Utility.DelegateUtility.CallAction<AggregateException>(callback, task.Exception);
                    Utility.DelegateUtility.CallEvent(FindingCompleted, this, new EventArgs());
                }, TaskContinuationOptions.NotOnFaulted);
            t.ContinueWith(
                (task) =>
                {
                    lock (notifyInfo)
                    {
                        notifyInfo.IsFinding = false;
                    }
                    foreach (var post in notifyInfo.PostInFinding)
                    {
                        CheckPost(post, notifyInfo);
                    }
                    notifyInfo.PostInFinding.Clear();
                }, TaskContinuationOptions.NotOnFaulted);
        }
        /// <summary>
        /// セクションを探します。
        /// 
        /// セクションは3時間以上発言していない区間からみて最初のポストから始まります。
        /// 次のセクションは、そこから3時間経過後の最初のポストから始まります。
        /// これを現在時刻まで繰り返して現在のセクションを探します。
        /// この方法で求められたセクションは正確です。
        /// IsAccuracyフラグがtrueにセットされます。
        /// 
        /// セクションが見つからない場合は、現在の実装では、126番目のポストをセクションの最初のポストとみなしています。
        /// これは適当な実装です。がある程度きっちりした実装にしても不正確になるでしょう。
        /// そのためIsAccuracyフラグをfalseにセットし、不正確であることを周知します。
        /// 次のセクションからは前述した動作で探します。
        /// </summary>
        private void FindSection(NotifyInformation notifyInfo)
        {
            DateTime now = DateTime.Now;

            IList<PostClass> postList = null;
            postList = Twitter.GetUserTimelinePostClassApi(FINDING_GET_COUNT, 0);

            var postCreatedDescQuery =
                from post in postList
                orderby post.PostedOrRetweetedAt descending
                select post;

            bool foundNoPostSection = false;
            PostClass nextPost = null;
            foreach (var post in postCreatedDescQuery)
            {
                if (nextPost == null)
                {
                    if (now > post.PostedOrRetweetedAt.AddHours(SECTION_HOUR))
                    {
                        foundNoPostSection = true;
                        notifyInfo.LastSectionEndTime = post.PostedOrRetweetedAt.AddHours(SECTION_HOUR);
                        notifyInfo.IsAccuracy = true;
                        break;
                    }
                }
                else
                {
                    if (nextPost.PostedOrRetweetedAt > post.PostedOrRetweetedAt.AddHours(SECTION_HOUR))
                    {
                        foundNoPostSection = true;
                        notifyInfo.LastSectionEndTime = post.PostedOrRetweetedAt.AddHours(SECTION_HOUR);
                        notifyInfo.SectionStartPost = nextPost;
                        notifyInfo.IsAccuracy = true;
                        break;
                    }
                }
                nextPost = post;
            }

            if (!foundNoPostSection)
            {
                var postCreatedDescArray = postCreatedDescQuery.ToArray();

                if (postCreatedDescArray.Count() == 0)
                {
                    notifyInfo.LastSectionEndTime = now;
                    notifyInfo.IsAccuracy = true;
                }
                else if (postCreatedDescArray.Count() <= FINDING_GET_COUNT - 1)
                {
                    int firstPostIndex = postCreatedDescArray.Count() - 1;
                    notifyInfo.LastSectionEndTime = postCreatedDescArray[firstPostIndex].PostedOrRetweetedAt.AddSeconds(-1);
                    notifyInfo.SectionStartPost = postCreatedDescArray[firstPostIndex];
                    notifyInfo.IsAccuracy = true;
                }
                else
                {
                    notifyInfo.LastSectionEndTime = postCreatedDescArray[126].PostedOrRetweetedAt.AddSeconds(-1);
                    notifyInfo.SectionStartPost = postCreatedDescArray[126];
                    notifyInfo.IsAccuracy = false;
                }
            }

            if (notifyInfo.SectionStartPost != null)
            {
                while (
                    notifyInfo.SectionStartPost != null &&
                    now > notifyInfo.SectionStartPost.PostedOrRetweetedAt.AddHours(SECTION_HOUR))
                {
                    notifyInfo.LastSectionEndTime = notifyInfo.SectionStartPost.PostedOrRetweetedAt.AddHours(SECTION_HOUR);
                    notifyInfo.SectionStartPost =
                        (from post in postList
                         where post.PostedOrRetweetedAt >= notifyInfo.LastSectionEndTime
                         orderby post.PostedOrRetweetedAt
                         select post).FirstOrDefault();
                }

                var postInSectionQuery =
                    from post in postList
                    where post.PostedOrRetweetedAt >= notifyInfo.SectionStartPost.PostedOrRetweetedAt
                    select post;

                notifyInfo.PostInSection.Clear();
                if (notifyInfo.SectionStartPost != null)
                {
                    foreach (var post in postInSectionQuery)
                    {
                        if (!notifyInfo.PostInSection.ContainsKey(post.StatusId))
                        {
                            notifyInfo.PostInSection[post.StatusId] = post;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// PostClassをチェックします。
        /// 
        /// FindSectionで求められたセクション情報から、現在のセクションのポスト数を求め、
        /// 通知ポスト数NotifyCountに達したときに規制通知を行います。
        /// </summary>
        /// <param name="post">チェックするPostClass</param>
        private void CheckPost(PostClass post, NotifyInformation notifyInfo)
        {
            if (post.IsDm)
            {
                return;
            }
            if (!String.IsNullOrEmpty(post.RetweetedBy) && !Twitter.IsCurrentUser(post.RetweetedBy) ||
                String.IsNullOrEmpty(post.RetweetedBy) && !Twitter.IsCurrentUser(post.ScreenName))
            {
                return;
            }

            lock (notifyInfo)
            {
                if (notifyInfo.LastSectionEndTime > post.PostedOrRetweetedAt)
                {
                    return;
                }

                if (!notifyInfo.PostInSection.ContainsKey(post.StatusId))
                {
                    notifyInfo.PostInSection[post.StatusId] = post;
                }

                if (notifyInfo.SectionStartPost == null ||
                    notifyInfo.SectionStartPost.PostedOrRetweetedAt > post.PostedOrRetweetedAt)
                {
                    notifyInfo.SectionStartPost = post;
                }

                if (post.PostedOrRetweetedAt > notifyInfo.SectionStartPost.PostedOrRetweetedAt.AddHours(SECTION_HOUR))
                {
                    notifyInfo.LastSectionEndTime = notifyInfo.SectionStartPost.PostedOrRetweetedAt.AddHours(SECTION_HOUR);
                    notifyInfo.SectionStartPost = post;

                    var outOfSectionArray =
                        (from postPair in notifyInfo.PostInSection
                         where postPair.Value.PostedOrRetweetedAt < notifyInfo.LastSectionEndTime
                         orderby postPair.Value.PostedOrRetweetedAt
                         select postPair).ToArray();

                    foreach (var outPost in outOfSectionArray)
                    {
                        notifyInfo.PostInSection.Remove(outPost);
                    }

                    notifyInfo.IsNoticed = false;
                }
                else
                {
                    if (notifyInfo.PostInSection.Count >= NotifyCount)
                    {
                        if (!notifyInfo.IsNoticed)
                        {
                            notifyInfo.IsNoticed = true;

                            DateTime limitReleaseDate = notifyInfo.SectionStartPost.PostedOrRetweetedAt.AddHours(SECTION_HOUR);
                            string limitReleaseDateString = limitReleaseDate.ToString(LimitReleaseDateFormat);
                            string notAccuracyMessage = "";
                            if (!notifyInfo.IsAccuracy)
                            {
                                notAccuracyMessage = NotAccuracyMessage;
                            }
                            int countInSection = notifyInfo.PostInSection.Count();

                            var t = Task.Factory.StartNew(
                                () =>
                                {
                                    Twitter.PostStatus(
                                        String.Format(NotificationMessage,
                                        countInSection, limitReleaseDateString, notAccuracyMessage),
                                        0);
                                });
                            t.ContinueWith(
                                (task) =>
                                {
                                    Utility.DelegateUtility.CallEvent<Event.AggregateExceptionEventArgs>(
                                        NotifyError, this, new Event.AggregateExceptionEventArgs(task.Exception));
                                }, TaskContinuationOptions.OnlyOnFaulted);
                        }
                    }
                }
            }
        }