/*!
  \file
  \brief レイヤー管理

  \author Satofumi KAMIMURA

  $Id: LayerManager.cpp 1950 2011-05-07 08:18:39Z satofumi $

  \todo 登録済みのイベントを insertEvent() しても問題ないように修正する
*/

#include "LayerManager.h"
#include "Layer.h"
#include "EventManager.h"
#include "Event.h"
#include <boost/bind.hpp>
#include <algorithm>
#include <list>

using namespace qrk;
using namespace boost;
using namespace std;


namespace
{
    typedef list<LayerInterface*> Layers;
}


struct LayerManager::pImpl
{
    Layers layers_;
    EventManager event_manager_;

    Point<long> current_cursor_;
    Point<long> previous_cursor_;


    pImpl(void) : previous_cursor_(-1, -1)
    {
        SDL_EnableUNICODE(SDL_ENABLE);
    }


    ~pImpl(void)
    {
        SDL_EnableUNICODE(SDL_DISABLE);
    }


    static pImpl* object(void)
    {
        static pImpl singleton_object;
        return &singleton_object;
    }


    void updateEvent(void)
    {
        //bool cursor_moved = false;
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            switch (event.type) {

            case SDL_QUIT:
                // !!! コールバックを呼ぶか、ここで終了させる
                exit(0);
                break;

            case SDL_KEYDOWN:
            case SDL_KEYUP:
                event_manager_.checkKey(event.key.keysym.sym, event.key.type,
                                        event.key.keysym.mod,
                                        event.key.keysym.unicode);
                break;

            case SDL_MOUSEBUTTONDOWN:
            case SDL_MOUSEBUTTONUP:
                event_manager_.checkClick(event.button.button,
                                          event.button.type);
                break;

            case SDL_MOUSEMOTION:
                //cursor_moved = true;
                current_cursor_ = Point<long>(event.motion.x, event.motion.y);
                event_manager_.checkEnterCursor(current_cursor_,
                                                previous_cursor_);
                previous_cursor_ = current_cursor_;
                event_manager_.cursorMoved();
                break;

            default:
                break;
            }
        }
    }


    void remove(LayerInterface* layer)
    {
        Layers::iterator it = find(layers_.begin(), layers_.end(), layer);
        if (it != layers_.end()) {
            layers_.erase(it);
        }
    }
};


LayerManager::LayerManager(void) : pimpl(pImpl::object())
{
}


LayerManager::~LayerManager(void)
{
}


void LayerManager::updateEvent(void)
{
    pimpl->updateEvent();
}


void LayerManager::draw(void)
{
    // 再描画
    for_each(pimpl->layers_.begin(), pimpl->layers_.end(),
             bind(&LayerInterface::draw, _1));
}


void LayerManager::swap(void)
{
    SDL_GL_SwapBuffers();
}


void LayerManager::clearEvent(void)
{
    pimpl->event_manager_.clear();
}


void LayerManager::insertEvent(Event* event)
{
    pimpl->event_manager_.insert(event);
}


void LayerManager::removeEvent(Event* event)
{
    pimpl->event_manager_.remove(event);
}


void LayerManager::clear(void)
{
    pimpl->layers_.clear();
}


void LayerManager::push_front(LayerInterface* layer)
{
    const Layers::iterator it =
        find(pimpl->layers_.begin(), pimpl->layers_.end(), layer);
    if (it == pimpl->layers_.end()) {
        pimpl->layers_.push_back(layer);
    }
}


void LayerManager::push_back(LayerInterface* layer)
{
    const Layers::iterator it =
        find(pimpl->layers_.begin(), pimpl->layers_.end(), layer);
    if (it == pimpl->layers_.end()) {
        pimpl->layers_.push_front(layer);
    }
}


void LayerManager::remove(LayerInterface* layer)
{
    pimpl->remove(layer);
}


Point<long> LayerManager::cursor(void)
{
    return pImpl::object()->current_cursor_;
}
