/// <summary> /// Decode a full taf string into a complete taf object. /// </summary> /// <param name="rawTaf"></param> /// <returns></returns> public static DecodedTaf ParseWithMode(string rawTaf, bool isStrict = false) { // prepare decoding inputs/outputs: (trim, remove linefeeds and returns, no more than one space) var cleanTaf = rawTaf.Trim(); cleanTaf = Regex.Replace(cleanTaf, "\n+", string.Empty); cleanTaf = Regex.Replace(cleanTaf, "\r+", string.Empty); cleanTaf = Regex.Replace(cleanTaf, "[ ]{2,}", " ") + " "; cleanTaf = cleanTaf.ToUpper(); var remainingTaf = cleanTaf; if (!cleanTaf.Contains("CNL")) { // appending END to it is necessary to detect the last line of evolution // but only when the TAF wasn't cancelled (CNL) remainingTaf = cleanTaf.Trim() + " END"; } else { remainingTaf = cleanTaf; } var decodedTaf = new DecodedTaf(cleanTaf); var withCavok = false; // call each decoder in the chain and use results to populate decoded taf foreach (var chunkDecoder in _decoderChain) { try { // try to parse a chunk with current chunk decoder var decodedData = chunkDecoder.Parse(remainingTaf, withCavok); // map obtained fields (if any) to the final decoded object if (decodedData.ContainsKey(ResultKey) && decodedData[ResultKey] is Dictionary <string, object> ) { var result = decodedData[ResultKey] as Dictionary <string, object>; foreach (var obj in result) { if (obj.Value != null) { typeof(DecodedTaf).GetProperty(obj.Key).SetValue(decodedTaf, obj.Value); } } } // update remaining taf for next round remainingTaf = decodedData[RemainingTafKey] as string; } catch (TafChunkDecoderException tafChunkDecoderException) { // log error in decoded taf and abort decoding if in strict mode decodedTaf.AddDecodingException(tafChunkDecoderException); // abort decoding if strict mode is activated, continue otherwise if (isStrict) { break; } // update remaining taf for next round remainingTaf = tafChunkDecoderException.RemainingTaf; } // hook for CAVOK decoder, keep CAVOK information in memory if (chunkDecoder is VisibilityChunkDecoder) { withCavok = decodedTaf.Cavok; } } // weather evolutions var evolutionDecoder = new EvolutionChunkDecoder(isStrict, withCavok); while (!string.IsNullOrEmpty(remainingTaf) && remainingTaf.Trim() != "END") { evolutionDecoder.Parse(remainingTaf, decodedTaf); remainingTaf = evolutionDecoder.Remaining; } return(decodedTaf); }