/* Copyright 2023 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/>.
 */

#include <graphene.h>

namespace
{
graphene_rect_t* gdkmm_graphene_rect_copy(const graphene_rect_t* other)
{
  return graphene_rect_init_from_rect(graphene_rect_alloc(), other);
}

using get_functype = void (*)(const graphene_rect_t* r, graphene_point_t* p);
using Point = Gdk::Graphene::Point;

Point get_point(const graphene_rect_t* r, get_functype get_func)
{
  graphene_point_t* p = graphene_point_alloc();
  get_func(r, p);
  return Point(p, false);
}
} // anonymous namespace

namespace Gdk
{
namespace Graphene
{

Rect::Rect(float x, float y, float width, float height)
{
  gobject_ = graphene_rect_init(graphene_rect_alloc(), x, y, width, height);
}

Rect::operator bool() const
{
  return gobj();
}

Point Rect::get_center() const
{
  return get_point(gobj(), graphene_rect_get_center);
}

Point Rect::get_top_left() const
{
  return get_point(gobj(), graphene_rect_get_top_left);
}

Point Rect::get_top_right() const
{
  return get_point(gobj(), graphene_rect_get_top_right);
}

Point Rect::get_bottom_right() const
{
  return get_point(gobj(), graphene_rect_get_bottom_right);
}

Point Rect::get_bottom_left() const
{
  return get_point(gobj(), graphene_rect_get_bottom_left);
}

std::array<Vec2,4> Rect::get_vertices() const
{
  graphene_vec2_t vertices[4];
  graphene_rect_get_vertices(gobj(), vertices);
  return {Vec2(&vertices[0]), Vec2(&vertices[1]), Vec2(&vertices[2]), Vec2(&vertices[3])};
}

Rect Rect::join(const Rect& b) const
{
  graphene_rect_t* c_union = graphene_rect_alloc();
  graphene_rect_union(gobj(), b.gobj(), c_union);
  return Rect(c_union, false);
}

std::optional<Rect> Rect::intersection(const Rect& b) const
{
  graphene_rect_t* c_intersection = graphene_rect_alloc();
  const bool intersect = graphene_rect_intersection(gobj(), b.gobj(), c_intersection);
  if (!intersect)
    return {};
  return Rect(c_intersection, false);
}

Rect Rect::round_extents() const
{
  graphene_rect_t* c_extents = graphene_rect_alloc();
  graphene_rect_round_extents(gobj(), c_extents);
  return Rect(c_extents, false);
}

Rect Rect::interpolate(const Rect& b, double factor) const
{
  graphene_rect_t* c_interpolation = graphene_rect_alloc();
  graphene_rect_interpolate(gobj(), b.gobj(), factor, c_interpolation);
  return Rect(c_interpolation, false);
}

Rect Rect::expand(const Point& p) const
{
  graphene_rect_t* c_expansion = graphene_rect_alloc();
  graphene_rect_expand(gobj(), p.gobj(), c_expansion);
  return Rect(c_expansion, false);
}

Rect Rect::scale(float s_h, float s_v) const
{
  graphene_rect_t* c_scaled = graphene_rect_alloc();
  graphene_rect_scale(gobj(), s_h, s_v, c_scaled);
  return Rect(c_scaled, false);
}

} //namespace Graphene
} //namespace Gdk
