#include "LayoutTree.h"

#include <GG/Layout.h>


namespace {
    struct WndWithin
    {
        WndWithin(const GG::Rect& rect) : m_rect(rect) {}
        bool operator()(const GG::Wnd* w) {return m_rect.Contains(w->UpperLeft());}
        const GG::Rect m_rect;
    };
}

////////////////////////////////////////
// LayoutTree::Node
////////////////////////////////////////
LayoutTree::Node::Node() :
    m_layout(0)
{}

LayoutTree::Node::Node(const GG::Rect& rect, const GG::Pt& offset) :
    m_layout(0),
    m_bounds_rect(rect + offset)
{}

LayoutTree::Node::Node(GG::Layout* layout, const GG::Pt& offset) :
    m_layout(layout),
    m_bounds_rect(layout->UpperLeft() + offset, layout->LowerRight() + offset)
{
    std::vector<std::vector<GG::Rect> > rects = layout->CellRects();
    m_cells.resize(rects.size());
    for (unsigned int i = 0; i < rects.size(); ++i) {
        m_cells[i].resize(rects[i].size());
        for (unsigned int j = 0; j < rects[i].size(); ++j) {
            std::list<GG::Wnd*>::const_iterator it =
                std::find_if(layout->Children().begin(), layout->Children().end(), WndWithin(rects[i][j]));
            GG::Layout* sub_layout = it == layout->Children().end() ? 0 : dynamic_cast<GG::Layout*>(*it);
            if (sub_layout)
                m_cells[i][j] = Node(sub_layout, offset);
            else
                m_cells[i][j] = Node(rects[i][j], offset);
        }
    }
}


////////////////////////////////////////
// LayoutTree
////////////////////////////////////////
LayoutTree::LayoutTree()
{}

boost::tuple<GG::Layout*, int, int> LayoutTree::Cell(const GG::Pt& pt) const
{
    for (unsigned int i = 0; i < m_root_nodes.size(); ++i) {
        assert(m_root_nodes[i].m_layout);
        if (m_root_nodes[i].m_bounds_rect.Contains(pt))
            return Cell(m_root_nodes[i], pt);
    }
    return boost::tuple<GG::Layout*, int, int>();
}

void LayoutTree::Reset(const GG::Wnd* dialog, const std::set<GG::Wnd*>& children)
{
    m_root_nodes.clear();
    if (GG::Layout* layout = const_cast<GG::Layout*>(dialog->GetLayout()))
        m_root_nodes.push_back(Node(layout, GG::Pt(0, 0)));
    for (std::set<GG::Wnd*>::const_iterator it = children.begin(); it != children.end(); ++it) {
        if (GG::Layout* layout = dynamic_cast<GG::Layout*>(*it))
            m_root_nodes.push_back(Node(layout, dialog->ClientUpperLeft()));
    }
}

boost::tuple<GG::Layout*, int, int> LayoutTree::Cell(const Node& node, const GG::Pt& pt) const
{
    for (unsigned int i = 0; i < node.m_cells.size(); ++i) {
        for (unsigned int j = 0; j < node.m_cells[i].size(); ++j) {
            if (node.m_cells[i][j].m_bounds_rect.Contains(pt)) {
                if (node.m_cells[i][j].m_layout)
                    return Cell(node.m_cells[i][j], pt);
                else
                    return boost::tuple<GG::Layout*, int, int>(node.m_layout, i, j);
            }
        }
    }
    return boost::tuple<GG::Layout*, int, int>();
}
