// =============================================================== //
//                                                                 //
//   File      : SEC_drawn_pos.hxx                                 //
//   Purpose   : store all drawn positions                         //
//                                                                 //
//   Coded by Ralf Westram (coder@reallysoft.de) in August 2007    //
//   Institute of Microbiology (Technical University Munich)       //
//   http://www.arb-home.de/                                       //
//                                                                 //
// =============================================================== //

#ifndef SEC_DRAWN_POS_HXX
#define SEC_DRAWN_POS_HXX

#ifndef _GLIBCXX_MAP
#include <map>
#endif
#ifndef AW_POSITION_HXX
#include <aw_position.hxx>
#endif

using namespace AW;

typedef std::map<size_t, Position> PosMap;

class SEC_drawn_positions : virtual Noncopyable {
    PosMap drawnAt;

public:
    void clear() { drawnAt.clear(); }
    void announce(size_t abs, const Position& drawn) { drawnAt[abs] = drawn; }

    bool empty() const { return drawnAt.empty(); }
    const PosMap::const_iterator begin() const { return drawnAt.begin(); }
    const PosMap::const_iterator end() const { return drawnAt.end(); }

    const Position *drawn_at(size_t abs) const {
        PosMap::const_iterator found = drawnAt.find(abs);
        return (found == drawnAt.end()) ? NULp : &(found->second);
    }

    const Position& drawn_before(size_t abspos, size_t *before_abs) const {
        sec_assert(!empty());
        PosMap::const_iterator found = drawnAt.lower_bound(abspos); // first position which is >= abspos

        if (found == drawnAt.begin()) { // no position drawn before abspos
            found = drawnAt.end(); // wrap to (beyond) end
        }
        advance(found, -1); // now just use position before (will be last map position when found==.end())
        sec_assert(found != drawnAt.end());

        if (before_abs) *before_abs = found->first;
        return *&found->second;
    }

    const Position& drawn_after(size_t abspos, size_t *after_abs) const {
        sec_assert(!empty());
        PosMap::const_iterator found = drawnAt.upper_bound(abspos); // first pos which is > abspos

        if (found == drawnAt.end()) { // no position drawn behind abs
            found = drawnAt.begin(); // wrap to start
        }

        if (after_abs) *after_abs = found->first;
        return *&found->second;
    }

    const Position& drawn_at_or_after(size_t abspos) const {
        const Position *at = drawn_at(abspos);
        return at ? *at : drawn_after(abspos, NULp);
    }

};


#else
#error SEC_drawn_pos.hxx included twice
#endif // SEC_DRAWN_POS_HXX
