/*  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 Lesser General Public License
    as published by the Free Software Foundation, either version 3
    of the License, or (at your option) any later version..

    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 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 <math.h>

#include <cairo.h>
#include <cairo-svg.h>

#include <stdlib.h>

#include "paths.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glib.h>

#include "virand/random.h"
#include <popt.h>

#include <glib-object.h>
#include "graphics.h"
#include "radial.h"
#include "figure.h"
#include "shape.h"
#include "path.h"
#include "line.h"
#include "symmetry.h"
#include "spiral.h"

#include <assert.h>

struct generator_config {
  char *name;
  GType glyph_type;
  int *weight_var;
  int top;
};

int
main (int argc, const char **argv)
{
  int autocache = 0;
  const char *cachedir = visualid_cachedir ();

  /* default weights (relative probabilities): */
  int base_weight = 1;

  int enable_radial = -1;
/*   int enable_faces = -1; */
  int enable_figure = -1;
  int enable_shape = -1;
  int enable_path = -1;
  int enable_line = -1;
  int enable_symmetry = -1;
  int enable_spiral = -1;

  double width=72, height=72;
  double linewidth = .03;
  double outline_width = .015;

  const char *name;
  char *output_file = NULL;
  char *glyph_file = NULL;
  cairo_surface_t *output;
  cairo_t *cr;

  VisualID_Generator *generator;
  VisualID_Glyph *glyph = NULL;

  struct poptOption cmd_options[] = {
    {"autocache", 0,
     POPT_ARG_VAL,
     &autocache, 1,
     "automatically search for base-IDs in the cache, " \
     "and write the new ID into the cache", NULL},
    {"cache", 0,
     POPT_ARG_VAL | POPT_ARGFLAG_DOC_HIDDEN,
     &autocache, 1,
     NULL, NULL},

    {"autocache-dir", 0,
     POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
     &cachedir, 0,
     "Directory where VisualIDs are autocached", "DIRECTORY"},
    {"cachedir", 0,
     POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN,
     &cachedir, 0,
     NULL, NULL},


    {"output", 'o', POPT_ARG_STRING, &output_file, 0,
     "write output to this (SVG) file", "FILEPATH"},

    {"width", 'w', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT,
     &width, 0,
     "width of output image", NULL},
    {"height", 'h', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT,
     &height, 0,
     "height of output image", NULL},
    {"linewidth", 'L', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT,
     &linewidth, 0,
     "line-width", NULL},
    {"outline-width", 'O', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT,
     &outline_width, 0,
     "outline-width", NULL},

    {"base-weight", '_', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT,
     &base_weight, 1,
     "default weight for unspecified generators", NULL},
    {"radial", 'r', POPT_ARG_INT, &enable_radial, 1,
     "enable radial-generator w/ given probability-weight", NULL},
    {"figure", 'f', POPT_ARG_INT, &enable_figure, 1,
     "enable figure-generator w/ given probability-weight", NULL},
    {"shape", 's', POPT_ARG_INT, &enable_shape, 1,
     "enable shape-generator w/ given probability-weight", NULL},
    {"path", 'p', POPT_ARG_INT, &enable_path, 1,
     "enable path-generator w/ given probability-weight", NULL},
    {"line", 'l', POPT_ARG_INT, &enable_line, 1,
     "enable line-generator w/ given probability-weight", NULL},
    {"symmetry", 'y', POPT_ARG_INT, &enable_symmetry, 1,
     "enable symmetry-generator w/ given probability-weight", NULL},
    {"spiral", 'i', POPT_ARG_INT, &enable_spiral, 1,
     "enable spiral-generator w/ given probability-weight", NULL},

    POPT_AUTOHELP
    POPT_TABLEEND
  };

  int opt;

  poptContext optCon = poptGetContext (NULL, argc, argv, cmd_options, 0);
  poptSetOtherOptionHelp (optCon, "[OPTION...] <input-name>");

  while ((opt = poptGetNextOpt (optCon)) >= 0) {
    switch (opt) {
    }
    /* No specific actions--just set variables and handle "--help" */
  }

  if (opt < -1) {
    fprintf (stderr, "Error parsing argument %s: %s.\n",
             poptBadOption (optCon, 0), poptStrerror (opt));
    exit (1);
  }

  name = poptGetArg (optCon);
  if (name == NULL) {
    fprintf (stderr, "mkvisualid requires a string\
 for which to generate a VisualID.\n");
    exit (1);
  }

  if (cachedir) {
    visualid_set_cachedir (cachedir);
  }

  if (autocache) {
    struct stat statbuf;
    glyph_file = visualid_path_for_file (name);

    if (stat (glyph_file, &statbuf) == 0) {
      printf ("\"%s\" already exists in cache.\n", name);
      goto have_cached_glyph;
    } else {
      double score;
      char *base_filename = visualid_base_for_file (name, &score);

      if (base_filename) {
        char *base_path = g_strdup_printf ("%s/%s", visualid_cachedir (),
                                                    base_filename);
        link (base_path, glyph_file);
        goto have_cached_glyph;
      }
    }
  } else if (output_file) {
    glyph_file = output_file;
    output_file = NULL;
  } else {
    fprintf (stderr, "No output-file specified.\n\
Either specifiy one with --output, use --autocache, or do both.\n");
    exit (1);
  }

  printf ("visualid for %s = %s\n", name, glyph_file);

  output = cairo_svg_surface_create (glyph_file, width, height);
  cr = cairo_create (output);

  g_type_init ();

  generator = g_object_new (VISUALID_TYPE_GENERATOR, NULL);
  g_object_set (generator->roots,
                "default-item-weight", base_weight,
                NULL);
  virand_generator_set_weights
    (generator->roots,
     (gpointer) VISUALID_TYPE_RADIAL, enable_radial,
     (gpointer) VISUALID_TYPE_FIGURE, enable_figure,
     (gpointer) VISUALID_TYPE_SHAPE, enable_shape,
     (gpointer) VISUALID_TYPE_PATH, enable_path,
     (gpointer) VISUALID_TYPE_LINE, enable_line,
     (gpointer) VISUALID_TYPE_SYMMETRY, enable_symmetry,
     (gpointer) VISUALID_TYPE_SPIRAL, enable_spiral,
     NULL);

  {
    virand_set_seed_string (generator->state,
                            name, strlen (name));
  }

  glyph = visualid_glyph_new (generator);

  if (glyph == NULL) {
    fprintf (stderr, "constraints eliminated all generators.\n");
    exit (1);
  }

  cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
  cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);

  visualid_draw (glyph, cr, width, height, linewidth + outline_width*2);

  cairo_scale (cr, width/2, height/2);

  cairo_set_line_width (cr, linewidth + outline_width*2);
  cairo_set_source_rgb (cr, 1, 1, 1);
  cairo_stroke_preserve (cr);

  cairo_set_line_width (cr, linewidth);
  cairo_set_source_rgb (cr, 0, 0, 0);
  cairo_stroke (cr);

  cairo_destroy (cr);
  cairo_surface_destroy (output);

  have_cached_glyph:

  if (output_file) {
    if (g_file_test (output_file, G_FILE_TEST_IS_DIR))
    {
      char *output_basename = g_strdup_printf ("%s.svg", name);
      output_file = g_build_filename (output_file, output_basename, NULL);
      g_free (output_basename);
    }

    unlink (output_file);
    link (glyph_file, output_file);
  }

  return 0;
}

