private bool _snapToUnselectedEdges(ref DateTime dt, TimeSpan snapSpan)
        {
            bool snapped = false;

            UnsetState(TRB_PART.START | TRB_PART.END, TRB_STATE.SNAPPED_TO);

            DateTime myDT_0                = dt - ptrAdjTS_0;
            DateTime myDT_1                = dt - ptrAdjTS_1;
            TimeSpan closeSpan             = TimeSpan.MaxValue;
            TimeBox  trbClose              = null;
            TRB_PART closePart             = TRB_PART.NONE;
            TRB_PART movingPartThatSnapped = TRB_PART.NONE;

            foreach (var proj in EachVisibleProject())
            {
                if (!proj.Visible)
                {
                    continue;
                }
                ;
                foreach (var trb in proj.TimeBoxCollection)
                {
                    if (trb.HasState(TRB_PART.WHOLE, TRB_STATE.NOT | TRB_STATE.SELECTED))
                    {
                        TimeSpan tmpSpan;

                        if (movingPart.HasFlag(TRB_PART.START))
                        {
                            tmpSpan = (trb.StartDate - myDT_0).Duration();
                            if (tmpSpan < closeSpan)
                            {
                                trbClose              = trb;
                                closeSpan             = tmpSpan;
                                closePart             = TRB_PART.START;
                                movingPartThatSnapped = TRB_PART.START;
                            }

                            tmpSpan = (trb.EndDate - myDT_0).Duration();
                            if (tmpSpan < closeSpan)
                            {
                                trbClose              = trb;
                                closeSpan             = tmpSpan;
                                closePart             = TRB_PART.END;
                                movingPartThatSnapped = TRB_PART.START;
                            }
                        }

                        if (movingPart.HasFlag(TRB_PART.END))
                        {
                            tmpSpan = (trb.StartDate - myDT_1).Duration();
                            if (tmpSpan < closeSpan)
                            {
                                trbClose              = trb;
                                closeSpan             = tmpSpan;
                                closePart             = TRB_PART.START;
                                movingPartThatSnapped = TRB_PART.END;
                            }

                            tmpSpan = (trb.EndDate - myDT_1).Duration();
                            if (tmpSpan < closeSpan)
                            {
                                trbClose              = trb;
                                closeSpan             = tmpSpan;
                                closePart             = TRB_PART.END;
                                movingPartThatSnapped = TRB_PART.END;
                            }
                        }
                    }
                }
            }

            if (trbClose != null && closeSpan <= snapSpan)
            {
                snapped = true;
                dt      = (DateTime)trbClose.GetDateTime(closePart);
                dt      = dt + (movingPartThatSnapped == TRB_PART.START ? ptrAdjTS_0 : ptrAdjTS_1);
                trbClose.SetState(closePart, TRB_STATE.SNAPPED_TO);
            }

            return(snapped);
        }
        public void MoveSelectedEdges(TimeBox trbClicked, TRB_PART partMov, DateTime dt, TimeSpan snapSpan,
                                      TRB_ACTION action)
        {
            // rules..
            // don't move other edges ???
            if (action == TRB_ACTION.BEGIN)
            {
                startDT = dt;

                ptrAdjTS_0 = dt - (DateTime)trbClicked.GetDateTime(TRB_PART.START);
                ptrAdjTS_1 = dt - (DateTime)trbClicked.GetDateTime(TRB_PART.END);

                // 1 unset all edges
                UnsetState(TRB_PART.START | TRB_PART.END, TRB_STATE.SELECTED);
                // 2 set edges accordingly
                SetState(partMov, TRB_PART.WHOLE, TRB_STATE.SELECTED);

                // 3. what edge are we moving, start or end?
                movingPart = partMov;

                TimeBox adj;
                spanL = TimeSpan.MinValue;
                spanR = TimeSpan.MaxValue;

                if (movingPart.HasFlag(TRB_PART.START))
                {
                    // left move
                    // 4. Get the minimum distance to the previous end
                    foreach (var proj in EachVisibleProject())
                    {
                        if (!proj.Visible)
                        {
                            continue;
                        }
                        foreach (var trb in proj.TimeBoxCollection)
                        {
                            if (trb.HasState(movingPart, TRB_STATE.SELECTED))
                            {
                                trb.StoreDates();
                                adj = _getAdj(trb, -1);
                                if (adj != null)
                                {
                                    spanL = _max(spanL, adj.EndDate - trb.StartDate);
                                }
                                if (!movingPart.HasFlag(TRB_PART.END))
                                {
                                    spanR = _min(spanR, trb.EndDate - trb.StartDate);
                                }
                            }
                        }
                    }
                }

                if (movingPart.HasFlag(TRB_PART.END))
                {
                    // right move
                    // 5. Get the MAximuim distance to the next start
                    foreach (var proj in EachVisibleProject())
                    {
                        if (!proj.Visible)
                        {
                            continue;
                        }
                        foreach (var trb in proj.TimeBoxCollection)
                        {
                            if (trb.HasState(movingPart, TRB_STATE.SELECTED))
                            {
                                trb.StoreDates();
                                adj = _getAdj(trb, +1);
                                if (adj != null)
                                {
                                    spanR = _min(spanR, adj.StartDate - trb.EndDate);
                                }
                                if (!movingPart.HasFlag(TRB_PART.START))
                                {
                                    spanL = _max(spanL, trb.StartDate - trb.EndDate);
                                }
                            }
                        }
                    }
                }
            }

            bool snapped = false;

            if (snapSpan.TotalMinutes > 0)
            {
                // snap the active edge only
                snapped = _snapToUnselectedEdges(ref dt, snapSpan);
            }

            TimeSpan spanDT = dt - startDT;

            if (spanDT < spanL)
            {
                spanDT = spanL;
            }
            if (spanDT > spanR)
            {
                spanDT = spanR;
            }

            foreach (var proj in EachVisibleProject())
            {
                if (!proj.Visible)
                {
                    continue;
                }
                foreach (var trb in proj.TimeBoxCollection)
                {
                    if (trb.HasState(movingPart, TRB_STATE.SELECTED))
                    {
                        trb.ShiftDateTime(movingPart, spanDT);
                    }
                }
            }

            if (snapped)
            {
                SetState(TRB_PART.END, TRB_PART.END, TRB_STATE.SELECTED, TRB_STATE.SNAPPED);
            }
            else
            {
                UnsetState(TRB_PART.END, TRB_PART.END, TRB_STATE.SELECTED, TRB_STATE.SNAPPED);
            }


            // finally snap the unsnapped to others nearest day
            if (action == TRB_ACTION.FINISH)
            {
                // condition: Selected but not snapped
                TimeBoxProcess(delegate(TimeBox trb)
                {
                    if (trb.HasState(movingPart, TRB_STATE.SELECTED) &&
                        trb.HasState(movingPart, TRB_STATE.SNAPPED | TRB_STATE.NOT))
                    {
                        // snap to whole day
                        var myDT   = (DateTime)trb.GetDateTime(movingPart);
                        var snapDT = FileChangeTable.Round(myDT, new TimeSpan(1, 0, 0, 0));

                        var thisSpan = snapDT - trb.GetStoredDateTime(movingPart);
                        if (thisSpan < spanL)
                        {
                            thisSpan = spanL;
                        }
                        if (thisSpan > spanR)
                        {
                            thisSpan = spanR;
                        }
                        trb.ShiftDateTime(movingPart, (TimeSpan)thisSpan);
                    }
                });

                foreach (var proj in EachVisibleProject())
                {
                    if (!proj.Visible)
                    {
                        continue;
                    }
                    if (proj.HasState(TRB_PART.WHOLE, TRB_STATE.SELECTED))
                    {
                        proj.TimeBoxSort();
                        proj.TimeBoxMerge();
                    }
                }

                ActivityTraceBuilder.Buildv2(this);
                movingPart = TRB_PART.NONE;
            }
        }