/* Copyright (C) 2025 The cairomm 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 <https://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <cassert>
#include <cairomm/cairomm.h>

// This program shows how to iterate through a Cairo::Path.

std::ostream& operator<<(std::ostream& out, const Cairo::Path::Element::Point& p)
{
  out << "  x: " << p.x << ", y: " << p.y << std::endl;
  return out;
}

void print_path(const Cairo::RefPtr<const Cairo::Path>& path)
{
  // A Path is a series of Path::Element items. The custom Path::const_iterator
  // calculates the size of the cairo_path_data_t internally (i.e. how many
  // points are there before the next header) so the application doesn't need to
  // calculate the length manually, it just needs to increment the const_iterator.
  // Alternatively a range-for statement: for (const auto& elt : *path)
  for (Cairo::Path::const_iterator it = path->begin(); it != path->end(); ++it)
  {
    // A Path::Element object is a collection of 0 or more Path::Element::Point
    // objects, the precise number depends on the type of data.
    const Cairo::Path::Element elt = *it;
    const Cairo::Path::ElementType data_type = elt.type();
    switch (data_type)
    {
      case Cairo::Path::ElementType::LINE_TO:
        std::cout << "LINE_TO element" << std::endl;
        assert(elt.size() == 1); // LINE_TO has 1 data point
        std::cout << elt[0];
        break;

      case Cairo::Path::ElementType::MOVE_TO:
        std::cout << "MOVE_TO element" << std::endl;
        assert(elt.size() == 1); // MOVE_TO has 1 data point
        std::cout << elt[0];
        break;

      case Cairo::Path::ElementType::CURVE_TO:
        std::cout << "CURVE_TO element" << std::endl;
        assert(elt.size() == 3); // CURVE_TO has 3 data points
        std::cout << elt[0] << elt[1] << elt[2];
        break;

      case Cairo::Path::ElementType::CLOSE_PATH:
        std::cout << "CLOSE_PATH element" << std::endl;
        assert(elt.size() == 0); // CLOSE_PATH has no data points
        break;
      default:
        break;
    }
    std::cout << std::endl;
  }
}

int main(int /* argc */, char** /* argv */)
{
  Cairo::RefPtr<Cairo::ImageSurface> surface =
    Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, 600, 400);
  Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);

  // Draw some random stuff.
  cr->move_to(10.0, 10.0);
  cr->line_to(500.0, 300.0);
  cr->curve_to(250.0, 250.0, 100.0, 100.0, 300.0, 300.0);
  cr->close_path();
  cr->rectangle(50.0, 50.0, 200.0, 150.0);
  cr->arc(300.0, 200.0, 75.0, 0.0, 1.8 * M_PI);

  std::cout << "NORMAL PATH" << std::endl
            << "===========" << std::endl;
  print_path(cr->copy_path2());

  std::cout << "FLATTENED PATH" << std::endl
            << "==============" << std::endl;
  print_path(cr->copy_path_flat2());
}
