private function parseWithMode($raw_taf, $strict)
    {
        // prepare decoding inputs/outputs: (trim, remove linefeeds and returns, no more than one space)
        $clean_taf = trim($raw_taf);
        $clean_taf = preg_replace("#\n+#", ' ', $clean_taf);
        $clean_taf = preg_replace("#\r+#", ' ', $clean_taf);
        $clean_taf = preg_replace('#[ ]{2,}#', ' ', $clean_taf) . ' ';
        $clean_taf = strtoupper($clean_taf);
        if (strpos($clean_taf, 'CNL') === false) {
            // appending END to it is necessary to detect the last line of evolution
            // but only when the TAF wasn't cancelled (CNL)
            $remaining_taf = trim($clean_taf) . ' END';
        } else {
            $remaining_taf = $clean_taf;
        }
        $decoded_taf = new DecodedTaf($clean_taf);
        $with_cavok = false;

        // call each decoder in the chain and use results to populate decoded taf
        foreach ($this->decoder_chain as $chunk_decoder) {
            try {
                // try to parse a chunk with current chunk decoder
                $decoded = $chunk_decoder->parse($remaining_taf, $with_cavok);

                // map obtained fields (if any) to the final decoded object
                $result = $decoded['result'];
                if ($result != null) {
                    foreach ($result as $key => $value) {
                        if ($value !== null) {
                            $setter_name = 'set'.ucfirst($key);
                            $decoded_taf->$setter_name($value);
                        }
                    }
                }

                // update remaining taf for next round
                $remaining_taf = $decoded['remaining_taf'];
            } catch (ChunkDecoderException $cde) {
                // log error in decoded taf and abort decoding if in strict mode
                $decoded_taf->addDecodingException($cde);
                // abort decoding if strict mode is activated, continue otherwise
                if ($strict) {
                    break;
                }
                // update remaining taf for next round
                $remaining_taf = $cde->getRemainingTaf();
            }

             // hook for CAVOK decoder, keep CAVOK information in memory
            if ($chunk_decoder instanceof VisibilityChunkDecoder) {
                $with_cavok = $decoded_taf->getCavok();
            }
        }

        // weather evolutions
        $evolutionDecoder = new EvolutionChunkDecoder($strict, $with_cavok);
        while ($remaining_taf != null && trim($remaining_taf) != 'END') {
            $evolutionDecoder->parse($remaining_taf, $decoded_taf);
            $remaining_taf = $evolutionDecoder->getRemaining();
        }

        return $decoded_taf;
    }