/*
 * Find all the fonts that are in the document but not available on the users system
 * and have been substituted for other fonts
 *
 * Return a list of SPItems where fonts have been substituted.
 *
 * Walk thru all the objects ...
 * a. Build up a list of the objects with fonts defined in the style attribute
 * b. Build up a list of the objects rendered fonts - taken for the objects layout/spans
 * If there are fonts in a. that are not in b. then those fonts have been substituted.
 */
GSList * FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring *out)
{
    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
    GSList *allList = NULL;
    GSList *outList = NULL;
    std::set<Glib::ustring> setErrors;
    std::set<Glib::ustring> setFontSpans;
    std::map<SPItem *, Glib::ustring> mapFontStyles;

    allList = get_all_items(NULL, doc->getRoot(), desktop, false, false, true, NULL);

    for (GSList *i = allList; i != NULL; i = i->next) {

        SPItem *item = SP_ITEM(i->data);
        SPStyle *style = item->style;
        Glib::ustring family = "";

        if (is_top_level_text_object (item)) {
            // Should only need to check the first span, since the others should be covered by TSPAN's etc
            family = te_get_layout(item)->getFontFamily(0);
            setFontSpans.insert(family);
        }
        else if (SP_IS_TEXTPATH(item)) {
            SPTextPath const *textpath = SP_TEXTPATH(item);
            if (textpath->originalPath != NULL) {
                family = SP_TEXT(item->parent)->layout.getFontFamily(0);
                setFontSpans.insert(family);
            }
        }
        else if (SP_IS_TSPAN(item) || SP_IS_FLOWTSPAN(item)) {
            // is_part_of_text_subtree (item)
             // TSPAN layout comes from the parent->layout->_spans
             SPObject *parent_text = item;
             while (parent_text && !SP_IS_TEXT(parent_text)) {
                 parent_text = parent_text->parent;
             }
             if (parent_text != NULL) {
                 family = SP_TEXT(parent_text)->layout.getFontFamily(0);
                 // Add all the spans fonts to the set
                 gint ii = 0;
                 for (SPObject *child = parent_text->firstChild() ; child ; child = child->getNext() ) {
                     family = SP_TEXT(parent_text)->layout.getFontFamily(ii);
                     setFontSpans.insert(family);
                     ii++;
                 }
             }
        }

        if (style) {
            gchar const *style_font = NULL;
            if (style->font_family.set)
                style_font = style->font_family.value;
            else if (style->font_specification.set)
                style_font = style->font_specification.value;
            else if (style->font_family.value)
                style_font = style->font_family.value;
            else if (style->font_specification.value)
                style_font = style->font_specification.value;

            if (style_font) {
                if (has_visible_text(item)) {
                    mapFontStyles.insert(std::make_pair (item, style_font));
                }
            }
        }
    }

    // Check if any document styles are not in the actual layout
    std::map<SPItem *, Glib::ustring>::const_iterator mapIter;
    for (mapIter = mapFontStyles.begin(); mapIter != mapFontStyles.end(); ++mapIter) {
        SPItem *item = mapIter->first;
        Glib::ustring fonts = mapIter->second;

        // CSS font fallbacks can have more that one font listed, split the font list
        std::vector<Glib::ustring> vFonts = Glib::Regex::split_simple("," , fonts);
        bool fontFound = false;
        for(size_t i=0; i<vFonts.size(); i++) {
            Glib::ustring font = vFonts[i];
            // trim whitespace
            size_t startpos = font.find_first_not_of(" \n\r\t");
            size_t endpos = font.find_last_not_of(" \n\r\t");
            if(( std::string::npos == startpos ) || ( std::string::npos == endpos)) {
                continue; // empty font name
            }
            font = font.substr( startpos, endpos-startpos+1 );
            std::set<Glib::ustring>::const_iterator iter = setFontSpans.find(font);
            if (iter != setFontSpans.end() ||
                    font == Glib::ustring("sans-serif") ||
                    font == Glib::ustring("Sans") ||
                    font == Glib::ustring("serif") ||
                    font == Glib::ustring("Serif") ||
                    font == Glib::ustring("monospace") ||
                    font == Glib::ustring("Monospace")) {
                fontFound = true;
                break;
            }
        }
        if (fontFound == false) {
            Glib::ustring subName = getSubstituteFontName(fonts);
            Glib::ustring err = Glib::ustring::compose(
                    _("Font '%1' substituted with '%2'"), fonts.c_str(), subName.c_str());
            setErrors.insert(err);
            outList = g_slist_prepend (outList, item);
        }
    }

    std::set<Glib::ustring>::const_iterator setIter;
    for (setIter = setErrors.begin(); setIter != setErrors.end(); ++setIter) {
        Glib::ustring err = (*setIter);
        out->append(err + "\n");
        g_warning("%s", err.c_str());
    }

    return outList;
}