/*$Id$
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 2003 Nick Lewycky <nicholas@fresco.org>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#include <Fresco/config.hh>
#include <Fresco/Path.hh>
#include <Fresco/Types.hh>
#include <Berlin/PathImpl.hh>

void PathImpl::move_to_point(const Vertex &v)
{
  PathSegment *s = new PathSegment();
  s->to = v;
  s->type = move;
  segments.push_back(s);
}

void PathImpl::add_line_to_point(const Vertex &v)
{
  PathSegment *s = new PathSegment();
  s->to = v;
  s->type = line;
  segments.push_back(s);
}

void PathImpl::add_lines(const Vertices &v)
{
  for (int i = 0; i < v.length(); i++)
    add_line_to_point(v[i]);
}

void PathImpl::add_curve_to_point(const Vertex &cp1, const Vertex &cp2,
                                  const Vertex &end)
{
  PathSegment *s = new PathSegment();
  s->to = end;
  s->cp1 = cp1;
  s->cp2 = cp2;
  s->type = cubic;
  segments.push_back(s);
}

void PathImpl::add_quad_curve_to_point(const Vertex &cp, const Vertex &end)
{
  PathSegment *s = new PathSegment();
  s->to = end;
  s->cp1 = cp;
  s->type = conic;
  segments.push_back(s);
}

void PathImpl::add_rect(const Vertex &upper, const Vertex &lower)
{
  Vertex corner1, corner2;
  corner1.x = upper.x; corner1.y = lower.y;
  corner2.x = lower.x; corner2.y = upper.y;
  move_to_point(upper);
  add_line_to_point(corner1);
  add_line_to_point(lower);
  add_line_to_point(corner2);
  add_line_to_point(upper);
}

void PathImpl::add_rects(const Vertices &upper, const Vertices &lower)
{
  if (upper.length() != lower.length()) return;
  for (int i = 0; i < upper.length(); i++)
    add_rect(upper[i], lower[i]);
}

void PathImpl::add_arc(const Vertex &g, CORBA::Float radius, CORBA::Float start,
                       CORBA::Float end, CORBA::Boolean clockwise)
{
  std::cerr << "PathImpl::add_arc: NYI!" << std::endl;
}

void PathImpl::add_arc_to_point(const Vertex &v1, const Vertex &v2,
                                CORBA::Float radius)
{
  std::cerr << "PathImpl::add_arc_to_point: NYI!" << std::endl;
}

CORBA::Boolean PathImpl::is_path_empty()
{
  return (segments.size() == 0);
}

Vertex PathImpl::get_current_point()
{
  if (is_path_empty()) {
    Vertex v = {0, 0, 0};
    return v;
  } else
    return segments[segments.size()-1]->to;
}

Region_ptr PathImpl::get_bounding_box()
{
  return Fresco::Region::_nil();
}

CORBA::Boolean PathImpl::contains_point(const Vertex &v)
{
  return false;
}

CORBA::Boolean PathImpl::contains_rect(const Vertex &upper, const Vertex &lower)
{
  return false;
}

CORBA::Boolean PathImpl::intersects_rect(const Vertex &upper,
                                         const Vertex &lower)
{
  return false;
}

Vertices *PathImpl::get_subpath(CORBA::ULong i)
{
  if (i >= length()) return new Vertices(0);

  Vertices_var vv = new Vertices();
  PathSegment *s = segments[i];

  switch (s->type) {
  case move:
    vv->length(1);
    vv[0] = s->to;
    break;
  case line:
    vv->length(2);
    if (i == 0) {
      Vertex v = { 0, 0, 0 };
      vv[0] = v;
    } else
      vv[0] = segments[i-1]->to;
    vv[1] = s->to;
    break;
  case conic:
    vv->length(3);
    if (i == 0) {
      Vertex v = { 0, 0, 0 };
      vv[0] = v;
    } else
      vv[0] = segments[i-1]->to;
    vv[1] = s->cp1;
    vv[2] = s->to;
    break;
  case cubic:
    vv->length(4);
    if (i == 0) {
      Vertex v = { 0, 0, 0 };
      vv[0] = v;
    } else
      vv[0] = segments[i-1]->to;
    vv[1] = s->cp1;
    vv[2] = s->cp2;
    vv[3] = s->to;
    break;
  }

  return vv._retn();
}

CORBA::ULong PathImpl::length()
{
  return segments.size();
}
