#include "zones_makeup.h"
#include "zones_description_interface.h"

namespace NZonesMakeup {

    //TZoneSpan
    TZoneSpan::TZoneSpan(IInputStream& in, int version) {
        Deserialize(in, version);
    }

    TZoneSpan::TZoneSpan(const TPosition& begin, const TPosition& end)
        : Begin(begin)
        , End(end)
    {}

    const TPosition TZoneSpan::GetBegin() const {
        return Begin;
    }

    const TPosition TZoneSpan::GetEnd() const {
        return End;
    }

    bool TZoneSpan::operator == (const TZoneSpan& other) const {
        return Begin == other.Begin && End == other.End;
    }

    bool TZoneSpan::operator != (const TZoneSpan& other) const {
        return !operator == (other);
    }

    void TZoneSpan::Serialize(IOutputStream& out) const {
        Begin.Serialize(out);
        End.Serialize(out);
    }

    void TZoneSpan::Deserialize(IInputStream& in, int version) {
        Begin.Deserialize(in, version);
        End.Deserialize(in, version);
    }

    //TZoneMakeup
    void TZoneMakeup::Serialize(IOutputStream& out) const {
        ui32 size = StartSent.ysize();
        out.Write(&size, sizeof(size));
        if (size) {
            out.Write(&StartSent[0], size * sizeof(StartSent[0]));
            out.Write(&StartWord[0], size * sizeof(StartWord[0]));
            out.Write(&FinishSent[0], size * sizeof(FinishSent[0]));
            out.Write(&FinishWord[0], size * sizeof(FinishWord[0]));
        };
        out.Write(&LengthInWords, sizeof(LengthInWords));
    }

    void TZoneMakeup::Deserialize(IInputStream& in, int /*version*/) {
        ui32 size;
        in.Load(&size, sizeof(size));
        StartSent.resize(size, 0);
        FinishSent.resize(size, 0);
        StartWord.resize(size, 0);
        FinishWord.resize(size, 0);

        if (size) {
            in.Load(&StartSent[0], size * sizeof(StartSent[0]));
            in.Load(&StartWord[0], size * sizeof(StartWord[0]));
            in.Load(&FinishSent[0], size * sizeof(FinishSent[0]));
            in.Load(&FinishWord[0], size * sizeof(FinishWord[0]));
        }
        in.Load(&LengthInWords, sizeof(LengthInWords));
    }

    TZoneMakeup::TZoneMakeup()
        : LengthInWords(0)
    {}

    TZoneMakeup::TZoneMakeup(IInputStream& in, int version)
        : LengthInWords(0)
    {
        Deserialize(in, version);
    }

    ui32 TZoneMakeup::GetLengthInWords() const {
        return LengthInWords;
    }

    void TZoneMakeup::MarkSentsBySpan(NZonesMakeup::TSentsMakeup& sents, NZonesMakeup::TZoneId id, ui32 startSent, ui32 endSent) {
        if (endSent >= sents.size())
            sents.resize(endSent, 0);
        for (ui32 st = startSent; st < endSent; st++) {
            sents[st] |= id;
        }
    }

    void TZoneMakeup::AddSpan(TZoneSpan span) {
        StartSent.push_back(span.GetBegin().Sent);
        StartWord.push_back(span.GetBegin().Word);
        FinishSent.push_back(span.GetEnd().Sent);
        FinishWord.push_back(span.GetEnd().Word);
        LengthInWords += span.GetEnd().WordInDoc - span.GetBegin().WordInDoc;
    }

    bool TZoneMakeup::operator == (const TZoneMakeup& other) const {
        if (GetLengthInWords() != other.GetLengthInWords() || StartSent.size() != other.StartSent.size())
            return false;
        for (size_t i = 0; i < StartSent.size(); ++i) {
            if (StartSent[i] != other.StartSent[i])
                return false;
            if (FinishSent[i] != other.FinishSent[i])
                return false;
            if (StartWord[i] != other.StartWord[i])
                return false;
            if (FinishWord[i] != other.FinishWord[i])
                return false;
        }
        return true;
    }

    bool TZoneMakeup::operator != (const TZoneMakeup& other) const {
        return !operator == (other);
    }

}
