/*
 * This program 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 of the License, or (at your option) version 3.
 *
 * This program 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 the program; if not, see <http://www.gnu.org/licenses/>  
 *
 *
 * Authors:
 *		Srinivasa Ragavan <sragavan@novell.com>
 *
 * Copyright (C) 2009 Novell, Inc. (www.novell.com)
 *
 */

#include "custom-cell-renderer-hbox.h"

/* This is based mainly on GtkCellRendererProgress
 *  in GAIM, written and (c) 2002 by Sean Egan
 *  (Licensed under the GPL), which in turn is
 *  based on Gtk's GtkCellRenderer[Text|Toggle|Pixbuf]
 *  implementation by Jonathan Blandford */

/* Some boring function declarations: GObject type system stuff */

static void     custom_cell_renderer_hbox_init       (CustomCellRendererHBox      *cellprogress);

static void     custom_cell_renderer_hbox_class_init (CustomCellRendererHBoxClass *klass);

static void     custom_cell_renderer_hbox_get_property  (GObject                    *object,
                                                             guint                       param_id,
                                                             GValue                     *value,
                                                             GParamSpec                 *pspec);

static void     custom_cell_renderer_hbox_set_property  (GObject                    *object,
                                                             guint                       param_id,
                                                             const GValue               *value,
                                                             GParamSpec                 *pspec);

static void     custom_cell_renderer_hbox_finalize (GObject *gobject);


/* These functions are the heart of our custom cell renderer: */

static void     custom_cell_renderer_hbox_get_size   (GtkCellRenderer            *cell,
                                                          GtkWidget                  *widget,
                                                          GdkRectangle               *cell_area,
                                                          gint                       *x_offset,
                                                          gint                       *y_offset,
                                                          gint                       *width,
                                                          gint                       *height);

static void     custom_cell_renderer_hbox_render     (GtkCellRenderer            *cell,
                                                          GdkWindow                  *window,
                                                          GtkWidget                  *widget,
                                                          GdkRectangle               *background_area,
                                                          GdkRectangle               *cell_area,
                                                          GdkRectangle               *expose_area,
                                                          guint                       flags);


enum
{
  PROP_PERCENTAGE = 1,
};

static   gpointer parent_class;


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_get_type: here we register our type with
 *                                          the GObject type system if we
 *                                          haven't done so yet. Everything
 *                                          else is done in the callbacks.
 *
 ***************************************************************************/

GType
custom_cell_renderer_hbox_get_type (void)
{
  static GType cell_progress_type = 0;

  if (cell_progress_type == 0)
  {
    static const GTypeInfo cell_progress_info =
    {
      sizeof (CustomCellRendererHBoxClass),
      NULL,                                                     /* base_init */
      NULL,                                                     /* base_finalize */
      (GClassInitFunc) custom_cell_renderer_hbox_class_init,
      NULL,                                                     /* class_finalize */
      NULL,                                                     /* class_data */
      sizeof (CustomCellRendererHBox),
      0,                                                        /* n_preallocs */
      (GInstanceInitFunc) custom_cell_renderer_hbox_init,
    };

    /* Derive from GtkCellRenderer */
    cell_progress_type = g_type_register_static (GTK_TYPE_CELL_RENDERER,
                                                 "CustomCellRendererHBox",
                                                  &cell_progress_info,
                                                  0);
  }

  return cell_progress_type;
}


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_init: set some default properties of the
 *                                      parent (GtkCellRenderer).
 *
 ***************************************************************************/

static void
custom_cell_renderer_hbox_init (CustomCellRendererHBox *cellrendererprogress)
{
  cellrendererprogress->start_children = NULL;
  cellrendererprogress->end_children = NULL;
  GTK_CELL_RENDERER(cellrendererprogress)->mode = GTK_CELL_RENDERER_MODE_INERT;
  GTK_CELL_RENDERER(cellrendererprogress)->xpad = 2;
  GTK_CELL_RENDERER(cellrendererprogress)->ypad = 2;
}


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_class_init:
 *
 *  set up our own get_property and set_property functions, and
 *  override the parent's functions that we need to implement.
 *  And make our new "percentage" property known to the type system.
 *  If you want cells that can be activated on their own (ie. not
 *  just the whole row selected) or cells that are editable, you
 *  will need to override 'activate' and 'start_editing' as well.
 *
 ***************************************************************************/

static void
custom_cell_renderer_hbox_class_init (CustomCellRendererHBoxClass *klass)
{
  GtkCellRendererClass *cell_class   = GTK_CELL_RENDERER_CLASS(klass);
  GObjectClass         *object_class = G_OBJECT_CLASS(klass);

  parent_class           = g_type_class_peek_parent (klass);
  object_class->finalize = custom_cell_renderer_hbox_finalize;

  /* Hook up functions to set and get our
   *   custom cell renderer properties */
  object_class->get_property = custom_cell_renderer_hbox_get_property;
  object_class->set_property = custom_cell_renderer_hbox_set_property;

  /* Override the two crucial functions that are the heart
   *   of a cell renderer in the parent class */
  cell_class->get_size = custom_cell_renderer_hbox_get_size;
  cell_class->render   = custom_cell_renderer_hbox_render;

 }


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_finalize: free any resources here
 *
 ***************************************************************************/

static void
custom_cell_renderer_hbox_finalize (GObject *object)
{
/*
  CustomCellRendererHBox *cellrendererprogress = CUSTOM_CELL_RENDERER_HBOX(object);
*/

  /* Free any dynamically allocated resources here */

  (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_get_property: as it says
 *
 ***************************************************************************/

static void
custom_cell_renderer_hbox_get_property (GObject    *object,
                                            guint       param_id,
                                            GValue     *value,
                                            GParamSpec *psec)
{
  /* CustomCellRendererHBox  *cellprogress = CUSTOM_CELL_RENDERER_HBOX(object); */

  switch (param_id)
  {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec);
      break;
  }
}


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_set_property: as it says
 *
 ***************************************************************************/

static void
custom_cell_renderer_hbox_set_property (GObject      *object,
                                            guint         param_id,
                                            const GValue *value,
                                            GParamSpec   *pspec)
{
 /* CustomCellRendererHBox *cellprogress = CUSTOM_CELL_RENDERER_HBOX (object); */

  switch (param_id)
  {
      default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
      break;
  }
}

/***************************************************************************
 *
 *  custom_cell_renderer_hbox_new: return a new cell renderer instance
 *
 ***************************************************************************/

GtkCellRenderer *
custom_cell_renderer_hbox_new (void)
{
  return g_object_new(CUSTOM_TYPE_CELL_RENDERER_HBOX, NULL);
}


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_get_size: crucial - calculate the size
 *                                          of our cell, taking into account
 *                                          padding and alignment properties
 *                                          of parent.
 *
 ***************************************************************************/

void custom_cell_renderer_hbox_pack_start (GtkCellRenderer *cell, GtkCellRenderer *child, gboolean expand)
{
  CustomCellRendererHBox *cellprogress = CUSTOM_CELL_RENDERER_HBOX (cell);

  g_object_set_data ((GObject *)child, "expand-cell", GUINT_TO_POINTER(expand));
  cellprogress->start_children = g_list_prepend (cellprogress->start_children, child);
}

void custom_cell_renderer_hbox_pack_end (GtkCellRenderer *cell, GtkCellRenderer *child, gboolean expand)
{
  CustomCellRendererHBox *cellprogress = CUSTOM_CELL_RENDERER_HBOX (cell);

  g_object_set_data ((GObject *)child, "expand-cell", GUINT_TO_POINTER(expand));
  cellprogress->end_children = g_list_prepend (cellprogress->end_children, child);
}

static void
custom_cell_renderer_hbox_get_size (GtkCellRenderer *cell,
                                        GtkWidget       *widget,
                                        GdkRectangle    *cell_area,
                                        gint            *x_offset,
                                        gint            *y_offset,
                                        gint            *width,
                                        gint            *height)
{
  CustomCellRendererHBox *cellprogress = CUSTOM_CELL_RENDERER_HBOX (cell);
  gint calc_width = 0;
  gint calc_height = 0;
  gint xo = 0, yo = 0;
  GList *tmp;
  gint cx=0, cy=0, cw=0, ch=0;

  calc_width = cell->xpad;
  tmp = cellprogress->start_children;
  while (tmp) {
	  GtkCellRenderer *child = (GtkCellRenderer *) tmp->data;

	  if (ch > calc_height)
		  calc_height = ch;
	  
	  calc_width += cw+(2*child->xpad);
	  if (cx > xo)
		  xo = cx;
	  if (cy > yo)
		  yo = cy;
	  tmp = tmp->next;
  }

  tmp = cellprogress->end_children;
  while (tmp) {
	  GtkCellRenderer *child = (GtkCellRenderer *) tmp->data;
	  gtk_cell_renderer_get_size (child, widget, cell_area, &cx, &cy, &cw, &ch);
	  if (ch > calc_height)
		  calc_height = ch;

	  calc_width += cw+(2*child->xpad);
	  if (cx > xo)
		  xo = cx;
	  if (cy > yo)
		  yo = cy;
	  tmp = tmp->next;
  }
  if (width)
    *width = calc_width;

  if (height)
    *height = calc_height;

  if (cell_area)
  {
    if (x_offset)
    {
      *x_offset = MAX (xo, 0);
    }

    if (y_offset)
    {
      *y_offset = MAX (yo, 0);
    }
  }
}


/***************************************************************************
 *
 *  custom_cell_renderer_hbox_render: crucial - do the rendering.
 *
 ***************************************************************************/

#define RADIUS 8

static void
draw_rounded_rectangle (cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height)
{
  int radius = RADIUS;

  if (width < 1 || height < 1)
    return;

  /* this allows for calculating end co-ordinates */
  width--;
  height--;

  if (width < RADIUS * 2)
  {
    radius = width / 2;
  }
  else if (height < RADIUS * 2)
  {
    radius = height / 2;
  }

  cairo_line_to (cr, x, y + height - radius);
  cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI * 1.5);
  cairo_arc (cr, x + width - radius, y + radius, radius, G_PI * 1.5, 0);
  cairo_arc (cr, x + width - radius, y + height - radius, radius,  0,  G_PI * 0.5 );
  cairo_line_to (cr, x +radius , y + height);
  cairo_arc (cr, x + radius, y + height - radius, radius, G_PI * 0.5, G_PI );
  cairo_move_to (cr, x + radius, y + height );

}

static void
draw_circle  (cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height)
{
	 int radius = width ? (width/2) : 3;

  if (width < 1 || height < 1)
    return;

  /* this allows for calculating end co-ordinates */
  radius = radius - 2;
  if (radius <= 0)
	   radius = 3;
  width--;
  height--;

  if (width < RADIUS * 2)
  {
    radius = width / 2;
  }
  else if (height < RADIUS * 2)
  {
    radius = height / 2;
  }

  cairo_arc (cr, x+radius, y+(radius/1), radius, G_PI*2, 05 *G_PI);
}

static void
custom_cell_renderer_hbox_render (GtkCellRenderer *cell,
                                      GdkWindow       *window,
                                      GtkWidget       *widget,
                                      GdkRectangle    *background_area,
                                      GdkRectangle    *cell_area,
                                      GdkRectangle    *expose_area,
                                      guint            flags)
{
  CustomCellRendererHBox *cellprogress = CUSTOM_CELL_RENDERER_HBOX (cell);
  gint                        width, height;
  gint                        x_offset, y_offset;
  GList *tmp;
  int max_width=0;
  
  custom_cell_renderer_hbox_get_size (cell, widget, cell_area,
                                          &x_offset, &y_offset,
                                          &width, &height);
  tmp =  cellprogress->end_children;
  while(tmp) {
	  GtkCellRenderer *child = (GtkCellRenderer *)tmp->data;
	  gint cx, cy, cw, ch;
	
	  gtk_cell_renderer_get_size (child, widget, cell_area, &cx, &cy, &cw, &ch);
	  if (max_width < cw)
		   max_width = cw;
	  tmp = tmp->next;

  }

  tmp =  cellprogress->start_children;
  cell_area->x = (cell_area->x /2) + cell->xpad+10 ;
  cell_area->width = cell_area->width - max_width - cell->xpad;
  while(tmp) {
	  GtkCellRenderer *child = (GtkCellRenderer *)tmp->data;
	  gint cx, cy, cw, ch;

	  gtk_cell_renderer_get_size (child, widget, cell_area, &cx, &cy, &cw, &ch);
	  if (GTK_IS_CELL_RENDERER_TOGGLE(child)) {
		   gboolean state;
		   cairo_t *cr;
		   extern GdkColor *pcolor_sel;
		   cr = gdk_cairo_create (window);
		   gdk_cairo_set_source_color (cr,  pcolor_sel);
		   
		   g_object_get (child, "active", &state, NULL);
		   if (state){
				draw_circle (cr, cell_area->x+cell->xpad, cell_area->y+(cy)+(1.5*cell->ypad), cw, ch);
				cairo_fill(cr);
				cell_area->x += cw + (child->xpad);
		   }
		   cairo_destroy (cr);
	  } else {
		   gtk_cell_renderer_render (child, window, widget, background_area, cell_area, expose_area, flags);
		   cell_area->x += cw + (2* child->xpad);
	  }
	  
	  tmp = tmp->next;
  }
  cell_area->width += max_width+cell->xpad;
  tmp =  cellprogress->end_children;  
  cell_area->x = cell_area->width + (cell->xpad);
  while(tmp) {
	  GtkCellRenderer *child = (GtkCellRenderer *)tmp->data;
	  gint cx, cy, cw, ch;
	  cairo_t *cr;
	  gboolean custom = GPOINTER_TO_INT(g_object_get_data ((GObject *)child, "p-custom"));
	  
	  gtk_cell_renderer_get_size (child, widget, cell_area, &cx, &cy, &cw, &ch);
	  cell_area->x  =  cell_area->x - cw - (child->xpad) -cx;
	  if (custom && cw >20) {
		   GdkColor col;

		   /* Color code received from the wireframe */
		   gdk_color_parse ("#febf00", &col);	
		   cr = gdk_cairo_create (window);
		   gdk_cairo_set_source_color (cr,  &col);
		   draw_rounded_rectangle (cr, cell_area->x, cell_area->y+cy+(1*cell->ypad), cw, ch);
		   cairo_fill(cr);
		   gtk_cell_renderer_render (child, window, widget, background_area, cell_area, expose_area, flags);
		   cairo_destroy (cr);
	  } else
		   gtk_cell_renderer_render (child, window, widget, background_area, cell_area, expose_area, flags);
	  cell_area->x += cx;
	  tmp = tmp->next;
  }
}


