/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtMacExtras module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#import <AppKit/AppKit.h>
#include "qmactoolbar.h"
#include "qmactoolbar_p.h"

#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtCore/QUuid>
#include <QtCore/QString>
#include <QtCore/qdebug.h>

#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QtGui/QGuiApplication>
#include <qpa/qplatformnativeinterface.h>
#else
#include <QtGui/QMainWindow>
#endif

#include "qmacfunctions.h"
#include "qmacfunctions_p.h"
#include "qmactoolbaritem_p.h"
#include "qmactoolbardelegate_p.h"
#include "qnstoolbar_p.h"

QT_BEGIN_NAMESPACE

/*!
  \class QMacToolBar
  \inmodule QtMacExtras
  \since 5.3
  \brief The QMacToolBar class wraps the native NSToolbar class.

  QMacToolBar provides a Qt-based API for NSToolBar. The toolbar displays one or
  more \e items. Each toolbar item has an icon and a text label.

  The toolbar must be attached to a QWindow using the
  \l{QMacToolBar::attachToWindow()}{attachToWindow()} method in order to be visible.
  The toolbar is attached to the native NSWindow and is displayed above the
  QWindow. QMacToolBar visibility follows window visibility.

  Add items by calling addItem(). The toolbar has a customization menu which
  is available to the user from the toolbar context menu. Use addAllowedItem() to
  add items to the customization menu.

  Usage: (QtWidgets)
  \code
    QMacToolBar *toolBar = new QMacToolBar(this);
    QMacToolBarItem *toolBarItem = toolBar->addItem(QIcon(), QStringLiteral("foo"));
    connect(toolBarItem, SIGNAL(activated()), this, SLOT(fooClicked()));

    this->window()->winId(); // create window->windowhandle()
    toolBar->attachToWindow(this->window()->windowHandle());
  \endcode

  \sa QMacToolBarItem
*/

/*!
    Constructs a QMacToolBar with the given \a parent
*/
QMacToolBar::QMacToolBar(QObject *parent)
    : QObject(*new QMacToolBarPrivate(), parent)
{
}

/*!
    Constructs a QMacToolBar with the given \a identifier and \a parent. The identifier is used
    to uniquely identify the toolbar within the appliation, for example when autosaving the
    toolbar configuration.
*/
QMacToolBar::QMacToolBar(const QString &identifier, QObject *parent)
    : QObject(*new QMacToolBarPrivate(identifier), parent)
{
}

/*!
    Destroys the toolbar.
*/
QMacToolBar::~QMacToolBar()
{
    Q_D(QMacToolBar);
    [d->toolbar release];
}

/*!
    Add a toolbar item with \a icon and \a text.
*/
QMacToolBarItem *QMacToolBar::addItem(const QIcon &icon, const QString &text)
{
    Q_D(QMacToolBar);
    QMacToolBarItem *item = new QMacToolBarItem(this);
    item->setText(text);
    item->setIcon(icon);
    d->items.append(item);
    d->allowedItems.append(item);
    return item;
}

/*!
    Add a toolbar separator item.
*/
void QMacToolBar::addSeparator()
{
    addStandardItem(QMacToolBarItem::Space); // No Seprator on OS X.
}

/*!
    Add a toolbar standard item.
    \omitvalue standardItem
    \internal
*/
QMacToolBarItem *QMacToolBar::addStandardItem(QMacToolBarItem::StandardItem standardItem)
{
    Q_D(QMacToolBar);
    QMacToolBarItem *item = new QMacToolBarItem(this);
    item->setStandardItem(standardItem);
    d->items.append(item);
    d->allowedItems.append(item);
    return item;
}

/*!
    Add atoolbar item with \a icon and \a text to the toolbar customization menu.
*/
QMacToolBarItem *QMacToolBar::addAllowedItem(const QIcon &icon, const QString &text)
{
    Q_D(QMacToolBar);
    QMacToolBarItem *item = new QMacToolBarItem(this);
    item->setText(text);
    item->setIcon(icon);
    d->allowedItems.append(item);
    return item;
}

/*!
    Add a standard toolbar item to the toolbar customization menu.
    \omitvalue standardItem
    \internal
*/
QMacToolBarItem *QMacToolBar::addAllowedStandardItem(QMacToolBarItem::StandardItem standardItem)
{
    Q_D(QMacToolBar);
    QMacToolBarItem *item = new QMacToolBarItem(this);
    item->setStandardItem(standardItem);
    d->allowedItems.append(item);
    return item;
}

/*!
    Sets the list of the default toolbar \a items.
*/
void QMacToolBar::setItems(QList<QMacToolBarItem *> &items)
{
    Q_D(QMacToolBar);
    d->items = items;
}

/*!
    Returns the list of the default toolbar items.
*/
QList<QMacToolBarItem *> QMacToolBar::items()
{
    Q_D(QMacToolBar);
    return d->items;
}

/*!
    Sets the list of toolbar items shown on the toolbar customization menu to \a allowedItems.
*/
void QMacToolBar::setAllowedItems(QList<QMacToolBarItem *> &allowedItems)
{
    Q_D(QMacToolBar);
    d->allowedItems = allowedItems;
}

/*!
    Returns the list oftoolbar items shown on the the toolbar customization menu.
*/
QList<QMacToolBarItem *> QMacToolBar::allowedItems()
{
    Q_D(QMacToolBar);
    return d->allowedItems;
}

/*!
    Attaches the toolbar to \a window. The toolbar will be displayed at the top of the
    native window, under and attached to the title bar above the QWindow. The toolbar is displayed
    outside the QWidnow area.

    Use QWidget::windowHandle() to get a QWindow pointer from a QWidget instance. At app startup
    the QWindow might not have been created yet, call QWidget::winId() to make sure it is.
*/
void QMacToolBar::attachToWindow(QWindow *window)
{
    Q_D(QMacToolBar);
    if (!window) {
        detachFromWindow();
        return;
    }

    QPlatformNativeInterface::NativeResourceForIntegrationFunction function = resolvePlatformFunction("setNSToolbar");
    if (function) {
        typedef void (*SetNSToolbarFunction)(QWindow *window, void *nsToolbar);
        reinterpret_cast<SetNSToolbarFunction>(function)(window, d->toolbar);
    } else {
        d->targetWindow = window;
        QTimer::singleShot(100, this, SLOT(showInWindow_impl())); // ### hackety hack
    }
}

/*!
    \internal
*/
void QMacToolBar::showInWindow_impl()
{
    Q_D(QMacToolBar);
    if (!d->targetWindow) {
        QTimer::singleShot(100, this, SLOT(showInWindow_impl()));
        return;
    }

    NSWindow *macWindow = static_cast<NSWindow*>(
        QGuiApplication::platformNativeInterface()->nativeResourceForWindow("nswindow", d->targetWindow));

    if (!macWindow) {
        QTimer::singleShot(100, this, SLOT(showInWindow_impl()));
        return;
    }

    [macWindow setToolbar: d->toolbar];
    [macWindow setShowsToolbarButton:YES];
}

/*!
    Detatches the toolbar from the current window.
*/
void QMacToolBar::detachFromWindow()
{
    Q_D(QMacToolBar);
    if (!d->targetWindow)
        return;

    NSWindow *macWindow = static_cast<NSWindow*>(
        QGuiApplication::platformNativeInterface()->nativeResourceForWindow("nswindow", d->targetWindow));
    [macWindow setToolbar:nil];
}

/*!
    Returns the naitve NSTooolbar object.
*/
NSToolbar *QMacToolBar::nativeToolbar() const
{
    Q_D(const QMacToolBar);
    return d->toolbar;
}

QMacToolBarPrivate::QMacToolBarPrivate(const QString &identifier)
{
    QString ident = identifier.isEmpty() ? QUuid::createUuid().toString() : identifier;
    toolbar = [[NSToolbar alloc] initWithIdentifier:ident.toNSString()];
    [toolbar setAutosavesConfiguration:NO];
    [toolbar setAllowsUserCustomization:YES];

    QMacToolbarDelegate *delegate = [[QMacToolbarDelegate alloc] init];
    delegate->toolbarPrivate = this;
    [toolbar setDelegate:delegate];

    targetWindow = 0;
}

QMacToolBarPrivate::~QMacToolBarPrivate()
{
    [[toolbar delegate]release];
    [toolbar release];
}

NSMutableArray *QMacToolBarPrivate::getItemIdentifiers(const QList<QMacToolBarItem *> &items, bool cullUnselectable)
{
    NSMutableArray *array = [[NSMutableArray alloc] init];
    foreach (const QMacToolBarItem * item, items) {
        if (cullUnselectable && item->selectable() == false)
            continue;
        [array addObject : item->d_func()->itemIdentifier()];
    }
    return array;
}

void QMacToolBarPrivate::itemClicked(NSToolbarItem *item)
{
    QString identifier = QString::fromNSString([item itemIdentifier]);
    QMacToolBarItem *toolButton = reinterpret_cast<QMacToolBarItem *>(identifier.toULongLong());
    Q_EMIT toolButton->activated();
}


QT_END_NAMESPACE
