/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* This file is part of the GtkHTML library.
 *
 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
 * Copyright (C) 1997 Torben Weis (weis@kde.org)
 * Copyright (C) 2000 Helix Code, Inc.
 *
 * 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; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include <config.h>
#include <glib/gi18n-lib.h>
#include "htmlcolor.h"
#include "htmlcolorset.h"
#include "htmlengine-save.h"
#include "htmlenumutils.h"
#include "htmlrule.h"
#include "htmlpainter.h"
#include "htmlsettings.h"
#include "gtkhtml.h"


HTMLRuleClass html_rule_class;
static HTMLObjectClass *parent_class = NULL;


/* HTMLObject methods.  */

#define HTML_RULE_MIN_SIZE 12

static void
copy (HTMLObject *self,
      HTMLObject *dest)
{
	(* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest);

	HTML_RULE (dest)->length = HTML_RULE (self)->length;
	HTML_RULE (dest)->size   = HTML_RULE (self)->size;
	HTML_RULE (dest)->shade  = HTML_RULE (self)->shade;
	HTML_RULE (dest)->halign = HTML_RULE (self)->halign;
}

static void
set_max_width (HTMLObject *o,
               HTMLPainter *painter,
               gint max_width)
{
	o->max_width = max_width;
}

static gint
calc_min_width (HTMLObject *o,
                HTMLPainter *painter)
{
	gint pixel_size;

	pixel_size = html_painter_get_pixel_size (painter);

	if (HTML_RULE (o)->length > 0)
		return HTML_RULE (o)->length * pixel_size;

	return pixel_size;
}

static HTMLFitType
fit_line (HTMLObject *o,
          HTMLPainter *painter,
          gboolean start_of_line,
          gboolean first_run,
          gboolean next_to_floating,
          gint width_left)
{
	if (!start_of_line)
		return HTML_FIT_NONE;
	o->width = MIN (width_left, o->max_width);

	if (o->percent == 0) {
		gint pixel_size = html_painter_get_pixel_size (painter);
		if (HTML_RULE (o)->length * pixel_size < width_left) {
			o->width = HTML_RULE (o)->length * pixel_size;
		} else
			o->width = width_left;
	}

	return (next_to_floating && width_left <= 0) ? HTML_FIT_NONE : HTML_FIT_COMPLETE;
}

static gboolean
html_rule_real_calc_size (HTMLObject *self,
                          HTMLPainter *painter,
                          GList **changed_objs)
{
	HTMLRule *rule;
	gint ascent, descent;
	gint pixel_size;
	gint height;
	gboolean changed;

	rule = HTML_RULE (self);
	pixel_size = html_painter_get_pixel_size (painter);

	if (rule->size >= HTML_RULE_MIN_SIZE) {
		height = rule->size;
	} else {
		height = HTML_RULE_MIN_SIZE;
	}

	ascent = (height / 2 + height % 2 + 1) * pixel_size;
	descent = (height / 2 + 1) * pixel_size;

	changed = FALSE;

	if (self->width > self->max_width) {
		self->width = self->max_width;
		changed = TRUE;
	}

	if (ascent != self->ascent) {
		self->ascent = ascent;
		changed = TRUE;
	}

	if (descent != self->descent) {
		self->descent = descent;
		changed = TRUE;
	}

	return changed;
}

static void
html_rule_draw (HTMLObject *o,
      HTMLPainter *p,
      gint x,
                gint y,
      gint width,
                gint height,
      gint tx,
                gint ty)
{
	HTMLRule *rule;
	guint w, h;
	gint xp, yp;
	gint pixel_size = html_painter_get_pixel_size (p);
	HTMLEngine *e;

	if (p->widget && GTK_IS_HTML (p->widget))
		e = html_object_engine (o, GTK_HTML (p->widget)->engine);
	else
		return;

	rule = HTML_RULE (o);

	if (y + height < o->y - o->ascent || y > o->y + o->descent)
		return;

	h = rule->size * pixel_size;
	xp = o->x + tx;
	yp = o->y + ty - (rule->size / 2 + rule->size % 2) * pixel_size;

	if (o->percent == 0)
		w = o->width;
	else
		/* The cast to `gdouble' is to avoid overflow (eg. when
		 * printing).  */
		w = ((gdouble) o->width * o->percent) / 100;

	switch (rule->halign) {
	case HTML_HALIGN_LEFT:
		break;
	case HTML_HALIGN_CENTER:
	case HTML_HALIGN_NONE:
		/* Default is `align=center' according to the specs.  */
		xp += (o->width - w) / 2;
		break;
	case HTML_HALIGN_RIGHT:
		xp += o->width - w;
		break;
	default:
		g_warning ("Unknown HTMLRule alignment %d.", rule->halign);
	}

	if (rule->shade)
		html_painter_draw_border (p,
					  &((html_colorset_get_color (e->settings->color_set, HTMLBgColor))->color),
					  xp, yp, w, h, HTML_BORDER_INSET, 1);
	else {
		html_painter_set_pen (p, &html_colorset_get_color_allocated (e->settings->color_set, p,
									     HTMLTextColor)->color);
		html_painter_fill_rect (p, xp, yp, w, h);
	}
}

static gboolean
accepts_cursor (HTMLObject *self)
{
	return TRUE;
}

static gboolean
save (HTMLObject *self,
      HTMLEngineSaveState *state)
{
	gchar *size;
	const gchar *shade;
	gchar *align;
	gchar *length;
	gboolean rv;

	size   = HTML_RULE (self)->size == 2 ? g_strdup ("") : g_strdup_printf (" SIZE=\"%d\"", HTML_RULE (self)->size);
	shade  = HTML_RULE (self)->shade ? "" : " NOSHADE";
	length = HTML_RULE (self)->length
		? g_strdup_printf (" LENGTH=\"%d\"", HTML_RULE (self)->length)
		: (self->percent > 0 && self->percent != 100 ? g_strdup_printf (" LENGTH=\"%d%%\"", self->percent) : g_strdup (""));
	align = g_strdup_printf (" ALIGN=\"%s\"", html_halign_name (HTML_RULE (self)->halign));

	rv = html_engine_save_output_string (state, "\n<HR%s%s%s%s>\n", shade, size, length, align);

	g_free (align);
	g_free (length);
	g_free (size);

	return rv;
}

static gboolean
save_plain (HTMLObject *self,
            HTMLEngineSaveState *state,
            gint requested_width)
{
	gint i;

	if (!html_engine_save_output_string (state, "\n"))
		return FALSE;

	/* Fixme no alignment or percent */
	for (i = 0; i < requested_width; i++)
		if (!html_engine_save_output_string (state, "_"))
			return FALSE;

	if (!html_engine_save_output_string (state, "\n"))
		return FALSE;

	return TRUE;
}

void
html_rule_type_init (void)
{
	html_rule_class_init (&html_rule_class, HTML_TYPE_RULE, sizeof (HTMLRule));
}

void
html_rule_class_init (HTMLRuleClass *klass,
                      HTMLType type,
                      guint object_size)
{
	HTMLObjectClass *object_class;

	object_class = HTML_OBJECT_CLASS (klass);

	html_object_class_init (object_class, type, object_size);

	object_class->copy = copy;
	object_class->draw = html_rule_draw;
	object_class->set_max_width = set_max_width;
	object_class->calc_min_width = calc_min_width;
	object_class->fit_line = fit_line;
	object_class->calc_size = html_rule_real_calc_size;
	object_class->accepts_cursor = accepts_cursor;
	object_class->save = save;
	object_class->save_plain = save_plain;

	parent_class = &html_object_class;
}

void
html_rule_init (HTMLRule *rule,
                HTMLRuleClass *klass,
                gint length,
                gint percent,
                gint size,
                gboolean shade,
                HTMLHAlignType halign)
{
	HTMLObject *object;

	object = HTML_OBJECT (rule);

	html_object_init (object, HTML_OBJECT_CLASS (klass));

	if (size < 1)
		size = 1;	/* FIXME why? */
	rule->size = size;

	object->percent = percent;

	rule->length = length;
	rule->shade  = shade;
	rule->halign = halign;

	if (percent > 0) {
		object->flags &= ~ HTML_OBJECT_FLAG_FIXEDWIDTH;
		rule->length = 0;
	} else if (rule->length > 0) {
		object->flags |= HTML_OBJECT_FLAG_FIXEDWIDTH;
	} else {
		object->flags &= ~ HTML_OBJECT_FLAG_FIXEDWIDTH;
	}
}

HTMLObject *
html_rule_new (gint length,
               gint percent,
               gint size,
               gboolean shade,
               HTMLHAlignType halign)
{
	HTMLRule *rule;

	rule = g_new (HTMLRule, 1);
	html_rule_init (rule, &html_rule_class, length, percent,
			size, shade, halign);

	return HTML_OBJECT (rule);
}

