/* Copyright (C) 2017 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

_CONFIGINCLUDE(gdkmmconfig.h)

_DEFS(gdkmm,gdk)

#include <glibmm/refptr.h>
#include <glibmm/ustring.h>
#include <glibmm/value.h>
#include <giomm/file.h>
#include <gdk/gdk.h> // For GdkContentFormats.
#include <vector>

_CC_INCLUDE(gdk/gdk.h)

namespace Gdk
{

/** Advertising and negotiating of content exchange formats.
 *
 * %Gdk::ContentFormats is used to advertise and negotiate the format of
 * content passed between different widgets, windows or applications using
 * for example the clipboard or drag'n'drop.
 *
 * GDK supports content in 2 forms: GType and mime type.
 * Using GTypes is meant only for in-process content transfers. Mime types
 * are meant to be used for data passing both in-process and out-of-process.
 * The details of how data is passed is described in the documentation of
 * the actual implementations.
 *
 * A %Gdk::ContentFormats describes a set of possible formats content can be
 * exchanged in. It is assumed that this set is ordered. GTypes are more
 * important than mime types. Order between different Gtypes or mime types
 * is the order they were added in, most important first. Functions that
 * care about order, such as join(), describe in
 * their documentation how they interpret that order, though in general the
 * order of the first argument is considered the primary order of the result,
 * followed by the order of further arguments.
 *
 * For debugging purposes, the function to_string() exists.
 * It will print a comma-separated list of formats from most important to least
 * important.
 *
 * %Gdk::ContentFormats is an immutable object. After creation, you cannot change
 * the types it represents. Instead, new %Gdk::ContentFormats have to be created.
 * Gdk::ContentFormatsBuilder is meant to help in this endeavor.
 *
 * @see Gdk::Drag, Gdk::Drop, Gdk::Clipboard
 *
 * @newin{3,94}
 */
class GDKMM_API ContentFormats final
{
  // GdkContentFormats is actually registered as a boxed type, but it has custom
  // reference-counting instead of copy/free functions, so we use it via RefPtr.
  _CLASS_OPAQUE_REFCOUNTED(ContentFormats, GdkContentFormats, NONE, gdk_content_formats_ref, gdk_content_formats_unref, GDKMM_API)
  _IGNORE(gdk_content_formats_ref, gdk_content_formats_unref)
public:
  /** Creates a new %Gdk::ContentFormats from an array of mime types.
   *
   * The mime types must be different or the behavior of the return value
   * is undefined. If you cannot guarantee this, use Gdk::ContentFormatsBuilder
   * instead.
   *
   * @param mime_types A vector of mime types.
   * @return The new %Gdk::ContentFormats.
   */
  static Glib::RefPtr<ContentFormats> create(const std::vector<Glib::ustring>& mime_types = {});
  _IGNORE(gdk_content_formats_new)

  /** Creates a new %Gdk::ContentFormats from a mime type.
   *
   * @param mime_type A mime type.
   * @return The new %Gdk::ContentFormats.
   */
  static Glib::RefPtr<ContentFormats> create(const Glib::ustring& mime_type);

  /** Creates a new %Gdk::ContentFormats from a GType.
   *
   * @param type A GType.
   * @return The new %Gdk::ContentFormats.
   */
  _WRAP_METHOD(static Glib::RefPtr<ContentFormats> create(GType type), gdk_content_formats_new_for_gtype)

  _WRAP_METHOD(static Glib::RefPtr<ContentFormats> parse(const Glib::ustring& string), gdk_content_formats_parse)

  /** Prints the given %ContentFormats into a string for human consumption.
   *
   * The resulting string can be parsed with parse().
   *
   * @return A new string.
   */
  _WRAP_METHOD(Glib::ustring to_string() const, gdk_content_formats_to_string)
  _IGNORE(gdk_content_formats_print)

  /** Gets the Types included in the %ContentFormats.
   * Note that they may not contain any Types, in particular when they are empty.
   * In that case an empty vector will be returned.
   *
   * @return A vector of types included in the %ContentFormats. May be empty.
   */
  std::vector<GType> get_gtypes() const;
  _IGNORE(gdk_content_formats_get_gtypes)

  /** Gets the mime types included in the %ContentFormats.
   * Note that they may not contain any mime types, in particular when they are empty.
   * In that case an empty vector will be returned.
   *
   * @return A vector of mime types included in the %ContentFormats. May be empty.
   */
  std::vector<Glib::ustring> get_mime_types() const;
  _IGNORE(gdk_content_formats_get_mime_types)

  _WRAP_METHOD(bool contain_gtype(GType type) const, gdk_content_formats_contain_gtype)
  _WRAP_METHOD(bool contain_mime_type(const Glib::ustring& mime_type) const,
    gdk_content_formats_contain_mime_type)
  _WRAP_METHOD(bool is_empty() const, gdk_content_formats_is_empty)

  // 'union' is a C and C++ keyword. Can't be a method name.
  /** Append all missing types from @a second to <tt>*this</tt>, in the order
   * they had in @a second.
   *
   * @param second The %ContentFormats to merge from.
   * @return A new %ContentFormats.
   */
  Glib::RefPtr<ContentFormats> join(const Glib::RefPtr<const ContentFormats>& second) const;
  _IGNORE(gdk_content_formats_union)

  _WRAP_METHOD(bool match(const Glib::RefPtr<const ContentFormats>& second) const, gdk_content_formats_match)
  _WRAP_METHOD(GType match_gtype(const Glib::RefPtr<const ContentFormats>& second) const, gdk_content_formats_match_gtype)
  /** Finds the first mime type from <tt>*this</tt> that is also contained in @a second.
   * If no matching mime type is found, an empty string is returned.
   *
   * @param second The Gdk::ContentFormats to intersect with.
   * @return The first common mime type, or an empty string if none.
   */
  _WRAP_METHOD(Glib::ustring match_mime_type(const Glib::RefPtr<const ContentFormats>& second) const, gdk_content_formats_match_mime_type)
};

} // namespace Gdk

#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace Glib
{
// This is needed so Glib::RefPtr<Gdk::ContentFormats> can be used with
// Glib::Value and _WRAP_PROPERTY in Gdk::Clipboard and elsewhere.
template <>
class GDKMM_API Value<Glib::RefPtr<Gdk::ContentFormats>> : public ValueBase_Boxed
{
public:
  typedef Glib::RefPtr<Gdk::ContentFormats> CppType;
  typedef GdkContentFormats* CType;

  static GType value_type();

  void set(const CppType& data);
  CppType get() const;
};

// This is needed so std::vector<Glib::RefPtr<Gio::File>> can be used with
// Glib::Value in Gdk::ContentProvider and elsewhere.
template <>
class GDKMM_API Value<std::vector<Glib::RefPtr<Gio::File>>> : public ValueBase_Boxed
{
public:
  typedef std::vector<Glib::RefPtr<Gio::File>> CppType;
  typedef GdkFileList* CType;

  static GType value_type();

  void set(const CppType& data);
  CppType get() const;
};

} // namespace Glib
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
