public function parse($echo = false) {
        if ($this->_parsed) {
            if ($echo) {
                echo $this->_parsed;
            }

            return $this->_parsed;
        }

        // Check the cache first
        $isCached = false;
        $cacheKey = $this->getCacheKey();
        $storage = $this->getStorage();

        if ($cacheKey && $storage) {
            try {
                $this->_parsed = $storage->get($cacheKey);
                $isCached = true;
            } catch (MissingItemException $e) {}
        }

        // Does not exist in the cache, parse it
        if (!$isCached) {
            $this->_triggerHook('startup');

            $string = $this->_triggerHook('beforeParse', $this->_string);

            if ($this->_isParseable($string)) {
                $string = $this->_parse($this->_extractChunks($string));

            } else {
                $string = $this->_triggerHook('beforeContent', $string);
                $string = $this->convertLineBreaks($string);
                $string = $this->_triggerHook('afterContent', $string);
            }

            $string = $this->_triggerHook('afterParse', $string);

            $this->_parsed = $this->cleanNewlines($string);

            // Cache the value
            if ($cacheKey && $storage) {
                $storage->set($cacheKey, $this->_parsed, strtotime($this->getConfig('cacheExpires')));
            }
        }

        if ($echo) {
            echo $this->_parsed;
        }

        return $this->_parsed;
    }