bool ImageSearchInfo::match( ImageInfoPtr info ) const
{
    if ( m_isNull )
        return true;

    if ( !m_compiled )
        compile();

    bool ok = true;
#ifdef HAVE_EXIV2
    ok = m_exifSearchInfo.matches( info->fileName() );
#endif

    QDateTime actualStart = info->date().start();
    QDateTime actualEnd = info->date().end();
    if ( actualEnd <= actualStart )  {
        QDateTime tmp = actualStart;
        actualStart = actualEnd;
        actualEnd = tmp;
    }

    if ( !m_date.start().isNull() ) {
        // Date
        // the search date matches the actual date if:
        // actual.start <= search.start <= actuel.end or
        // actual.start <= search.end <=actuel.end or
        // search.start <= actual.start and actual.end <= search.end

        bool b1 =( actualStart <= m_date.start() && m_date.start() <= actualEnd );
        bool b2 =( actualStart <= m_date.end() && m_date.end() <= actualEnd );
        bool b3 = ( m_date.start() <= actualStart && ( actualEnd <= m_date.end() || m_date.end().isNull() ) );

        ok = ok && ( ( b1 || b2 || b3 ) );
    } else if ( !m_date.end().isNull() ) {
        bool b1 = ( actualStart <= m_date.end() && m_date.end() <= actualEnd );
        bool b2 = ( actualEnd <= m_date.end() );
        ok = ok && ( ( b1 || b2 ) );
    }

    // -------------------------------------------------- Options
    // alreadyMatched map is used to make it possible to search for
    // Jesper & None
    QMap<QString, StringSet> alreadyMatched;
    for (CategoryMatcher* optionMatcher : m_categoryMatchers) {
        ok = ok && optionMatcher->eval(info, alreadyMatched);
    }


    // -------------------------------------------------- Label
    ok = ok && ( m_label.isEmpty() || info->label().indexOf(m_label) != -1 );

    // -------------------------------------------------- RAW
    ok = ok && ( m_searchRAW == false || ImageManager::RAWImageDecoder::isRAW( info->fileName()) );

    // -------------------------------------------------- Rating

    //ok = ok && (_rating == -1 ) || ( _rating == info->rating() );
    if (m_rating != -1) {
    switch( m_ratingSearchMode ) {
        case 1:
        // Image rating at least selected
        ok = ok && ( m_rating <= info->rating() );
        break;
        case 2:
        // Image rating less than selected
        ok = ok && ( m_rating >= info->rating() );
        break;
        case 3:
        // Image rating not equal
        ok = ok && ( m_rating != info->rating() );
        break;
        default:
            ok = ok && ((m_rating == -1 ) || ( m_rating == info->rating() ));
        break;
    }
    }


    // -------------------------------------------------- Resolution
    if ( m_megapixel )
        ok = ok && ( m_megapixel * 1000000 <= info->size().width() * info->size().height() );

    // -------------------------------------------------- Text
    QString txt = info->description();
    if ( !m_description.isEmpty() ) {
        QStringList list = m_description.split(QChar::fromLatin1(' '), QString::SkipEmptyParts);
        Q_FOREACH( const QString &word, list ) {
            ok = ok && ( txt.indexOf( word, 0, Qt::CaseInsensitive ) != -1 );
        }
    }