public void CompleteTagConstructor_QaaWithXDashBeforeValidLanguageName_NoChange()
		{
			var cleaner = new IetfLanguageTagCleaner("qaa-x-th");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("qaa-x-th"));
			Assert.That(cleaner.Language, Is.EqualTo("qaa"));
			Assert.That(cleaner.PrivateUse, Is.EqualTo("th"));
		}
		public void CompleteTagConstructor_InvalidLanguageNameWithScript_QaaAdded()
		{
			var cleaner = new IetfLanguageTagCleaner("wee-Latn");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("qaa-Latn-x-wee"));

			// Also when initially "Latn" is properly in the Script field.
			cleaner = new IetfLanguageTagCleaner("wee", "Latn", "", "", "");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("qaa-Latn-x-wee"));
		}
        ///<summary>
        /// Constructor.
        ///</summary>
        ///<param name="idsInFile"></param>
        ///<param name="replaceIdsInFile"></param>
        ///<param name="writingSystemRepository"></param>
        public static void FindOrphans(
			IEnumerable<string> idsInFile,
			IdReplacementStrategy replaceIdsInFile,
			IWritingSystemRepository writingSystemRepository)
        {
            List<string> originalIds = idsInFile.ToList();
            List<string> updatedIds = originalIds.ToList();
            foreach (string wsId in originalIds)
            {
                // Check if it's in the repo
                if (writingSystemRepository.Contains(wsId))
                {
                    continue;
                }
                string newId;
                if (writingSystemRepository.WritingSystemIdHasChanged(wsId))
                {
                    newId = writingSystemRepository.WritingSystemIdHasChangedTo(wsId);
                }
                else
                {
                    // It's an orphan
                    // Clean it
                    var rfcTagCleaner = new IetfLanguageTagCleaner(wsId);
                    rfcTagCleaner.Clean();
                    newId = rfcTagCleaner.GetCompleteTag();
                }

                WritingSystemDefinition conformantWritingSystem;
                writingSystemRepository.WritingSystemFactory.Create(newId, out conformantWritingSystem);
                // If it changed, then change
                if (conformantWritingSystem.LanguageTag != wsId)
                {
                    conformantWritingSystem.LanguageTag = IetfLanguageTag.ToUniqueLanguageTag(
                        conformantWritingSystem.LanguageTag, updatedIds);
                    replaceIdsInFile(wsId, conformantWritingSystem.LanguageTag);
                    updatedIds.Remove(wsId);
                    updatedIds.Add(conformantWritingSystem.LanguageTag);
                }

                // Check if it's in the repo
                if (writingSystemRepository.Contains(conformantWritingSystem.LanguageTag))
                    continue;

                // It's not in the repo so set it
                writingSystemRepository.Set(conformantWritingSystem);
            }
            writingSystemRepository.Save();
        }
		public void NewTag_IsNotModified()
		{
			var cleaner = new IetfLanguageTagCleaner("fr-Qaaa-QM-x-Mysc-YY");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "fr", "Qaaa", "QM", "", "fr-Qaaa-QM-x-Mysc-YY");
		}
		public void RegionCodesThatMatchLanguageCodesNotMovedToPrivateUse()
		{
			var cleaner = new IetfLanguageTagCleaner("rwr-IN");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "rwr", "", "IN", "", "rwr-IN");
		}
		public void ZhNoRegion_InsertsRegionCN()
		{
			var cleaner = new IetfLanguageTagCleaner("zh", "", "", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "zh", "", "CN", "", "zh-CN");
		}
		public void PrivateRegionMultiPartVariant_InsertsPrivateRegionCode()
		{
			var cleaner = new IetfLanguageTagCleaner("fr", "", "x-ZY", "fonipa-x-etic", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "fr", "", "QM", "fonipa", "fr-QM-fonipa-x-ZY-etic");
		}
		public void CompleteTagConstructor_XDashBeforeValidLanguageNameInVariant_NoChange()
		{
			var cleaner = new IetfLanguageTagCleaner("", "", "", "x-de", "");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("x-de"));
		}
		public void Language_XDashBeforeString_AddsQaa()
		{
			var cleaner = new IetfLanguageTagCleaner("x-blah");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("qaa-x-blah"));
		}
		public void CmnRegion_BecomesZh()
		{
			var cleaner = new IetfLanguageTagCleaner("cmn", "", "NO", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "zh", "", "NO", "", "zh-NO");
		}
		void VerifyRfcCleaner(IetfLanguageTagCleaner cleaner, string language, string script, string region, string variant, string completeTag)
		{
			Assert.That(cleaner.Language, Is.EqualTo(language));
			Assert.That(cleaner.Script, Is.EqualTo(script));
			Assert.That(cleaner.Region, Is.EqualTo(region));
			Assert.That(cleaner.Variant, Is.EqualTo(variant));
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo(completeTag));
		}
		public void ZhRegion_NoChange()
		{
			var cleaner = new IetfLanguageTagCleaner("zh", "", "NO", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "zh", "", "NO", "", "zh-NO");

			cleaner = new IetfLanguageTagCleaner("zh", "", "x-ZK", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "zh", "", "QM", "", "zh-QM-x-ZK");
		}
		public void LanguageSubtagContainsMultipleValidLanguageSubtagsAsWellAsDataThatIsNotValidLanguageScriptRegionOrVariant_AllSubtagsButFirstValidLanguageSubtagAreMovedToPrivateUse()
		{
			var cleaner = new IetfLanguageTagCleaner("bogus-en-audio-tpi-bogus2-x-", "", "", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "en", "Zxxx", "", "", "en-Zxxx-x-bogus-audio-bogus2-tpi");
		}
		public void Arb_BecomesAr()
		{
			var cleaner = new IetfLanguageTagCleaner("arb", "", "x-ZG", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "ar", "", "QM", "", "ar-QM-x-ZG");
		}
		public void Pes_BecomesFa()
		{
			var cleaner = new IetfLanguageTagCleaner("pes", "Latn", "", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "fa", "Latn", "", "", "fa-Latn");
		}
		public void CmnNoRegion_BecomesZhCN()
		{
			var cleaner = new IetfLanguageTagCleaner("cmn", "", "", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "zh", "", "CN", "", "zh-CN");
		}
		public void CleanMarksCustomScriptMovedToPrivateUse()
		{
			var cleaner = new IetfLanguageTagCleaner("en-Zyxw");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "en", "Qaaa", "", "", "en-Qaaa-x-Zyxw");
		}
		public void CompleteTagConstructor_LanguageNameWithAudio_GetZxxxAdded()
		{
			var cleaner = new IetfLanguageTagCleaner("aaa-x-audio");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("aaa-Zxxx-x-audio"));
		}
		public void ScriptEndingWithX_IsHandledCorrectly()
		{
			var cleaner = new IetfLanguageTagCleaner("zh-Phnx-CN-fonipa-x-emic");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "zh", "Phnx", "CN", "fonipa", "zh-Phnx-CN-fonipa-x-emic");
		}
		public void EmicWithoutFonipa_AddsFonipa()
		{
			var cleaner = new IetfLanguageTagCleaner("en", "", "", "x-emic", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "en", "", "", "fonipa", "en-fonipa-x-emic");
		}
		public void CompleteTagConstructor_HasLanguageNameAndOtherName_OtherNameMovedToPrivateUse()
		{
			var cleaner = new IetfLanguageTagCleaner("abc-123");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("abc-x-123"));
		}
		public void CompleteTagConstructor_TagContainsOnlyPrivateUseWithAdditionalXDash_RedundantXDashRemoved()
		{
			var cleaner = new IetfLanguageTagCleaner("x-some-x-whatever");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("qaa-x-some-whatever"));
		}
		public void ValidLanguageCodeMarkedPrivate_InsertsQaa()
		{
			var cleaner = new IetfLanguageTagCleaner("x-de", "", "", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "qaa", "", "", "", "qaa-x-de");
		}
		public void CompleteTagConstructor_PrivateUseWithAudioAndDuplicateX_MakesAudioTag()
		{
			var cleaner = new IetfLanguageTagCleaner("x-en-Zxxx-x-audio");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("qaa-Zxxx-x-en-Zxxx-audio"));
		}
		public void PrivateUseVariantLanguageCode_IsNotShortened()
		{
			var cleaner = new IetfLanguageTagCleaner("qaa", "", "", "", "x-kal");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "qaa", "", "", "", "qaa-x-kal");
		}
		public void MultiPartVariantWithoutX_InsertsX()
		{
			var cleaner = new IetfLanguageTagCleaner("fr", "", "", "fonipa-etic", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "fr", "", "", "fonipa", "fr-fonipa-x-etic");
		}
		public void CompleteTagConstructor_HasInvalidLanguageName_MovedToPrivateUse()
		{
			var cleaner = new IetfLanguageTagCleaner("234");
			cleaner.Clean();
			Assert.That(cleaner.GetCompleteTag(), Is.EqualTo("qaa-x-234"));
		}
		public void LanguageCodeAfterX_IsNotShortened()
		{
			var cleaner = new IetfLanguageTagCleaner("qaa-x-kal");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "qaa", "", "", "", "qaa-x-kal");
		}
		public void NewTagWithPrivateLanguage_IsNotModified()
		{
			var cleaner = new IetfLanguageTagCleaner("qaa-Qaaa-QM-x-kal-Mysc-YY");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "qaa", "Qaaa", "QM", "", "qaa-Qaaa-QM-x-kal-Mysc-YY");
		}
		public void PrivateRegionKnownLanguageAndScript_InsertsPrivateRegionCode()
		{
			var cleaner = new IetfLanguageTagCleaner("fr", "Latn", "x-ZY", "", "");
			cleaner.Clean();
			VerifyRfcCleaner(cleaner, "fr", "Latn", "QM", "", "fr-Latn-QM-x-ZY");
		}