#include "Window.h"
#include <sstream>


Window::Window(Window* parent)
: Sprite(), _parent(parent), _caption(0), _enabled(true), _draggable(false), _dragBound(true)
{
    if (_parent != 0) {
        _parent->addChild(this);
    }

    setPosition(Point(0.0f, 0.0f));
    setSize(Size(256.0f, 256.0f));

    _caption = new Text();
    _caption->setPosition(Vector3(0.0f, 0.0f, 0.0f));
    _caption->setScale(Vector3(1.0f, 1.0f, 1.0f));
    _caption->setMaxWidth(_size.w());
    _caption->setMaxHeight(_size.h());
    _caption->setFont(L"Microsoft Sans Serif", L"000000", 13.0f, Text::FONT_STYLE_REGULAR, Text::H_ALIGN_CENTER | Text::V_ALIGN_CENTER);

    Sprite::addChild(_caption);
}

Window::~Window()
{
    delete _caption;
}

Window* Window::getParent()
{
    return _parent;
}

void Window::setParent(Window* parent)
{
    if (_parent != 0)
        _parent->removeChild(this);

    _parent = parent;

    if (_parent != 0)
        _parent->addChild(this);
}

Point Window::getPosition()
{
    return _position;
}

Size Window::getSize()
{
    return _size;
}

bool Window::isEnabled()
{
    return _enabled;
}

void Window::enable(bool enabled)
{
    if ((_enabled == true) && (enabled == false)) {
        _enabled = false;

        for (std::list<Node*>::iterator iChild = getChildren().begin(); iChild != getChildren().end(); ++iChild) {
            if (Window* child = dynamic_cast<Window*>(*iChild))
                child->enable(enabled);
        }
    }

    else if ((_enabled == false) && (enabled == true)) {
        _enabled = true;

        for (std::list<Node*>::iterator iChild = getChildren().begin(); iChild != getChildren().end(); ++iChild) {
            if (Window* child = dynamic_cast<Window*>(*iChild))
                child->enable(enabled);
        }
    }
}

bool Window::isDraggable()
{
    return _draggable;
}

void Window::setDraggable(bool draggable)
{
    _draggable = draggable;
}

bool Window::isDragBound()
{
    return _dragBound;
}

void Window::setDragBound(bool dragBound)
{
    _dragBound = dragBound;
}

void Window::setPosition(Point& position)
{
    _position = position;

    if (_parent != 0) {
        Size parentSize = _parent->getSize();
        Sprite::setPosition(Vector3(_position.x() / parentSize.w(), _position.y() / parentSize.h(), 0.0f));
    }
    else {
        Sprite::setPosition(Vector3(_position.x(), _position.y(), 0.0f));
    }

    for (std::list<Node*>::iterator iChild = Sprite::getChildren().begin(); iChild != Sprite::getChildren().end(); ++iChild) {
        if (Window* child = dynamic_cast<Window*>(*iChild)) {
            child->setPosition(child->getPosition());
        }
    }
}

void Window::setSize(Size& size)
{
    _size = size;

    if (_parent != 0) {
        Size parentSize = _parent->getSize();
        Sprite::setScale(Vector3(_size.w() / parentSize.w(), _size.h() / parentSize.h(), 1.0f));
    }
    else {
        Sprite::setScale(Vector3(_size.w(), _size.h(), 1.0f));
    }

    if (_caption != 0) {
        _caption->setMaxWidth(_size.w());
        _caption->setMaxHeight(_size.h());
    }

    for (std::list<Node*>::iterator iChild = Sprite::getChildren().begin(); iChild != Sprite::getChildren().end(); ++iChild) {
        if (Window* child = dynamic_cast<Window*>(*iChild)) {
            child->setSize(child->getSize());
        }
    }
}

Point Window::getTranslatedPosition()
{
    if (_parent != 0) {
        Point position = _position + _parent->_position;

        Window* ancestor = _parent->_parent;

        while (ancestor != 0) {
            position += ancestor->_position;
            ancestor = ancestor->_parent;
        }

        return position;
    }
    else {
        return _position;
    }
}

void Window::addChild(Window* child)
{
    child->_parent = this;
    Sprite::addChild(child);
}

void Window::removeChild(Window* child)
{
    for (std::list<Node*>::iterator iChild = Sprite::getChildren().begin(); iChild != Sprite::getChildren().end(); ++iChild) {
        if (dynamic_cast<Window*>(*iChild) == child) {
            child->_parent = 0;
            Sprite::getChildren().erase(iChild);
            return;
        }
    }
}

Text* Window::getCaption()
{
    return _caption;
}

void Window::setCaption(const wchar_t* caption)
{
    _caption->setText(caption);
}


bool Window::isHit(float x, float y)
{
    if (!_visible)
        return false;

    Point position = getTranslatedPosition();
    return ((x >= position.x()) && (x <= position.x() + _size.w()) && (y >= position.y()) && (y <= position.y() + _size.h()));
}

Window* Window::getHitWindow(float x, float y)
{
    if (!_visible)
        return 0;

    Point position = getTranslatedPosition();

    bool hit = ((x >= position.x()) && (x <= position.x() + _size.w()) && (y >= position.y()) && (y <= position.y() + _size.h()));

    for (std::list<Node*>::reverse_iterator iWindow = getChildren().rbegin(); iWindow != getChildren().rend(); ++iWindow) {
        if (Window* child = dynamic_cast<Window*>(*iWindow)) {
            Window* hitWindow = child->getHitWindow(x, y);

            if (hitWindow != 0)
                return hitWindow;
        }
    }

    if (hit)
        return this;
    else
        return 0;
}


void Window::connectEvent(int eventType, Window* window, EventHandler eventHandler)
{
    EventHandlerDelegate eventHandlerDelegate = fastdelegate::MakeDelegate(this, eventHandler);

    window->_eventHandlers.insert(std::pair<int, EventHandlerDelegate>(eventType, eventHandlerDelegate));
}

void Window::disconnectEvent(int eventType, Window* window, EventHandler eventHandler)
{
    EventHandlerDelegate eventHandlerDelegate = fastdelegate::MakeDelegate(this, eventHandler);

    std::pair<std::multimap<int, EventHandlerDelegate>::iterator, std::multimap<int, EventHandlerDelegate>::iterator> eventHandlers = window->_eventHandlers.equal_range(eventType);

    for (std::multimap<int, EventHandlerDelegate>::iterator iEventHandler = eventHandlers.first; iEventHandler != eventHandlers.second; ++iEventHandler) {
        if ((*iEventHandler).second == eventHandlerDelegate) {
            window->_eventHandlers.erase(iEventHandler);
            return;
        }
    }
}

void Window::handleEvent(Event& event)
{
    std::pair<std::multimap<int, EventHandlerDelegate>::iterator, std::multimap<int, EventHandlerDelegate>::iterator> eventHandlers = _eventHandlers.equal_range(event.type);

    for (std::multimap<int, EventHandlerDelegate>::iterator iEventHandler = eventHandlers.first; iEventHandler != eventHandlers.second; ++iEventHandler) {
        EventHandlerDelegate eventHandler = (*iEventHandler).second;

        if (eventHandler != 0)
            eventHandler(event);
    }  
}