/*
 *  DoubleMap.h
 *
 *  Created by Thant on 4/13/10.
 *  Copyright 2010 TeleNav Inc. All rights reserved.
 *
 */

#ifndef Foundation_Math_DoubleMap_INCLUDED
#define Foundation_Math_DoubleMap_INCLUDED


#include <map>
#include <boost/optional.hpp>

namespace Tn {

namespace math {

template <typename A, typename B>
struct DoubleMap {

    typedef std::map<A,B> ABMap;
    typedef std::map<B,A> BAMap;

    typedef std::pair<A,B> ABMapEntry;
    typedef std::pair<B,A> BAMapEntry;

private:

    ABMap ab_map;
    BAMap ba_map;

public:

    inline void insert(A const & a, B const & b) {
        ab_map.insert(ABMapEntry(a, b));
        ba_map.insert(BAMapEntry(b, a));
        typename std::map<A,B>::iterator it = ab_map.find(a);
    }

    boost::optional<B> find(A const & a) const {
        typename ABMap::const_iterator it = ab_map.find(a);
        return (it != ab_map.end()) ? boost::optional<B>(it->second) : boost::optional<B>();
    }

    boost::optional<A> find(B const & b) const {
        typename BAMap::const_iterator it = ba_map.find(b);
        return (it != ba_map.end()) ? boost::optional<A>(it->second) : boost::optional<A>();
    }

    bool erase(A const & a) {
        typename ABMap::iterator it_ab = ab_map.find(a);
        if (it_ab != ab_map.end()) {
            typename BAMap::iterator it_ba = ba_map.find(it_ab->second);
            if (it_ba != ba_map.end()) {
                ba_map.erase(it_ba);
            } else {
                // one of the keys wasn't unique and was already
                // removed
            }
            ab_map.erase(it_ab);
            return true;
        }
        return false;
    }
        
    bool erase(B const & b) {
        typename BAMap::iterator it_ba = ba_map.find(b);
        if (it_ba != ba_map.end()) {
            typename ABMap::iterator it_ab = ab_map.find(it_ba->second);
            if (it_ab != ab_map.end()) {
               ab_map.erase(it_ab);
            } else {
                // one of the keys wasn't unique and was already
                // removed
            }
            ba_map.erase(it_ba);
            return true;
        }
        return false;
    }
};


} // namespace Tn

} // namespace math

#endif
