/*
 *  QuadCoord.hpp
 *
 *  Created by thant on 10/17/2011.
 *  Copyright 2011 TeleNav. All rights reserved.
 *
 */

#ifndef Foundation_Math_QuadCoord_INCLUDED
#define Foundation_Math_QuadCoord_INCLUDED

#include <utility>
#include <foundation/TnTypes.h>
#include <iostream>

namespace Tn {

namespace math {

/*
 * QuadCoord implements an addressing system for the nodes of a
 * quad-tree.
 *
 * The level corresponds to the depth into the quad tree. Level zero
 * is the root node. Level one corresponds to four child nodes of the
 * root. Level two corresponds to 16 nodes, and so on.
 *
 * Each level can be thought of as a NxN array where N is
 * 2^level. Each node has a horizontal and vertical coordinate within
 * that array. Every node is fully specified by a level, a horizontal
 * component, and a vertical component.
 * 
 * It uses int32_t to represent the horizontal and vertical
 * components. If you use this quad tree to represent a tilation of
 * mercator projection of the earth's surface (which is what it's
 * for), the smallest tile this system can represent is less than an
 * inch at the equator--assuming I did my math right.
 * 
 */

enum eQuadrant {
    eQuadrant_BottomLeft = 1,
    eQuadrant_BottomRight,
    eQuadrant_TopLeft,
    eQuadrant_TopRight,
};

uint32_t GetHorizontalCoord(eQuadrant);         // zero or one
uint32_t GetVerticalCoord(eQuadrant);           // zero or one

struct QuadCoord {

    QuadCoord(); // root node
    QuadCoord(QuadCoord const & parent, eQuadrant branch);      // child node

    // This should eventually be private
    QuadCoord(uint32_t x, uint32_t y, uint32_t level);

    // Note order of arguments.
    QuadCoord(double longitude, double latitude, uint32_t level);

    QuadCoord getParent(QuadCoord const & coord);

    inline eQuadrant operator[](uint32_t i) const
    {
        uint32_t key = 0x0001 << (level - i - 1);
        bool horizontal = bool(x & key);
        bool vertical = bool(y & key);
        return 
            horizontal 
            ? 
            (vertical ? eQuadrant_TopRight : eQuadrant_BottomRight)
            :
            (vertical ? eQuadrant_TopLeft : eQuadrant_BottomLeft);
    }

    // Used to be const, but this prevents asignment. May should
    // switch to getters and setters.
    uint32_t x;
    uint32_t y;
    uint32_t level;
    uint32_t span;    // 2 ^ level


    /*  Convert a quad coord to mercator-projected latitude and
     *  longitude. (Does this belong here?)
     */

    static double longitude(uint32_t x, uint32_t span);
    static double latitude(uint32_t y, uint32_t span);

    double latitudeBottom() const;
    double latitudeTop() const;

    double longitudeLeft() const;
    double longitudeRight() const;

    QuadCoord getNeighbor(int32_t y /* latitude */, 
                          int32_t x /* longitude */);

    // This returns a normalized value.
    static double latToMercator(double latitude);

private:

};

// To allow quad coords to be used as keys.

inline bool operator==(QuadCoord const & a, QuadCoord const & b)
{
    return
        (a.x == b.x) &&
        (a.y == b.y) &&
        (a.level == b.level);
}


inline bool operator!=(QuadCoord const & a, QuadCoord const & b)
{
    return !(a==b);
}


//Will order the tiles from lowest to highest resolution
inline bool operator<(QuadCoord const & a, QuadCoord const & b)
{
    return
        ((a.level < b.level) ||
         ((a.level == b.level) &&
          ((a.y < b.y) ||
           ((a.y == b.y) &&
            (a.x < b.x)))));
}
    
inline std::ostream & operator<<(std::ostream &out, QuadCoord const & qc)
{
    // Since operator<< is a friend of the Point class, we can access
    // Point's members directly.
    out << "(X:" << qc.x << ", Y:" << qc.y << ", Level:" << qc.level
        << ", Span:" << qc.span << ")";
    
    return out;
}

} // namespace math

} // namespace Tn

#endif
