/*
 *  cairo-markup-path.c
 *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
 *
 *  This file is part of gLabels.
 *
 *  gLabels is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  gLabels 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include "cairo-markup-path.h"

#include <math.h>

#include "cairo-ellipse-path.h"

#include "debug.h"


/*===========================================*/
/* Private types                             */
/*===========================================*/


/*===========================================*/
/* Private globals                           */
/*===========================================*/


/*===========================================*/
/* Local function prototypes                 */
/*===========================================*/

static void       gl_cairo_markup_margin_path         (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup,
                                                       glLabel                 *label);

static void       gl_cairo_markup_margin_rect_path    (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup,
                                                       glLabel                 *label);

static void       gl_cairo_markup_margin_ellipse_path (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup,
                                                       glLabel                 *label);

static void       gl_cairo_markup_margin_round_path   (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup,
                                                       glLabel                 *label);

static void       gl_cairo_markup_margin_cd_path      (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup,
                                                       glLabel                 *label);

static void       gl_cairo_markup_line_path           (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup);

static void       gl_cairo_markup_circle_path         (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup);

static void       gl_cairo_markup_rect_path           (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup);

static void       gl_cairo_markup_ellipse_path        (cairo_t                 *cr,
                                                       const lglTemplateMarkup *markup);


/*--------------------------------------------------------------------------*/
/* Create markup path                                                       */
/*--------------------------------------------------------------------------*/
void
gl_cairo_markup_path (cairo_t                 *cr,
                      const lglTemplateMarkup *markup,
                      glLabel                 *label)
{
        gl_debug (DEBUG_PATH, "START");

        switch (markup->type) {
        case LGL_TEMPLATE_MARKUP_MARGIN:
                gl_cairo_markup_margin_path (cr, markup, label);
                break;
        case LGL_TEMPLATE_MARKUP_LINE:
                gl_cairo_markup_line_path (cr, markup);
                break;
        case LGL_TEMPLATE_MARKUP_CIRCLE:
                gl_cairo_markup_circle_path (cr, markup);
                break;
        case LGL_TEMPLATE_MARKUP_RECT:
                gl_cairo_markup_rect_path (cr, markup);
                break;
        case LGL_TEMPLATE_MARKUP_ELLIPSE:
                gl_cairo_markup_ellipse_path (cr, markup);
                break;
        default:
                g_message ("Unknown template markup type");
                break;
        }

        gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw margin markup.                                             */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_margin_path (cairo_t                *cr,
                             const lglTemplateMarkup *markup,
                             glLabel                *label)
{
	const lglTemplate      *template;
	const lglTemplateFrame *frame;

        gl_debug (DEBUG_PATH, "START");

        template = gl_label_get_template (label);
        frame = (lglTemplateFrame *)template->frames->data;

        switch (frame->shape) {

        case LGL_TEMPLATE_FRAME_SHAPE_RECT:
                gl_cairo_markup_margin_rect_path (cr, markup, label);
                break;

        case LGL_TEMPLATE_FRAME_SHAPE_ELLIPSE:
                gl_cairo_markup_margin_ellipse_path (cr, markup, label);
                break;

        case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
                gl_cairo_markup_margin_round_path (cr, markup, label);
                break;

        case LGL_TEMPLATE_FRAME_SHAPE_CD:
                gl_cairo_markup_margin_cd_path (cr, markup, label);
                break;

        default:
                g_message ("Unknown template label style");
                break;
        }

        gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw simple recangular margin.                                  */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_margin_rect_path (cairo_t                 *cr,
                                  const lglTemplateMarkup *markup,
                                  glLabel                 *label)
{
        const lglTemplate      *template;
        const lglTemplateFrame *frame;
        gdouble                 w, h, r, m;

        gl_debug (DEBUG_PATH, "START");

        template = gl_label_get_template (label);
        frame = (lglTemplateFrame *)template->frames->data;

        m = markup->margin.size;

        lgl_template_frame_get_size (frame, &w, &h);
	w = w - 2*m;
	h = h - 2*m;
        r = MAX (frame->rect.r - m, 0.0);

        if ( r == 0.0 )
        {
                cairo_rectangle (cr, m, m, w, h);
        }
        else
        {
                cairo_new_path (cr);
                cairo_arc_negative (cr, m+r,   m+r,   r, 3*G_PI/2, G_PI);
                cairo_arc_negative (cr, m+r,   m+h-r, r, G_PI,     G_PI/2);
                cairo_arc_negative (cr, m+w-r, m+h-r, r, G_PI/2,   0.);
                cairo_arc_negative (cr, m+w-r, m+r,   r, 2*G_PI,   3*G_PI/2);
                cairo_close_path (cr);
        }

        gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw elliptical margin.                                         */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_margin_ellipse_path (cairo_t                 *cr,
                                     const lglTemplateMarkup *markup,
                                     glLabel                 *label)
{
        const lglTemplate      *template;
        const lglTemplateFrame *frame;
        gdouble                 w, h, m;

        gl_debug (DEBUG_PATH, "START");

        template = gl_label_get_template (label);
        frame = (lglTemplateFrame *)template->frames->data;

        m = markup->margin.size;

        lgl_template_frame_get_size (frame, &w, &h);
	w = w - 2*m;
	h = h - 2*m;

        cairo_save (cr);
        cairo_translate (cr, m, m);
        gl_cairo_ellipse_path (cr, w/2.0, h/2.0);
        cairo_restore (cr);

        gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw round margin.                                              */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_margin_round_path (cairo_t                 *cr,
                                   const lglTemplateMarkup *markup,
                                   glLabel                 *label)
{
	const lglTemplate      *template;
	const lglTemplateFrame *frame;
	gdouble                 r, m;

	gl_debug (DEBUG_PATH, "START");

        template = gl_label_get_template (label);
        frame = (lglTemplateFrame *)template->frames->data;

	r = frame->round.r;
	m = markup->margin.size;

        cairo_arc (cr, r, r, r-m, 0, 2*G_PI);
        cairo_close_path (cr);

	gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw CD margins.                                                */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_margin_cd_path (cairo_t                 *cr,
                                const lglTemplateMarkup *markup,
                                glLabel                 *label)
{
	const lglTemplate      *template;
	const lglTemplateFrame *frame;
	gdouble                 m, r1, r2;
	gdouble                 theta1, theta2;
	gdouble                 xc, yc;
	gdouble                 w, h;

	gl_debug (DEBUG_PATH, "START");

        template = gl_label_get_template (label);
        frame = (lglTemplateFrame *)template->frames->data;

        lgl_template_frame_get_size (frame, &w, &h);
        xc = w/2.0;
        yc = h/2.0;

	m  = markup->margin.size;
        r1 = frame->cd.r1 - m;
        r2 = frame->cd.r2 + m;


        /*
         * Outer path (may be clipped)
         */
        theta1 = acos ((w-2*m) / (2.0*r1));
        theta2 = asin ((h-2*m) / (2.0*r1));

        cairo_new_path (cr);
        cairo_arc (cr, xc, yc, r1, theta1, theta2);
        cairo_arc (cr, xc, yc, r1, G_PI-theta2, G_PI-theta1);
        cairo_arc (cr, xc, yc, r1, G_PI+theta1, G_PI+theta2);
        cairo_arc (cr, xc, yc, r1, 2*G_PI-theta2, 2*G_PI-theta1);
        cairo_close_path (cr);


        /* Inner path (hole) */
        cairo_new_sub_path (cr);
        cairo_arc (cr, xc, yc, r2, 0.0, 2*G_PI);
        cairo_close_path (cr);

	gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw line markup.                                               */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_line_path (cairo_t                 *cr,
                           const lglTemplateMarkup *markup)
{
	gl_debug (DEBUG_PATH, "START");

        cairo_move_to (cr, markup->line.x1, markup->line.y1);
        cairo_line_to (cr, markup->line.x2, markup->line.y2);

	gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw circle markup.                                             */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_circle_path (cairo_t                 *cr,
                             const lglTemplateMarkup *markup)
{
	gl_debug (DEBUG_PATH, "START");

        cairo_arc (cr,
                   markup->circle.x0, markup->circle.y0,
                   markup->circle.r,
                   0.0, 2*G_PI);
        cairo_close_path (cr);

	gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw rect markup.                                               */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_rect_path (cairo_t                 *cr,
                           const lglTemplateMarkup *markup)
{
        gdouble x1 = markup->rect.x1;
        gdouble y1 = markup->rect.y1;
        gdouble w  = markup->rect.w;
        gdouble h  = markup->rect.h;
        gdouble r  = markup->rect.r;

	gl_debug (DEBUG_PATH, "START");

        if ( r == 0.0 )
        {
                cairo_rectangle (cr, x1, y1, w, h);
        }
        else
        {
                cairo_new_path (cr);
                cairo_arc_negative (cr, x1+r,   y1+r,   r, 3*G_PI/2, G_PI);
                cairo_arc_negative (cr, x1+r,   y1+h-r, r, G_PI,     G_PI/2);
                cairo_arc_negative (cr, x1+w-r, y1+h-r, r, G_PI/2,   0.);
                cairo_arc_negative (cr, x1+w-r, y1+r,   r, 2*G_PI,   3*G_PI/2);
                cairo_close_path (cr);
        }

	gl_debug (DEBUG_PATH, "END");
}


/*---------------------------------------------------------------------------*/
/* PRIVATE.  Draw ellipse markup.                                            */
/*---------------------------------------------------------------------------*/
static void
gl_cairo_markup_ellipse_path (cairo_t                 *cr,
                              const lglTemplateMarkup *markup)
{
        gdouble x1 = markup->ellipse.x1;
        gdouble y1 = markup->ellipse.y1;
        gdouble w  = markup->ellipse.w;
        gdouble h  = markup->ellipse.h;

	gl_debug (DEBUG_PATH, "START");

        cairo_save (cr);
        cairo_translate (cr, x1, y1);
        gl_cairo_ellipse_path (cr, w/2.0, h/2.0);
        cairo_restore (cr);

	gl_debug (DEBUG_PATH, "END");
}



/*
 * Local Variables:       -- emacs
 * mode: C                -- emacs
 * c-basic-offset: 8      -- emacs
 * tab-width: 8           -- emacs
 * indent-tabs-mode: nil  -- emacs
 * End:                   -- emacs
 */
