/*  Copyright (C) 2008--2010 Joshua Judson Rosen <rozzin@geekspace.com>.

    This program is free software: you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 3 as published by the Free Software Foundation.

    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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; see the file COPYING. If not, see
    <http://www.gnu.org/licenses/> or write to:

        The Free Software Foundation, inc.
        51 Franklin Street, Fifth Floor
        Boston, MA 02110-1301
        USA
*/

#include <stdlib.h>

#include <glib/grand.h>
#include "virand/random.h"

#include <math.h>
#include <cairo.h>

#include <glib-object.h>
#include "graphics.h"
#include "figure.h"
#include "radial.h"
#include "line.h"

#include <glib.h>

struct _VisualID_FigureClass {
  VisualID_GlyphClass parent_class;
};

G_DEFINE_TYPE(VisualID_Figure, visualid_figure, VISUALID_TYPE_GLYPH)

static void
exec_figure (VisualID_Figure *figure, cairo_t *cr)
{
  double x, y;
  int i;

  cairo_get_current_point (cr, &x, &y);
  cairo_new_sub_path (cr);

  cairo_move_to (cr, 0, 0);

  cairo_save (cr);
  for (i = 0; i < 4; i++) {
    cairo_save (cr);
    if (i) {
      if (i < 3) {
        cairo_scale (cr, 1, -1);
      }
      if (i > 1) {
        cairo_scale (cr, -1, 1);
      }
    }
    cairo_rotate (cr, M_PI_4);
/*     if (i > 1) { */
/*       cairo_scale (cr, -1, 1); */
/*     } */
/*     cairo_rotate (cr, M_PI_2 * (i % 2) + M_PI_4); */
    cairo_translate (cr, 0, figure->leg_scale/2);
    cairo_scale (cr, figure->leg_scale, figure->leg_scale);
    visualid_draw_path (figure->leg, cr);
    cairo_restore (cr);
  }
  cairo_restore (cr);

  /* head */
  cairo_save (cr);
  cairo_translate (cr, 0, figure->leg_scale/2 + figure->head_scale/2); /* .5); */
  cairo_scale (cr, figure->head_scale, figure->head_scale);
  visualid_draw_path (figure->head, cr);
  cairo_restore (cr);

  if (figure->tail) {
    cairo_save (cr);
    cairo_translate (cr, 0, -figure->tail_scale /* -.3 */);
    cairo_scale (cr, figure->tail_scale, figure->tail_scale);
    visualid_draw_path (figure->tail, cr);
    cairo_restore (cr);
  }

  cairo_new_sub_path (cr);
  cairo_move_to (cr, x, y);
}

static void
figure_constructed (GObject *self)
{
  VisualID_Figure *figure = VISUALID_FIGURE (self);
  VisualID_Glyph *glyph = VISUALID_GLYPH (self);
  GObjectClass *parent_class = G_OBJECT_CLASS (visualid_figure_parent_class);

  if (parent_class->constructed) {
    parent_class->constructed (self);
  }

  g_object_new (VISUALID_TYPE_RADIAL, "parent-glyph", glyph,
                                      "parent-attachment", "head-child",
                                      NULL);
  figure->head_scale = g_rand_double_range (glyph->generator->state, 0.1, 0.2);

  g_object_new (VISUALID_TYPE_LINE, "parent-glyph", glyph,
                                    "parent-attachment", "leg-child",
                                    NULL);
  figure->leg_scale = g_rand_double_range (glyph->generator->state, 0.3, 0.6);

  if (virand_prob (glyph->generator->state, .8)) {
    g_object_new (VISUALID_TYPE_LINE, "parent-glyph", glyph,
                                      "parent-attachment", "tail-child",
                                      NULL);
    figure->tail_scale = g_rand_double_range (glyph->generator->state,
                                              0.1, 0.4);
  } else {
    figure->tail = NULL;
  }
}

static void
figure_dispose (GObject *self)
{
  VisualID_Figure *figure = VISUALID_FIGURE (self);

  if (figure->head) {
    visualid_glyph_unparent (figure->head);
    figure->head = NULL;
  }

  if (figure->leg) {
    visualid_glyph_unparent (figure->leg);
    figure->leg = NULL;
  }

  if (figure->tail) {
    visualid_glyph_unparent (figure->tail);
    figure->tail = NULL;
  }

  G_OBJECT_CLASS (visualid_figure_parent_class)->dispose (self);
}

enum {
  PROP_HEAD_CHILD = 1,
  PROP_HEAD_SCALE,

  PROP_LEG_CHILD,
  PROP_LEG_SCALE,

  PROP_TAIL_CHILD,
  PROP_TAIL_SCALE
};

static void
figure_get_property (GObject *object,
                     guint property_id,
                     GValue *value,
                     GParamSpec *pspec)
{
  VisualID_Figure *self = VISUALID_FIGURE (object);

  switch (property_id)
    {
    case PROP_HEAD_CHILD:
      g_value_set_object (value, self->head);
      break;
    case PROP_HEAD_SCALE:
      g_value_set_double (value, self->head_scale);
      break;

    case PROP_LEG_CHILD:
      g_value_set_object (value, self->leg);
      break;
    case PROP_LEG_SCALE:
      g_value_set_double (value, self->leg_scale);
      break;

    case PROP_TAIL_CHILD:
      g_value_set_object (value, self->tail);
      break;
    case PROP_TAIL_SCALE:
      g_value_set_double (value, self->tail_scale);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
figure_set_property (GObject *object,
                     guint property_id,
                     const GValue *value,
                     GParamSpec *pspec)
{
  VisualID_Figure *self = VISUALID_FIGURE (object);

  switch (property_id)
    {
    case PROP_HEAD_CHILD:
      visualid_glyph_take_child (VISUALID_GLYPH (self),
                                 g_value_get_object (value),
                                 &self->head);
      break;
    case PROP_HEAD_SCALE:
      self->head_scale = g_value_get_double (value);
      break;

    case PROP_LEG_CHILD:
      visualid_glyph_take_child (VISUALID_GLYPH (self),
                                 g_value_get_object (value),
                                 &self->leg);
      break;
    case PROP_LEG_SCALE:
      self->leg_scale = g_value_get_double (value);
      break;

    case PROP_TAIL_CHILD:
      visualid_glyph_take_child (VISUALID_GLYPH (self),
                                 g_value_get_object (value),
                                 &self->tail);
      break;
    case PROP_TAIL_SCALE:
      self->tail_scale = g_value_get_double (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static int
visualid_figure_complexity (VisualID_Figure *figure, int recurse)
{
  int complexity = 0;

  if (recurse--) {
    complexity += (visualid_glyph_complexity (figure->head, recurse) +
                   visualid_glyph_complexity (figure->leg, recurse) * 4);

    if (figure->tail) {
      complexity += visualid_glyph_complexity (figure->tail, recurse);
    }
  }

  return complexity;
}

static void
visualid_figure_class_init (VisualID_FigureClass *class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);

  VISUALID_GLYPH_CLASS (class)->produce = (producer_fn *) exec_figure;
  VISUALID_GLYPH_CLASS (class)->complexity_fn =
    (complexity_fn *) visualid_figure_complexity;

  gobject_class->get_property = figure_get_property;
  gobject_class->set_property = figure_set_property;
  gobject_class->constructed = figure_constructed;
  gobject_class->dispose = figure_dispose;

  g_object_class_install_property
    (gobject_class, PROP_HEAD_CHILD,
     g_param_spec_object ("head-child",
                          "Head child",
                          "Radial glyph to use as the figure's head",
                          VISUALID_TYPE_GLYPH,
                          G_PARAM_READWRITE));
  g_object_class_install_property
    (gobject_class, PROP_HEAD_SCALE,
     g_param_spec_double ("head-scale",
                          "Head scale",
                          "Relative scale of the head-glyph",
                          0.1, .2, .15,
                          G_PARAM_READWRITE));

  g_object_class_install_property
    (gobject_class, PROP_LEG_CHILD,
     g_param_spec_object ("leg-child",
                          "Leg child",
                          "Line-glyph to use for the figure's legs/arms",
                          VISUALID_TYPE_GLYPH,
                          G_PARAM_READWRITE));
  g_object_class_install_property
    (gobject_class, PROP_LEG_SCALE,
     g_param_spec_double ("leg-scale",
                          "Leg scale",
                          "Relative scale of the leg-glyphs",
                          .3, .6, .45,
                          G_PARAM_READWRITE));

  g_object_class_install_property
    (gobject_class, PROP_TAIL_CHILD,
     g_param_spec_object ("tail-child",
                          "Tail child",
                          "Line-glyph to use for the figure's tail, if it has one",
                          VISUALID_TYPE_GLYPH,
                          G_PARAM_READWRITE));
  g_object_class_install_property
    (gobject_class, PROP_TAIL_SCALE,
     g_param_spec_double ("tail-scale",
                          "Tail scale",
                          "Relative scale of the line-glyph used as the figure's tail, if it has one",
                          .1, .4, .25,
                          G_PARAM_READWRITE));
}

static void
visualid_figure_init (VisualID_Figure *self)
{
}
