#include "gpanthera.hh"
#include <iostream>

namespace gPanthera {
    DockablePane::DockablePane(Gtk::Widget &child, const Glib::ustring &name, const Glib::ustring &label, Gtk::Image *icon, DockStack *stack, Gtk::Widget *custom_header)
        : Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0), name(name) {
        if(icon) {
            this->icon = icon;
        }
        if(stack) {
            this->stack = stack;
        }
        this->label.set_text(label);
        auto header = Gtk::make_managed<Gtk::HeaderBar>();
        header->set_show_close_button(false);
        if(custom_header) {
            header->set_custom_title(*custom_header);
        } else {
            header->set_custom_title(this->label);
        }
        auto header_menu_button = Gtk::make_managed<Gtk::MenuButton>();
        auto header_menu = Gtk::make_managed<Gtk::Menu>();
        header_menu_button->set_direction(Gtk::ARROW_NONE);
        header_menu_button->set_popup(*header_menu);
        auto close_menu_item = Gtk::make_managed<Gtk::MenuItem>("Close");
        auto pop_out_menu_item = Gtk::make_managed<Gtk::MenuItem>("Pop out");
        close_menu_item->signal_activate().connect([this]() {
            if(this->stack) {
                this->stack->set_visible_child("empty");
            }
        });
        pop_out_menu_item->signal_activate().connect([this]() {
            if(this->stack) {
                this->pop_out();
            }
        });
        header_menu->append(*close_menu_item);
        header_menu->append(*pop_out_menu_item);
        header_menu->show_all();
        header->pack_end(*header_menu_button);
        this->pack_start(*header, Gtk::PACK_SHRINK);
        this->pack_end(child, Gtk::PACK_EXPAND_WIDGET);
        show_all_children();
    }

    void DockablePane::redock(DockStack *stack) {
        if(this->window) {
            this->window->close();
            this->window = nullptr;
        }
        this->stack = stack;
    }

    void DockablePane::pop_out() {
        if(this->stack) {
            this->stack->remove(*this);
            this->stack = nullptr;
        }
    }


    Glib::ustring DockablePane::get_identifier() const {
        return name;
    }

    Gtk::Image *DockablePane::get_icon() const {
        return icon;
    }

    Gtk::Label *DockablePane::get_label() {
        return &label;
    }

    LayoutManager::LayoutManager() : Glib::ObjectBase("LayoutManager") {
    }

    void LayoutManager::add_pane(DockablePane *pane) {
        panes.push_back(pane);
    }

    DockStack::DockStack(std::shared_ptr<LayoutManager> layout) : Gtk::Stack(), layout(layout) {
        auto *empty_child = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_VERTICAL, 0);
        add(*empty_child, "empty");
    }

    DockWindow::DockWindow(DockablePane *pane) {
        this->pane = pane;
    }

    DockStackSwitcher::DockStackSwitcher(DockStack *stack) : Gtk::ButtonBox(Gtk::ORIENTATION_HORIZONTAL), stack(stack) {
        this->stack->signal_add().connect([this](Gtk::Widget *child) {
            this->update_buttons();
        });
        this->stack->signal_remove().connect([this](Gtk::Widget *child) {
            this->update_buttons();
        });
    }

    void DockStackSwitcher::update_buttons() {
        for(auto const &child : get_children()) {
            remove(*child);
        }
        for(auto const &widget : stack->get_children()) {
            if(auto pane = dynamic_cast<DockablePane*>(widget)) {
                auto *button = Gtk::make_managed<Gtk::Button>();
                if(pane->get_icon()) {
                    button->set_image(*pane->get_icon());
                }
                button->signal_clicked().connect([this, pane]() {
                    if(stack->get_visible_child_name() == pane->get_identifier()) {
                        stack->set_visible_child("empty");
                    } else {
                        stack->set_visible_child(pane->get_identifier());
                    }
                });
                if(pane->get_identifier() != Glib::ustring("empty")) {
                    pack_start(*button);
                }
            }
        }
    }

    void DockStack::add_pane(Gtk::Widget &child, const Glib::ustring &name) {
        if(auto pane = dynamic_cast<DockablePane*>(&child)) {
            pane->redock(this);
        }
        Gtk::Stack::add(child, name);
    }
} // namespace gPanthera
