/*    Copyright 2014 10gen Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include "mongo/db/jsobj.h"

namespace mongo {

int getGtLtOp(const BSONElement& e) {
    if (e.type() != Object)
        return BSONObj::Equality;

    BSONElement fe = e.embeddedObject().firstElement();
    return fe.getGtLtOp();
}

bool fieldsMatch(const BSONObj& lhs, const BSONObj& rhs) {
    BSONObjIterator l(lhs);
    BSONObjIterator r(rhs);

    while (l.more() && r.more()) {
        if (strcmp(l.next().fieldName(), r.next().fieldName())) {
            return false;
        }
    }

    return !(l.more() || r.more());  // false if lhs and rhs have diff nFields()
}

Labeler::Label GT("$gt");
Labeler::Label GTE("$gte");
Labeler::Label LT("$lt");
Labeler::Label LTE("$lte");
Labeler::Label NE("$ne");
Labeler::Label NIN("$nin");
Labeler::Label BSIZE("$size");

GENOIDLabeler GENOID;
DateNowLabeler DATENOW;
NullLabeler BSONNULL;
UndefinedLabeler BSONUndefined;

MinKeyLabeler MINKEY;
MaxKeyLabeler MAXKEY;

BSONObjBuilderValueStream::BSONObjBuilderValueStream(BSONObjBuilder* builder) {
    _builder = builder;
}

BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const BSONElement& e) {
    _builder->appendAs(e, _fieldName);
    _fieldName = StringData();
    return *_builder;
}

BufBuilder& BSONObjBuilderValueStream::subobjStart() {
    StringData tmp = _fieldName;
    _fieldName = StringData();
    return _builder->subobjStart(tmp);
}

BufBuilder& BSONObjBuilderValueStream::subarrayStart() {
    StringData tmp = _fieldName;
    _fieldName = StringData();
    return _builder->subarrayStart(tmp);
}

Labeler BSONObjBuilderValueStream::operator<<(const Labeler::Label& l) {
    return Labeler(l, this);
}

void BSONObjBuilderValueStream::endField(const StringData& nextFieldName) {
    if (haveSubobj()) {
        verify(_fieldName.rawData());
        _builder->append(_fieldName, subobj()->done());
        _subobj.reset();
    }
    _fieldName = nextFieldName;
}

BSONObjBuilder* BSONObjBuilderValueStream::subobj() {
    if (!haveSubobj())
        _subobj.reset(new BSONObjBuilder());
    return _subobj.get();
}

BSONObjBuilder& Labeler::operator<<(const BSONElement& e) {
    s_->subobj()->appendAs(e, l_.l_);
    return *s_->_builder;
}

}  // namespace mongo
