/// <summary>
        /// Convert phoneset to the mapped phoneset, using delegate mapPhone, if the parameter
        /// Delimiters is not null, mapped phones string will be splitted to several phones
        /// And added to the new phone set.
        /// </summary>
        /// <param name="phoneQuestion">Phone set to be converted.</param>
        /// <param name="mapPhone">Map old phone to new phone delegate.</param>
        /// <returns>Mapped phoneset.</returns>
        public static PhoneQuestion Convert(PhoneQuestion phoneQuestion, MapPhone mapPhone)
        {
            PhoneQuestion question = new PhoneQuestion(phoneQuestion.Name);

            foreach (string phone in phoneQuestion.Phones)
            {
                string[] mappedPhones = mapPhone(phone);

                if (mappedPhones == null || mappedPhones.Length <= 0 ||
                    string.IsNullOrEmpty(mappedPhones[0]))
                {
                    string message = Helper.NeutralFormat("Can't find phone [{0}]'s " +
                        "mapped phone in phoneset [{1}]", phone, phoneQuestion.Name);
                    continue;
                }

                foreach (string mappedPhone in mappedPhones)
                {
                    question.Phones.Add(mappedPhone);
                }
            }

            return question;
        }
        /// <summary>
        /// Build phoneset with the specified question item string.
        /// </summary>
        /// <param name="name">Phoneset name.</param>
        /// <param name="questions">String contained question items, the items should be separated by delimiters.</param>
        /// <param name="itemPattern">QuestionItem regex pattern, the first group of the pattern should be phone.</param>
        /// <param name="delimiters">Question item delimiters.</param>
        /// <returns>Parsed phone set.</returns>
        private static PhoneQuestion BuildPhoneQuestion(string name, string questions, string itemPattern, char[] delimiters)
        {
            PhoneQuestion question = new PhoneQuestion(name);

            string[] items = questions.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < items.Length; i++)
            {
                string item = items[i].Trim();
                Match matchItem = Regex.Match(item, itemPattern);

                if (!matchItem.Success)
                {
                    throw new InvalidDataException(Helper.NeutralFormat("Invalid question item [{0}] in question [{1}].", item, question.Name));
                }

                if (matchItem.Groups.Count < 2)
                {
                    throw new InvalidDataException(Helper.NeutralFormat("Invalid question item regex [{0}].", itemPattern.ToString()));
                }

                string phone = matchItem.Groups[1].Value;
                if (!question.Contains(phone))
                {
                    question.Phones.Add(phone);
                }
            }

            return question;
        }
        /// <summary>
        /// Get missing phone set: each phone should contain one question for it self.
        /// </summary>
        /// <param name="phoneQuestions">Phone questions to be checked.</param>
        /// <param name="phones">Phone set to be checked.</param>
        /// <returns>Missed phoneset.</returns>
        public static PhoneQuestion[] GetMissingPhoneSet(IEnumerable<PhoneQuestion> phoneQuestions, Collection<string> phones)
        {
            const string MissingQuestionNameSuffix = "_AutoGen_";
            Dictionary<string, bool> phoneExistDictionary = new Dictionary<string, bool>();

            foreach (string phone in phones)
            {
                phoneExistDictionary.Add(phone, false);
            }

            foreach (PhoneQuestion set in phoneQuestions)
            {
                // Check the questions with only one phone
                if (set.Phones.Count != 1)
                {
                    continue;
                }

                if (phoneExistDictionary.ContainsKey(set.Phones[0]))
                {
                    phoneExistDictionary[set.Phones[0]] = true;
                }                
            }

            List<PhoneQuestion> missedPhonesets = new List<PhoneQuestion>();

            foreach (string phone in phoneExistDictionary.Keys)
            {
                if (!phoneExistDictionary[phone])
                {
                    PhoneQuestion phoneset = new PhoneQuestion(MissingQuestionNameSuffix + phone);
                    phoneset.Phones.Add(phone); 
                    missedPhonesets.Add(phoneset);
                }
            }

            return missedPhonesets.ToArray();
        }