/// <summary>
        /// correct the attendance mistake caused by system problem
        /// </summary>
        static void AttendanceCorrection(List <AttendanceInfo> attendanceList)
        {
            // correct system fault
            foreach (var nextInfo in attendanceList)
            {
                if (CorrectSystemFault(nextInfo, new DateTime(2017, 8, 31), AttendanceState.None, AttendanceState.Normal))
                {
                    continue;
                }
                if (CorrectSystemFault(nextInfo, new DateTime(2017, 12, 28), AttendanceState.None, AttendanceState.Normal))
                {
                    continue;
                }
                if (CorrectSystemFault(nextInfo, new DateTime(2017, 12, 29), AttendanceState.None, AttendanceState.Normal))
                {
                    continue;
                }

                // leave 3 days before spring festival
                if (CorrectSystemFault(nextInfo, new DateTime(2018, 2, 12), AttendanceState.Absent, AttendanceState.Leave))
                {
                    continue;
                }
                if (CorrectSystemFault(nextInfo, new DateTime(2018, 2, 13), AttendanceState.Absent, AttendanceState.Leave))
                {
                    continue;
                }
                if (CorrectSystemFault(nextInfo, new DateTime(2018, 2, 14), AttendanceState.Absent, AttendanceState.Leave))
                {
                    continue;
                }
            } // foreach (var nextInfo in attendanceList)

            //
            // befor or later than enter and leave date
            // always put this rule in the last
            //
            #region // befor or later than enter and leave date
            foreach (var nextInfo in attendanceList)
            {
                DateTime onboardDate   = DateTime.MaxValue;
                DateTime dimissionDate = DateTime.MinValue;

                PersonInfo personInfo = PersonInfoRepo.GetPersonInfo(nextInfo.Name);
                if (personInfo == null)
                {
                    //MessageBox.Show(nextInfo.Name + " 没有台账信息!");
                    Trace.WriteLine("cannot find " + nextInfo.Name);
                    continue;
                }

                // onboard date
                try
                {
                    if (!ONBOARD_FORMAT_EXCEPTION.ContainsKey(personInfo.Name))
                    {
                        onboardDate = Convert.ToDateTime(personInfo.OnboardDate);
                    }
                }
                catch (FormatException)
                {
                    Trace.WriteLine("error onboard date format: " + personInfo.OnboardDate);
                    onboardDate = DateTime.MaxValue;
                    ONBOARD_FORMAT_EXCEPTION[personInfo.Name] = personInfo;
                }
                catch (Exception exp)
                {
                    MessageBox.Show(exp.Message);
                    return;
                }

                // leave date
                try
                {
                    if (string.IsNullOrWhiteSpace(personInfo.DimissionDate))
                    {
                        dimissionDate = DateTime.MaxValue; // not dismissed
                    }
                    else if (!DISMISSION_FORMAT_EXCEPTION.ContainsKey(personInfo.Name))
                    {
                        dimissionDate = Convert.ToDateTime(personInfo.DimissionDate);
                    }
                }
                catch (FormatException)
                {
                    Trace.WriteLine("error dismission date format: " + personInfo.DimissionDate);
                    dimissionDate = DateTime.MinValue;
                    DISMISSION_FORMAT_EXCEPTION[personInfo.Name] = personInfo;
                }
                catch (Exception exp)
                {
                    MessageBox.Show(exp.Message);
                    return;
                }

                if ((nextInfo.Date < onboardDate) && (nextInfo.State != AttendanceState.PaidLeave))
                //&& ((nextInfo.State == AttendanceState.Normal) || (nextInfo.State == AttendanceState.Late)))
                {
                    nextInfo.State = AttendanceState.NotOnboard;
                }

                if ((nextInfo.Date > dimissionDate) && (nextInfo.State != AttendanceState.PaidLeave))
                //&& ((nextInfo.State == AttendanceState.Normal) || (nextInfo.State == AttendanceState.Late)))
                {
                    nextInfo.State = AttendanceState.Dimission;
                }
            } // foreach (var nextInfo in attendanceList)
            #endregion // befor or later than enter and leave date
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="info"></param>
        /// <param name="faultDate"></param>
        /// <returns>
        /// false - did not do anything
        /// true - correct successfully
        /// </returns>
        static bool CorrectSystemFault(AttendanceInfo info, DateTime faultDate, AttendanceState errorState, AttendanceState correctState)
        {
            if (!info.Date.Equals(faultDate))
            {
                return(false);
            }

            PersonInfo personInfo = PersonInfoRepo.GetPersonInfo(info.Name);

            if (personInfo == null)
            {
                //MessageBox.Show(nextInfo.Name + " 没有台账信息!");
                Trace.WriteLine("cannot find " + info.Name);
                return(false);
            }

            // check dismission date
            DateTime dimissionDate = DateTime.MaxValue;

            try
            {
                if (!string.IsNullOrWhiteSpace(personInfo.DimissionDate) &&
                    !DISMISSION_FORMAT_EXCEPTION.ContainsKey(personInfo.Name))
                {
                    dimissionDate = Convert.ToDateTime(personInfo.DimissionDate);
                }
            }
            catch (FormatException)
            {
                Trace.WriteLine("error dismission date format: " + personInfo.DimissionDate);
                dimissionDate = DateTime.MinValue;
                DISMISSION_FORMAT_EXCEPTION[personInfo.Name] = personInfo;
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
                return(false);
            }
            if (dimissionDate < faultDate)
            {
                return(false); // skip the leave early case
            }

            // check onboard date
            DateTime onboardDate = DateTime.MinValue;

            try
            {
                if (!string.IsNullOrWhiteSpace(personInfo.OnboardDate) &&
                    !ONBOARD_FORMAT_EXCEPTION.ContainsKey(personInfo.Name))
                {
                    onboardDate = Convert.ToDateTime(personInfo.OnboardDate);
                }
            }
            catch (FormatException)
            {
                Trace.WriteLine("error onboard date format: " + personInfo.OnboardDate);
                onboardDate = DateTime.MaxValue;
                ONBOARD_FORMAT_EXCEPTION[personInfo.Name] = personInfo;
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
                return(false);
            }
            if (onboardDate > faultDate)
            {
                return(false); // skip the onboard later case
            }

            // correct the status
            if (errorState == AttendanceState.None)
            {
                info.State = correctState; // for all the case
            }
            else if (info.State == errorState)
            {
                info.State = correctState; // for specific case
            }

            return(true);
        }
        public static void FilteroutDissmissedPerson(List <AttendanceInfo> infoList)
        {
            // sort by date to get the first and last day
            infoList.Sort((info1, info2) => info1.Date.CompareTo(info2.Date));
            DateTime firstStatisticDay = infoList.First <AttendanceInfo>().Date;
            DateTime lastStatisticDay  = infoList.Last <AttendanceInfo>().Date;

            // get dissmissed person set
            HashSet <string> dissmissedPersonSet = new HashSet <string>();

            foreach (var nextInfo in infoList)
            {
                if (!string.IsNullOrEmpty(nextInfo.Name) && !dissmissedPersonSet.Contains(nextInfo.Name))
                {
                    dissmissedPersonSet.Add(nextInfo.Name);
                }
            }
            foreach (var nextPerson in dissmissedPersonSet.ToList())
            {
                PersonInfo personInfo = PersonInfoRepo.GetPersonInfo(nextPerson);
                if (personInfo == null)
                {
                    MessageBox.Show(string.Format("警告:没有找到台账信息 [{0}] ", nextPerson));
                    continue;
                }

                // check dismission date
                DateTime dimissionDate = DateTime.MaxValue;
                try
                {
                    if (!string.IsNullOrWhiteSpace(personInfo.DimissionDate))
                    {
                        dimissionDate = Convert.ToDateTime(personInfo.DimissionDate);
                    }
                }
                catch (Exception)
                {
                    Trace.WriteLine("error dismission date format: " + personInfo.DimissionDate);
                    dimissionDate = DateTime.MinValue;
                }
                if (firstStatisticDay <= dimissionDate)
                {
                    dissmissedPersonSet.Remove(nextPerson);
                }
                else
                {
                    Trace.WriteLine("dismissed person: " + nextPerson);
                }
            } // foreach (var nextPerson in dissmissedPersonSet.ToList())

            // remove the dissmissed records
            List <AttendanceInfo> removedInfoList = new List <AttendanceInfo>();

            foreach (var nextInfo in infoList)
            {
                if (dissmissedPersonSet.Contains(nextInfo.Name))
                {
                    removedInfoList.Add(nextInfo);
                }
            }
            foreach (var nextInfo in removedInfoList)
            {
                infoList.Remove(nextInfo);
            }

            // sort
            infoList.Sort((info1, info2) =>
            {
                if (!info1.Name.Equals(info2.Name))
                {
                    return(info1.Name.CompareTo(info2.Name));
                }

                return(info1.Date.CompareTo(info2.Date));
            });
        }