
#include "buglistjob.h"
#include "bug.h"
#include "bugimpl.h"
#include "packageimpl.h"
#include "nodefilter.h"

#include <dom/dom_element.h>
#include <dom/html_inline.h>
#include <dom/dom_text.h>

#include <assert.h>
#include <kdebug.h>

BugListJob::BugListJob()
{
}

BugListJob::~BugListJob()
{
}

void BugListJob::start( const Package &pkg )
{
    m_package = pkg;

    QString packageUrl = "http://bugs.kde.org/db/pa/l" + pkg.name() + ".html";

    HTMLBugJob::start( KURL( packageUrl ) );
}

void BugListJob::process()
{
    m_bugs.clear();

    QStringList tags;
    tags << "h2" << "li";
    processFiltered( tags );

    emit bugListAvailable( m_package, m_bugs );
}


void BugListJob::processNode( const DOM::Node &n )
{
    DOM::Element e = n;
    if ( e.tagName() == "h2" )
        parseSeverity( e );

    DOM::HTMLAnchorElement anchor = e.firstChild();
    if ( anchor.isNull() )
        return;

    KURL bugUrl( m_url, anchor.href().string() );

    DOM::Text bugHeaderTextElement = anchor.firstChild();
    QString bugHeader = bugHeaderTextElement.data().string();

    int colonPos = bugHeader.find( ':' );
    if ( colonPos <= 0 )
        return;

    QString bugNr = bugHeader.mid( 1, colonPos - 1 );
    QString title = bugHeader.mid( colonPos + 2 );

    QString submitter;
    uint age = 0;

    DOM::Node node = anchor.nextSibling();
    for (; !node.isNull(); node = node.nextSibling() )
    {
        DOM::Text txtElement = node;
        if ( txtElement.isNull() )
        {
            e = node;
            if ( e.tagName() == "EM" ||
                    e.tagName() == "STRONG" )
                parseAge( DOM::Text( e.firstChild() ).data().string(), age );
            continue;
        }

        QString txt = txtElement.data().string();
        int reportedByPos = txt.find( "Reported by: " );
        if ( reportedByPos != -1 )
        {
            int submitterStartPos = reportedByPos + 13;

            int endPos = txt.find( ';', reportedByPos );
            if ( endPos == -1 )
            {
                endPos = txt.findRev( '.' );
                if ( endPos == -1 || endPos < submitterStartPos )
                    endPos = submitterStartPos - 1;
            }

            submitter = txt.mid( submitterStartPos, endPos - submitterStartPos );
        }

        int daysOldPos = txt.find( "days old" );
        if ( daysOldPos != -1 )
            parseAge( txt, age );
    }

    Person p = Person::parseFromString( submitter );

    BugImpl *impl = new BugImpl( title, p, bugNr, age, m_currentSeverity, m_currentStatus );
    m_bugs.append( Bug( impl ) );
    //kdDebug() << "Bug " << bugNr << ":" << title << endl;
}

void BugListJob::parseSeverity( const DOM::Element &e )
{
    DOM::Text textElement = e.firstChild();
    QString text = textElement.data().string();
    // text is for instance "Grave bugs - outstanding:" or "Normal bugs - resolved:"
    //kdDebug() << "\nSeverity text: " << text << endl;
    int dashPos = text.find( "-" );
    if ( dashPos == -1 )
        return;
    bool closed = text.mid( dashPos+1 ).stripWhiteSpace().startsWith("resolved:");
    m_currentStatus = closed ? Bug::Closed : Bug::Open;
    //kdDebug() << "Status for next set of bugs: " << Bug::statusToString(m_currentStatus) << endl;

    text = text.left( dashPos );
    // This is a special case that can't be parsed by stringToSeverity
    if ( text.startsWith( "Reported crashes" ) ) {
        m_currentSeverity = Bug::Crash;
        //kdDebug() << "Severity for next set of bugs: crash" << endl;
    } else {
        QStringList words = QStringList::split( ' ', text );
        if ( words.count() < 2 )
           return;

        //kdDebug() << "Severity for next set of bugs: " << words[0] << endl;
        bool ok = false;
        Bug::Severity sev = Bug::stringToSeverity( words[ 0 ], &ok );
        if ( ok )
            m_currentSeverity = sev;
    }
}

void BugListJob::parseAge( const QString &text, uint &age )
{
    int daysOldPos = text.find( "days old" );
    if ( daysOldPos == -1 )
        return;

    int daysStartPos = text.findRev( ";", daysOldPos );
    if ( daysStartPos == -1 )
        daysStartPos = 0;

    bool ok = false;
    int tmpAge = text.mid( daysStartPos, daysOldPos - daysStartPos ).toUInt( &ok );
    if ( ok )
        age = tmpAge;
}

#include "buglistjob.moc"

/*
 * vim:sw=4:ts=4:et
 */
