/*
    SuperCollider Qt IDE
    Copyright (c) 2012 Jakob Leben & Tim Blechmann
    http://www.audiosynth.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

#pragma once

#include <QSplitter>
#include "../multi_editor.hpp"

namespace ScIDE {

class MultiEditor;

class MultiSplitter : public QSplitter
{
public:
    explicit MultiSplitter(MultiEditor *editor, QWidget *parent = 0):
        QSplitter(parent), mEditor(editor)
    {
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    }

    MultiEditor *editor() { return mEditor; }

    void insertWidget( QWidget *widget, QWidget *neighbour, Qt::Orientation direction )
    {
        if (!neighbour || !widgetIsChild(neighbour)) {
            qWarning("MultiSplitter: neighbour widget invalid");
            return;
        }

        QSplitter *parentSplitter = parentSplitterOf(neighbour);
        Q_ASSERT(parentSplitter);
        int posInParent = parentSplitter->indexOf(neighbour);
        Q_ASSERT(posInParent != -1);

        if (parentSplitter->orientation() == direction) {
            parentSplitter->insertWidget(posInParent + 1, widget);
        }
        else if (parentSplitter->count() < 2)
        {
            parentSplitter->setOrientation(direction);
            parentSplitter->addWidget(widget);
        }
        else {
            // store parent's current distribution:
            QList<int> parentsSizes = parentSplitter->sizes();
            QSplitter * splitter = new QSplitter(direction);
            // move the neighbour to the new splitter, and add the new widget:
            splitter->addWidget(neighbour);
            splitter->addWidget(widget);
            // insert the new splitter at the neighbour's old position:
            parentSplitter->insertWidget(posInParent, splitter);
            // restore parent's old distribution, affected by operations above:
            parentSplitter->setSizes(parentsSizes);
            // change the parent to the new splitter, for operations below:
            parentSplitter = splitter;
        }

        setEqualSizes(parentSplitter);
    }

    void removeWidget( QWidget *widget )
    {
        if (!widget || !widgetIsChild(widget)) {
            qWarning("MultiSplitter: widget invalid");
            return;
        }

        QSplitter *parent = parentSplitterOf(widget);
        if (parent == this && parent->count() < 2) {
            qWarning("MultiSplitter: can not remove last widget");
            return;
        }

        delete widget;

        Q_ASSERT(parent->count());

        if (parent->count() == 1) {
            QWidget *neighbour = parent->widget(0);
            if (parent != this) {
                // replace parent splitter with it's only child
                QSplitter *grandParent = parentSplitterOf(parent);
                QList<int> grandParentsSizes = grandParent->sizes();
                int posInParent = grandParent->indexOf(parent);
                Q_ASSERT(posInParent != -1);
                grandParent->insertWidget(posInParent, neighbour);
                delete parent;
                grandParent->setSizes(grandParentsSizes);
            }
            else {
                // replace child splitter with it's own children
                QSplitter *splitter = qobject_cast<QSplitter*>(neighbour);
                if (splitter) {
                    QList<int> childSizes = splitter->sizes();
                    Qt::Orientation childOrientation = splitter->orientation();
                    int childCount = splitter->count();
                    while(childCount--)
                        parent->addWidget(splitter->widget(0)); // 0 is always another widget
                    delete splitter;
                    parent->setOrientation(childOrientation);
                    parent->setSizes(childSizes);
                }
            }
        }
    }

    template<typename T> T* findChild()
    {
        return MultiSplitter::findChild<T>(this);
    }

private:
    template<typename T> static T* findChild( QSplitter * splitter ) {
        int childCount = splitter->count();
        for (int idx = 0; idx < childCount; ++idx) {
            QWidget *child = splitter->widget(idx);
            T* typedChild = qobject_cast<T*>(child);
            if (typedChild)
                return typedChild;
            QSplitter *childSplitter = qobject_cast<QSplitter*>(child);
            if (childSplitter) {
                typedChild = findChild<T>( childSplitter );
                if (typedChild)
                    return typedChild;
            }
        }
        return 0;
    }

    QSplitter *parentSplitterOf( QWidget *widget )
    {
        return qobject_cast<QSplitter*>( widget->parent() );
    }

    void setEqualSizes(QSplitter *splitter)
    {
        int widgetCount = splitter->count();
        int splitterSize = splitter->orientation() == Qt::Horizontal ?
                    splitter->size().width() : splitter->size().height();
        QList<int> newWidgetSizes;
        int singleWidgetSize = splitterSize / widgetCount;
        for( int idx = 0; idx < widgetCount; ++idx )
            newWidgetSizes << singleWidgetSize;
        splitter->setSizes( newWidgetSizes );
    }

    bool widgetIsChild( QWidget *widget )
    {
        QObject *object = widget->parent();
        while (object) {
            if (object == this)
                return true;
            object = object->parent();
        }
        return false;
    }

    MultiEditor *mEditor;
};

} // namespace ScIDE
