//----------------------------------------------------------------------------//
RenderedString BasicRenderedStringParser::parse(const String& input_string,
                                                const Font* active_font,
                                                const ColourRect* active_colours)
{
    // first-time initialisation (due to issues with static creation order)
    if (!d_initialised)
        initialiseTagHandlers();

    initialiseDefaultState();

    // Override active font if necessary
    if (active_font)
        d_fontName = active_font->getName();

    // Override active font if necessary
    if (active_colours)
        d_colours = *active_colours;

    RenderedString rs;
    String curr_section, tag_string;

    for (String::const_iterator input_iter(input_string.begin());
         input_iter != input_string.end();
         /* no-op*/)
    {
        const bool found_tag = parse_section(input_iter, input_string.end(), '[', curr_section);
        appendRenderedText(rs, curr_section);

        if (!found_tag)
            return rs;

        if (!parse_section(input_iter, input_string.end(), ']', tag_string))
        {
            Logger::getSingleton().logEvent(
                "BasicRenderedStringParser::parse: Ignoring unterminated tag : [" +
                tag_string);

            return rs;
        }

        processControlString(rs, tag_string);
    }

    return rs;
}
//----------------------------------------------------------------------------//
RenderedString BasicRenderedStringParser::parse(const String& input_string,
                                                Font* initial_font,
                                                const ColourRect* initial_colours)
{
    // first-time initialisation (due to issues with static creation order)
    if (!d_initialised)
        initialiseTagHandlers();

    initialiseDefaultState();

    // maybe override initial font.
    if (initial_font)
        d_fontName = initial_font->getName();

    // maybe override initial colours.
    if (initial_colours)
        d_colours = *initial_colours;

    RenderedString rs;
    String curr_section;

    size_t curr_pos = 0;

    while (curr_pos < input_string.length())
    {
        size_t cstart_pos = input_string.find_first_of('[', curr_pos);

        // if no control sequence start char, add remaining text verbatim.
        if (String::npos == cstart_pos)
        {
            curr_section += input_string.substr(curr_pos);
            curr_pos = input_string.length();
        }
        else if (cstart_pos == curr_pos || input_string[cstart_pos - 1] != '\\')
        {
            // append everything up to the control start to curr_section.
            curr_section += input_string.substr(curr_pos, cstart_pos - curr_pos);

            // scan forward for end of control sequence
            size_t cend_pos = input_string.find_first_of(']', cstart_pos);
            // if not found, treat as plain text
            if (String::npos == cend_pos)
            {
                curr_section += input_string.substr(curr_pos);
                curr_pos = input_string.length();
            }
            // extract control string
            else
            {
                appendRenderedText(rs, curr_section);
                curr_section.clear();

                String ctrl_string(
                    input_string.substr(cstart_pos + 1,
                                        cend_pos - cstart_pos - 1));
                curr_pos = cend_pos + 1;

                processControlString(rs, ctrl_string);
                continue;
            }
        }
        else
        {
            curr_section += input_string.substr(curr_pos,
                                                cstart_pos - curr_pos - 1);
            curr_section += '[';
            curr_pos = cstart_pos + 1;
            continue;
        }

        appendRenderedText(rs, curr_section);
        curr_section.clear();
    }

    return rs;
}