/*
   This file is part of the Nepomuk KDE project.
   Copyright (C) 2007 Sebastian Trueg <trueg@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
 */

#include "term.h"

#include <QtCore/QString>
#include <QtCore/QList>
#include <QtCore/QSharedData>
#include <QtCore/QDebug>


class Nepomuk::Search::Term::Private : public QSharedData
{
public:
    Private( Type t = InvalidTerm )
        : type( t ),
          comparator( Equal ) {
    }

    Type type;
    Comparator comparator;
    Soprano::LiteralValue value;
    QUrl resource;
    QString field;
    QUrl property;
    QList<Term> subTerms;
};


Nepomuk::Search::Term::Term()
    : d( new Private() )
{
}


Nepomuk::Search::Term::Term( const Term& other )
{
    d = other.d;
}


Nepomuk::Search::Term::Term( const Soprano::LiteralValue& value )
    : d( new Private( LiteralTerm ) )
{
    d->value = value;
}


Nepomuk::Search::Term::Term( const QString& field, const Soprano::LiteralValue& value )
    : d( new Private( ContainsTerm ) )
{
    d->field = field;
    d->value = value;
}


Nepomuk::Search::Term::Term( const QUrl& field, const Soprano::LiteralValue& value )
    : d( new Private( ContainsTerm ) )
{
    d->property = field;
    d->value = value;
}


Nepomuk::Search::Term::Term( const QUrl& field, const QUrl& resource )
    : d( new Private( ComparisonTerm ) )
{
    d->property = field;
    d->resource = resource;
}


Nepomuk::Search::Term::Term( const QUrl& field, const Soprano::LiteralValue& value, Comparator comparator )
    : d( new Private( ComparisonTerm ) )
{
    d->property = field;
    d->value = value;
    d->comparator = comparator;
}


Nepomuk::Search::Term::~Term()
{
}


Nepomuk::Search::Term& Nepomuk::Search::Term::operator=( const Term& other )
{
    d = other.d;
    return *this;
}


Nepomuk::Search::Term& Nepomuk::Search::Term::operator=( const Soprano::LiteralValue& literal )
{
    d->value = literal;
    d->type = LiteralTerm;
    d->subTerms.clear();
    d->field = QString();
    return *this;
}


bool Nepomuk::Search::Term::isValid() const
{
    return d->type != InvalidTerm;
}


Nepomuk::Search::Term::Type Nepomuk::Search::Term::type() const
{
    return d->type;
}


Soprano::LiteralValue Nepomuk::Search::Term::value() const
{
    return d->value;
}


QUrl Nepomuk::Search::Term::resource() const
{
    return d->resource;
}


Nepomuk::Search::Term::Comparator Nepomuk::Search::Term::comparator() const
{
    return d->comparator;
}


QString Nepomuk::Search::Term::field() const
{
    return d->field;
}


QUrl Nepomuk::Search::Term::property() const
{
    return d->property;
}


QList<Nepomuk::Search::Term> Nepomuk::Search::Term::subTerms() const
{
    return d->subTerms;
}


void Nepomuk::Search::Term::setType( Type type )
{
    d->type = type;
}


void Nepomuk::Search::Term::setValue( const Soprano::LiteralValue& v )
{
    d->value = v;
    d->resource = QUrl();
}


void Nepomuk::Search::Term::setResource( const QUrl& res )
{
    d->resource = res;
    d->value = Soprano::LiteralValue();
}


void Nepomuk::Search::Term::setComparator( Comparator c )
{
    d->comparator = c;
}


void Nepomuk::Search::Term::setField( const QString& f )
{
    d->field = f;
    d->property = QUrl();
}


void Nepomuk::Search::Term::setSubTerms( const QList<Term>& terms )
{
    d->subTerms = terms;
}


void Nepomuk::Search::Term::setProperty( const QUrl& p )
{
    d->property = p;
    d->field = QString();
}


void Nepomuk::Search::Term::addSubTerm( const Term& term )
{
    d->subTerms.append( term );
}


QDebug operator<<( QDebug dbg, const Nepomuk::Search::Term& term )
{
    if ( term.isValid() ) {
        dbg << "(Term";
        switch( term.type() ) {
        case Nepomuk::Search::Term::LiteralTerm:
            dbg << "literal";
            break;
        case Nepomuk::Search::Term::AndTerm:
            dbg << "and";
            break;
        case Nepomuk::Search::Term::OrTerm:
            dbg << "or";
            break;
        case Nepomuk::Search::Term::ContainsTerm:
            dbg << "contains";
            break;
        case Nepomuk::Search::Term::ComparisonTerm:
            dbg << "compare";
            switch( term.comparator() ) {
            case Nepomuk::Search::Term::Equal:
                dbg << "=";
                break;
            case Nepomuk::Search::Term::Greater:
                dbg << ">";
                break;
            case Nepomuk::Search::Term::Smaller:
                dbg << "<";
                break;
            case Nepomuk::Search::Term::GreaterOrEqual:
                dbg << ">=";
                break;
            case Nepomuk::Search::Term::SmallerOrEqual:
                dbg << "<=";
                break;
            }
        default:
            break;
        }
        if ( term.type() == Nepomuk::Search::Term::ContainsTerm ||
             term.type() == Nepomuk::Search::Term::EqualityTerm ) {
            if ( term.property().isValid() ) {
                dbg << "Property" << term.property();
            }
            else {
                dbg << "Field:" << term.field();
            }
        }
        if ( term.type() != Nepomuk::Search::Term::AndTerm &&
             term.type() != Nepomuk::Search::Term::OrTerm ) {
            if ( term.resource().isValid() ) {
                dbg << "Value:" << term.resource();
            }
            else {
                dbg << "Value:" << term.value();
            }
        }
        else {
            dbg << "Subterms: [";
            foreach( Nepomuk::Search::Term t, term.subTerms() ) {
                dbg << t;
            }
            dbg << "]";
        }
        dbg << ")";
    }

    return dbg;
}
