/*
 * EasyChem
 * A program for creating and editing molecular formulas.
 *
 * Copyright (C) 2003, 2004, 2005 François-Xavier Coudert
 * 
 * Distributed under the General Public Licence (GPL).
 * See file COPYING in the source distribution for more details.
 *
 */

#define _XOPEN_SOURCE 600
#include <fcntl.h>

#ifdef UNIX
#include <sys/wait.h>
#endif

#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <gtk/gtk.h>

#include "common.h"
#include "export.h"
#include "auxi.h"
#include "bonds.h"

/* Here are the compile-time settings and limits. */
#define LIMIT_SMALL     5
#define FIG_LENGTH	300
#define EPS_LENGTH	18

/* Some macros that helps keeping the code clean. */
#define IS_SMALL(a) ((a) < LIMIT_SMALL && (a) > -LIMIT_SMALL)
#define IS_BETWEEN(a,b,c) ((a) <= (b) && (b) <= (c))
#define MAX4(a,b,c,d) (MAX ((a), MAX ((b), MAX ((c),(d)))))
#define MIN4(a,b,c,d) (MIN ((a), MIN ((b), MIN ((c),(d)))))

#define N_GREEK 48
const unsigned int greek_len[N_GREEK] = { 5, 4, 5, 5, 7, 4, 3, 5,
  4, 5, 6, 2, 2, 2, 7, 2, 3, 5, 3, 7, 3, 3, 3, 5, 5, 4, 5, 5,
  7, 4, 3, 5, 4, 5, 6, 2, 2, 2, 7, 2, 3, 5, 3, 7, 3, 3, 3, 5
};
const char greek[N_GREEK][7] = { "alpha", "beta", "gamma", "delta",
  "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu",
  "nu", "xi", "omicron", "pi", "rho", "sigma", "tau", "upsilon", "phi",
  "chi", "psi", "omega", "Alpha", "Beta", "Gamma", "Delta", "Epsilon",
  "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi",
  "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi",
  "Psi", "Omega"
};
const int greek_symbol[N_GREEK] = { 97, 98, 103, 100, 101, 122, 104, 113,
  105, 107, 108, 109, 110, 120, 111, 112, 114, 115, 116, 117, 106, 99,
  121, 119, 65, 66, 71, 68, 69, 90, 72, 81, 73, 75, 76, 77, 78, 88,
  79, 80, 82, 83, 84, 85, 70, 67, 89, 87
};
const int greek_latex[N_GREEK] = { 1, 2, 3, 4, 24, 6, 7, 8, 9, 10, 11, 12,
  13, 14, 111, 15, 16, 17, 18, 19, 20, 21, 22, 23, 65, 66, 128, 129, 69,
  90, 72, 130, 73, 75, 131, 77, 78, 132, 79, 133, 80, 134, 84, 135, 136,
  88, 137, 138
};

#define N_NATURAL 8
const unsigned int natural_len[N_NATURAL] = { 2, 2, 2, 2, 4, 2, 2, 1 };
const char natural[N_NATURAL][4] = { "oe", "OE", "ae", "AE", "euro", "TM",
  "ss", "-"
};
const char natural_symbol[N_NATURAL][5] = { "\\200", "\\201", "æ",
  "Æ", "\\177", "TM", "ß", "-"
};
const int natural_latex[N_NATURAL] = { 141, 142, 230, 198, 32, 32, 223,
  127
};


#define FONT_R	1
#define FONT_I	2
#define FONT_B	4
int
fonts_used (struct Bond *list)
{
  int fonts = 0;
  struct Bond *current = list;

  while (current != NULL)
  {
    if (current->type == BOND_GROUP)
      fonts |= fonts_used (current->group_members);
    if (BOND_HAS_TEXT (current))
    {
      fonts |= FONT_R;
      if (g_strrstr (current->text, "\\emph") != NULL)
	fonts |= FONT_I;
      if (g_strrstr (current->text, "\\textbf") != NULL)
	fonts |= FONT_B;
    }
    
    current = current->next;
  }

  return fonts;
}

/* Here is a list of characters still missing to get a satisfying
 * Unicode support:
 *    - LATIN SMALL LETTER D WITH STROKE (and capital)
 *    - LATIN SMALL LETTER H WITH STROKE (and capital)
 *    - LATIN SMALL LETTER L WITH MIDDLE DOT (and capital)
 *    - LATIN SMALL LETTER L WITH STROKE (and capital)
 *    - LATIN SMALL LETTER L WITH CARON (and capital)
 *    - LATIN SMALL LETTER N WITH LEFT HOOK
 *    - LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
 *    - LATIN SMALL LETTER THORN 
 *    - LATIN CAPITAL LETTER ENG (and small)
 *    - LATIN SMALL LIGATURE IJ (and capital)
 *
 * Those are implemented but not satisfying:
 *    - LATIN CAPITAL LETTER G WITH CEDILLA (small letter != capital)
 *    - LATIN SMALL LETTER G WITH CEDILLA (small letter != capital)
 * 
 * Those have lesser priority:
 *    - LATIN SMALL LETTER A WITH OGONEK (and capital)
 *    - LATIN SMALL LETTER E WITH OGONEK (and capital)
 *    - LATIN SMALL LETTER I WITH OGONEK (not dotless i!! -- and capital)
 *    - LATIN SMALL LETTER U WITH OGONEK
 *    - LATIN SMALL LETTER SCHWA (and capital)
 *    - LATIN SMALL LETTER OPEN E
 *    - LATIN SMALL LETTER OPEN O
 *    - LATIN SMALL LETTER GAMMA
 *    - LATIN SMALL LETTER ETH (and capital)
 *    - LATIN SMALL LETTER KRA
 *    - feminine and masculine ordinal indicators
 *
 * Following characters do not appear to be in Unicode:
 *    - LATIN SMALL LETTER O WITH CEDILLA (and capital)
 *    - LATIN SMALL LETTER G WITH TILDE
 *    - LATIN SMALL LETTER M WITH CEDILLA (and capital)
 *    - LATIN SMALL LETTER M WITH MACRON (and capital)
 *    - LATIN SMALL LETTER N WITH DIAERESIS
 *    - LATIN SMALL LETTER N WITH MACRON (and capital)
 *    - LATIN SMALL LETTER P WITH MACRON (and capital)
 *
 */

#define N_ACCENT 188
const gchar accent[N_ACCENT][8] = {
/* accented vowels */
  "à", "á", "â", "ã", "ä", "ā", "ȧ", "ă", "å", "ǎ",
  "è", "é", "ê", "ẽ", "ë", "ē", "ė", "ĕ",      "ě",
  "ì", "í", "î", "ĩ", "ï", "ī", "ı", "ĭ",      "ǐ",
  "ò", "ó", "ô", "õ", "ö", "ō", "ȯ", "ŏ",      "ǒ",
  "ù", "ú", "û", "ũ", "ü", "ū",      "ŭ", "ů", "ǔ",
  "ỳ", "ý", "ŷ", "ỹ", "ÿ", "ȳ", "ẏ",      "ẙ",
/* capitals */
  "À", "Á", "Â", "Ã", "Ä", "Ā", "Ȧ", "Ă", "Å", "Ǎ",
  "È", "É", "Ê", "Ẽ", "Ë", "Ē", "Ė", "Ĕ",      "Ě",
  "Ì", "Í", "Î", "Ĩ", "Ï", "Ī", "İ", "Ĭ",      "Ǐ",
  "Ò", "Ó", "Ô", "Õ", "Ö", "Ō", "Ȯ", "Ŏ",      "Ǒ",
  "Ù", "Ú", "Û", "Ũ", "Ü", "Ū",      "Ŭ", "Ů", "Ǔ",
  "Ỳ", "Ý", "Ŷ", "Ỹ", "Ÿ", "Ȳ", "Ẏ",
/* acute */
  "ć", "ĺ", "ń", "ŕ", "ś", "ź",
  "Ć", "Ĺ", "Ń", "Ŕ", "Ś", "Ź",
/* cedilla */
  "ç", "ģ", "ķ", "ļ", "ņ", "ŗ", "ş",
  "Ç", "Ģ", "Ķ", "Ļ", "Ņ", "Ŗ", "Ş",
/* circumflex */
  "ĉ", "ĝ", "ĥ", "ĵ", "ŝ", "ŵ",
  "Ĉ", "Ĝ", "Ĥ", "Ĵ", "Ŝ", "Ŵ",
/* double acute (hungarumlaut) */
  "ő", "ű", "Ő", "Ű",
/* caron */
  "č", "ď", "ľ", "ň", "ř", "š", "ť", "ž",
  "Č", "Ď", "@", "Ň", "Ř", "Š", "Ť", "Ž", /* TODO -- L WITH CARON */
/* dot above */
  "ċ", "ġ", "ż", "Ċ", "Ġ", "Ż",
/* breve */
  "ğ", "Ğ",
/* tilde */
  "ñ", "Ñ",
/* macron */
/* diaeresis */
/* comma below */
  "ș", "ț", "Ș", "Ț",
/* not really accents */
  "æ", "Æ", "œ", "Œ", "ß", "ø", "Ø",
  "¡", "¿"
};
const unsigned int accent_latex[N_ACCENT] = {
/* accented vowels */
  96, 180, 94, 126, 168, 175, 125, 145, 146, 95,
  96, 180, 94, 126, 168, 175, 125, 145,      95,
  96, 180, 94, 126, 168, 175,   0, 145,      95,
  96, 180, 94, 126, 168, 175, 125, 145,      95,
  96, 180, 94, 126, 168, 175,      145, 146, 95,
  96, 180, 94, 126, 168, 175, 125,      146,
/* capitals */
  96, 180, 94, 126, 168, 175, 125, 145, 146, 95,
  96, 180, 94, 126, 168, 175, 125, 145,      95,
  96, 180, 94, 126, 168, 175, 125, 145,      95,
  96, 180, 94, 126, 168, 175, 125, 145,      95,
  96, 180, 94, 126, 168, 175,      145, 146, 95,
  96, 180, 94, 126, 168, 175, 125,
/* acute */
  180, 180, 180, 180, 180, 180,
  180, 180, 180, 180, 180, 180,
/* cedilla */
  184, 184, 184, 184, 184, 184, 184,
  184, 184, 184, 184, 184, 184, 184,
/* circumflex */
  94, 94, 94, 94, 94, 94,
  94, 94, 94, 94, 94, 94,
/* double acute (hungarumlaut) */
  124, 124, 124, 124,
/* caron */
  95, 95, 95, 95, 95, 95, 95, 95,
  95, 95, 95, 95, 95, 95, 95, 95,
/* dot above */
  125, 125, 125, 125, 125, 125,
/* breve */
  145, 145,
/* tilde */
  126, 126,
/* macron */
/* diaeresis */
/* domma below */
  44, 44, 44, 44,
/* not really accents */
  0, 0, 0, 0, 0, 0, 0,
  0, 0
};
const char accent_latex_letter[N_ACCENT] = {
/* accented vowels */
  'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
  'e', 'e', 'e', 'e', 'e', 'e', 'e', 'e',      'e',
  /* \217 is the dotless i*/
  '\217', '\217', '\217', '\217', '\217', '\217', '\217', '\217', '\217',
  'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',      'o',
  'u', 'u', 'u', 'u', 'u', 'u',      'u', 'u', 'u',
  'y', 'y', 'y', 'y', 'y', 'y', 'y',      'y',
/* capitals */
  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
  'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',      'E',
  'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I',      'I',
  'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O',      'O',
  'U', 'U', 'U', 'U', 'U', 'U',      'U', 'U', 'U',
  'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y',
/* acute */
  'c', 'l', 'n', 'r', 's', 'z',
  'C', 'L', 'N', 'R', 'S', 'Z',
/* cedilla */
  'c', 'g', 'k', 'l', 'n', 'r', 's',
  'C', 'G', 'K', 'L', 'N', 'R', 'S',
/* circumflex */
  'c', 'g', 'h','\220','s','w',
  'C', 'G', 'H', 'J', 'S', 'W',
/* double acute (hungarumlaut) */
  'o', 'u', 'O', 'U',
/* caron */
  'c', 'd','\217','n','r', 's', 't', 'z',
  'C', 'D', 'I', 'N', 'R', 'S', 'T', 'Z',
/* dot above */
  'c', 'g', 'z', 'C', 'G', 'Z',
/* breve */
  'g', 'G',
/* tilde */
  'n', 'N',
/* macron */
/* diaeresis */
/* comma delow */
  's', 't', 'S', 'T',
/* not really accents */
  '\346', '\306', '\215', '\216', '\337', '\370', '\330',
  '\241', '\277'
};

const float accent_latex_height[N_ACCENT] = {
/* accented vowels */
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,       0.00,
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,       0.00,
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,       0.00,
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00,       0.00, 0.00, 0.00,
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,       0.00,
/* capitals */
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22,
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22,       0.22,
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22,       0.22,
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22,       0.22,
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22,       0.22, 0.22, 0.22,
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22,
/* acute */
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
/* cedilla */  
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
/* circumflex */
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22,
/* double acute (hungarumlaut) */
  0.00, 0.00, 0.22, 0.22,
/* caron */
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
  0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22,
/* dot above */
  0.00, 0.00, 0.00, 0.22, 0.22, 0.22,
/* breve */
  0.00, 0.22,
/* tilde */
  0.00, 0.22,
/* macron */
/* diaeresis */
/* comma below */
  -0.15, -0.15, -0.15, -0.15,
/* not really accents */
  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
  0.00, 0.00
};

gchar *
append_char (const gchar * str, const gchar * c)
{
  gchar buf[10];
  gunichar uc = g_utf8_get_char (c);
  int i;

/* Special characters for PostScript */
  if (uc == g_utf8_get_char ("("))
    return g_strdup_printf ("%s\\(", str);
  if (uc == g_utf8_get_char (")"))
    return g_strdup_printf ("%s\\)", str);

  for (i = 0; i < N_ACCENT; i++)
    if (uc == g_utf8_get_char (accent[i]))
    {
      if (accent_latex[i] == 0)
/* This is used by the dotless i and j */
	return g_strdup_printf ("%s%c", str, accent_latex_letter[i]);
      else
        return g_strdup_printf ("%s)t %f(\\%.3o)(%c)acc(", str,
  	                        accent_latex_height[i], accent_latex[i],
	                        accent_latex_letter[i]);
    }
  
  buf[g_unichar_to_utf8 (uc, buf)] = 0;
  return g_strdup_printf ("%s%s", str, buf);
}


#define UCOMP(S1,S2) (g_utf8_get_char (S1) == g_utf8_get_char (S2))
gchar *
convert_latin1 (gchar * str)
{
  unsigned int flag, i;
  gchar *s, *s2, *pos;

  flag = 0;
  s = g_strdup ("(");
  for (pos = str; g_utf8_get_char (pos) != 0; pos = g_utf8_next_char (pos))
    {
      if (UCOMP(pos, "\\"))
	{
	  if (UCOMP (g_utf8_next_char (pos), " "))
	    {
	      s2 = s;
	      s = g_strdup_printf ("%s ", s2);
	      g_free (s2);
	      break;
	    }
	  for (i = 0; i < N_GREEK; i++)
	    if (strncmp (pos + 1, greek[i], greek_len[i]) == 0)
	      {
		s2 = s;
		if (prop.latex_export)
		{
		  s2 = s;
		  s = g_strdup_printf ("%s\\%.3o", s2, greek_latex[i]);
		  g_free (s2);
		}
		else
		{
		  s = g_strdup_printf ("%s)t ", s2);
		  g_free (s2);
		  s2 = s;
		  s = g_strdup_printf ("%s g(\\%.3o)t sf (", s2,
		                       greek_symbol[i]);
		  g_free (s2);
		}
		pos += greek_len[i];
		while (UCOMP (g_utf8_next_char (pos), " "))
		  pos ++;
		break;
	      }
	  for (i = 0; i < N_NATURAL; i++)
	    if (strncmp (pos + 1, natural[i], natural_len[i]) == 0)
	      {
		s2 = s;
		if (prop.latex_export)
		  s = g_strdup_printf ("%s\\%.3o", s2, natural_latex[i]);
		else
		  s = g_strdup_printf ("%s%s", s2, natural_symbol[i]);
		g_free (s2);
		pos += natural_len[i];
		while (UCOMP (g_utf8_next_char (pos), " "))
		  pos ++;
		break;
	      }
	}
      else
	{
	  s2 = s;
	  s = append_char (s2, pos);
	  g_free (s2);
	}
    }
  s2 = s;
  s = g_strdup_printf ("%s)t ", s2);
  g_free (s2);
/*  printf ("convert_latin1 returns: %s\n", s);*/
  return (s);
}
#undef UCOMP

/* This is the old version od convert_latin1, stored here for easy
 * reference while I am working on the new, full UTF-8 implementation. */
#if 0
gchar *
convert_latin1 (const gchar * str)
{
  unsigned int pos, flag, i;
  gchar *s, *s2;

  flag = 0;
  s = g_strdup ("(");
  for (pos = 0; pos < strlen (str); pos++)
    {
      if (str[pos] == '\\')
	{
	  if (str[pos + 1] == ' ')
	    {
	      s2 = s;
	      s = g_strdup_printf ("%s ", s2);
	      g_free (s2);
	      break;
	    }
	  for (i = 0; i < N_GREEK; i++)
	    if (strncmp (str + pos + 1, greek[i], greek_len[i]) == 0)
	      {
		s2 = s;
		if (prop.latex_export)
		{
		  s2 = s;
		  s = g_strdup_printf ("%s\\%.3o", s2, greek_latex[i]);
		  g_free (s2);
		}
		else
		{
		  s = g_strdup_printf ("%s)t ", s2);
		  g_free (s2);
		  s2 = s;
		  s = g_strdup_printf ("%s g(\\%.3o)t sf (", s2,
		                       greek_symbol[i]);
		  g_free (s2);
		}
		pos += greek_len[i];
		while (str[pos + 1] == ' ')
		  pos += 1;
		break;
	      }
	  for (i = 0; i < N_NATURAL; i++)
	    if (strncmp (str + pos + 1, natural[i], natural_len[i]) == 0)
	      {
		s2 = s;
		if (prop.latex_export)
		  s = g_strdup_printf ("%s\\%.3o", s2, natural_latex[i]);
		else
		  s = g_strdup_printf ("%s%s", s2, natural_symbol[i]);
		g_free (s2);
		pos += natural_len[i];
		while (str[pos + 1] == ' ')
		  pos += 1;
		break;
	      }
	}
      else
	{
	  s2 = s;
	  s = append_char (s2, str[pos]);
	  g_free (s2);
	}
    }
  s2 = s;
  s = g_strdup_printf ("%s)t ", s2);
  g_free (s2);
/*  printf ("convert_latin1 returns: %s\n", s);*/
  return (s);
}
#endif


/* This function will return 1 in the following cases :
 *
 *           1------2          \          /
 *          /        \          \        /
 *         /          \          2------1
 *
 *  meaning that, if you walk from point 1 to point 2, you should draw
 *  the second line of the double bond on your right.
 *
 *  In the other case, the routine will return 2.
 *
 *  If the case is symmetric (ketone, etc.), it will return:
 *    + 0 if the double bond is completely alone
 *    + 3 in the following case
 *
 *                  \
 *                   \
 *                    1------2
 *                   /
 *                  /
 *
 *    + 4 in the other case
 *
 *                  \
 *                   \
 *                    2------1
 *                   /
 *                  /
 *
 *    + 5 if both
 *
 *                  \          /
 *                   \        /
 *                    2------1
 *                   /        \
 *                  /          \
 *
 */
int
double_style (struct Bond *list, struct Bond *ref)
{
  struct Bond *current;
  int i1 = 0, i2 = 0;
  double x1, x2, y1, y2, px, py;

  if (ref == NULL || list == NULL || ref->type != BOND_DOUBLE)
    return 0;

  x1 = 0;
  y1 = 0;
  x2 = 0;
  y2 = 0;
  current = list;
  do
    {
      if (current == ref)
	continue;

      if (current->type >= BOND_ATOM)
	continue;

      if (IS_SMALL (current->x1 - ref->x1)
	  && IS_SMALL (current->y1 - ref->y1))
	{
	  x1 += current->x2;
	  y1 += current->y2;
	  i1++;
	}
      if (IS_SMALL (current->x2 - ref->x1)
	  && IS_SMALL (current->y2 - ref->y1))
	{
	  x1 += current->x1;
	  y1 += current->y1;
	  i1++;
	}
      if (IS_SMALL (current->x1 - ref->x2)
	  && IS_SMALL (current->y1 - ref->y2))
	{
	  x2 += current->x2;
	  y2 += current->y2;
	  i2++;
	}
      if (IS_SMALL (current->x2 - ref->x2)
	  && IS_SMALL (current->y2 - ref->y2))
	{
	  x2 += current->x1;
	  y2 += current->y1;
	  i2++;
	}
    }
  while ((current = current->next) != NULL);

  if (i1 != 0)
    {
      x1 /= i1;
      y1 /= i1;
    }
  if (i2 != 0)
    {
      x2 /= i2;
      y2 /= i2;
    }

  px = ref->y2 - ref->y1;
  py = ref->x1 - ref->x2;

  if (i1 == 0 && i2 == 0)
    return 0;

  if (i1 == 0)
    {
      if (px * (x2 - ref->x2) + py * (y2 - ref->y2) > 10000)
	return 7;
      if (px * (x2 - ref->x2) + py * (y2 - ref->y2) < -10000)
	return 6;
      return 3;
    }

  if (i2 == 0)
    {
      if (px * (x1 - ref->x1) + py * (y1 - ref->y1) > 10000)
	return 9;
      if (px * (x1 - ref->x1) + py * (y1 - ref->y1) < -10000)
	return 8;
      return 4;
    }

  if ((px * (x1 - ref->x1) + py * (y1 - ref->y1) > -10000)
      && (px * (x1 - ref->x1) + py * (y1 - ref->y1) < 10000)
      && (px * (x2 - ref->x2) + py * (y2 - ref->y2) < 10000)
      && (px * (x2 - ref->x2) + py * (y2 - ref->y2) > -10000))
    return 1;

  if (px * (x1 - ref->x1) + py * (y1 - ref->y1) > 10000)
    return 2;
  if (px * (x1 - ref->x1) + py * (y1 - ref->y1) < -10000)
    return 1;
  if (px * (x2 - ref->x2) + py * (y2 - ref->y2) > 10000)
    return 2;
  if (px * (x2 - ref->x2) + py * (y2 - ref->y2) < -10000)
    return 1;

  return 0;

}



/* Since the y-axis in the EPS export is reversed, we need a function
 * that computes the consequence on the 'double-style' value of all
 * double bonds. Here it is. */
int
invert_double_style (const int style)
{
  switch (style)
    {
    case 1:
      return 2;
    case 2:
      return 1;
    case 7:
      return 6;
    case 9:
      return 8;
    case 6:
      return 7;
    case 8:
      return 9;

    default:
      return style;
    }
}



/* We need to know what groups are at the end of a bond, to draw it
 * correctly... */
void
ends_of_bond (struct Bond *list, struct Bond *bond, struct Bond **group1,
	      struct Bond **group2)
{
  struct Bond *current;

  if (list == NULL)
    return;

  current = list;
  do
    {
      if ((current->type >= BOND_ATOM) && (current->type <= BOND_GROUP_R))
	{
	  if ((*group1 == NULL) && IS_SMALL (current->x3 - bond->x1)
	      && IS_SMALL (current->y3 - bond->y1))
	    *group1 = current;
	  if ((*group2 == NULL) && IS_SMALL (current->x3 - bond->x2)
	      && IS_SMALL (current->y3 - bond->y2))
	    *group2 = current;
	}

      if (current->type == BOND_GROUP)
	ends_of_bond (current->group_members, bond, group1, group2);
    }
  while ((current = current->next) != NULL);
}



/* This is used to convert the EasyChem (LaTeX-like) rich text format to
 * EPS. It depends on the font used, but this is not yet implemented. */
gchar *
richtext_to_eps (const gchar * text, const unsigned int p1i,
		 const unsigned int p2i)
{
#define IS_CONTROL(x) (((x) == '\\') || ((x) == '_') || ((x) == '^') \
                       || ((x) == '{') || ((x) == '}'))
#define N 2
#define MAX_LENGTH 7

  const unsigned int length[N] = { 5, 7 };
  const char command[N][MAX_LENGTH] = { "emph{", "textbf{" };
  const char command_eps[N][MAX_LENGTH] = { "it", "bold" };

  gchar *pre, *pre2, *total, *in, *end;
  unsigned int p1 = p1i, p2, i;

  pre = g_strstr_len (text + p1i, (signed) (p2i - p1i), "<markup>");
  if (pre != NULL)
    return richtext_to_eps (text, 0, (unsigned) (pre - text));

  while ((p1 < p2i) && !IS_CONTROL (text[p1]))
    p1++;

  if (p1 == p2i)
    {
      pre2 = g_strndup (text + p1i, p2i - p1i);
      pre = convert_latin1 (pre2);
      g_free (pre2);
      total = g_strdup_printf ("%s", pre);
      g_free (pre);
      return total;
    }

  pre2 = g_strndup (text + p1i, p1 - p1i);
  pre = convert_latin1 (pre2);
  g_free (pre2);

  switch (text[p1])
    {
    case '\\':			/* TODO */
      if (text[p1 + 1] == '\\')
	{
	  end = richtext_to_eps (text, p1 + 2, p2i);
	  total = g_strdup_printf ("%s (\\\\)t %s", pre, end);
	  g_free (pre);
	  g_free (end);
	  return total;
	}
      else
	{
	  for (i = 0; i < N; i++)
	    {
	      if (strncmp (command[i], text + p1 + 1, length[i]) == 0)
		{
		  p2 = corresponding_bracket (text, p1 + length[i]);
		  if ((p2 == 0) || (p2 <= p1 + 1))
		    fatal (_("richtext_to_eps (syntax error)"));
		  in = richtext_to_eps (text, p1 + 1 + length[i], p2);
		  end = richtext_to_eps (text, p2 + 1, p2i);
		  total =
		    g_strdup_printf ("%s %s %s %s %s", pre, command_eps[i],
				     in, command_eps[i], end);
		  g_free (pre);
		  g_free (in);
		  g_free (end);
		  return total;
		}
	    }
	  while (IS_ALPHA (text[p1 + 1]))
	    p1++;
	  while (text[p1 + 1] == ' ')
	    p1++;
	  g_free (pre);
	  pre2 = g_strndup (text + p1i, p1 + 1 - p1i);
	  pre = convert_latin1 (pre2);
	  g_free (pre2);
	  end = richtext_to_eps (text, p1 + 1, p2i);
	  total = g_strdup_printf ("%s %s", pre, end);
	  g_free (pre);
	  g_free (end);
	  return total;
	}
      break;

    case '_':
      if (text[p1 + 1] == '{')
	{
	  p2 = corresponding_bracket (text, p1 + 1);
	  if ((p2 == 0) || (p2 <= p1 + 1))
            fatal (_("richtext_to_eps (syntax error)"));
	  in = richtext_to_eps (text, p1 + 2, p2);
	  end = richtext_to_eps (text, p2 + 1, p2i);
	  total = g_strdup_printf ("%s bsub %s esub %s", pre, in, end);
	  g_free (pre);
	  g_free (in);
	  g_free (end);
	  return total;
	}
      else
	{
	  in = richtext_to_eps (text, p1 + 1, p1 + 2);
	  end = richtext_to_eps (text, p1 + 2, p2i);
	  total = g_strdup_printf ("%s bsub %s esub %s", pre, in, end);
	  g_free (in);
	  g_free (pre);
	  g_free (end);
	  return total;
	}
      break;

    case '^':
      if (text[p1 + 1] == '{')
	{
	  p2 = corresponding_bracket (text, p1 + 1);
	  if ((p2 == 0) || (p2 <= p1 + 1))
            fatal (_("richtext_to_eps (syntax error)"));
	  in = richtext_to_eps (text, p1 + 2, p2);
	  end = richtext_to_eps (text, p2 + 1, p2i);
	  total = g_strdup_printf ("%s bsup %s esup %s", pre, in, end);
	  g_free (pre);
	  g_free (in);
	  g_free (end);
	  return total;
	}
      else
	{
	  in = richtext_to_eps (text, p1 + 1, p1 + 2);
	  end = richtext_to_eps (text, p1 + 2, p2i);
	  total = g_strdup_printf ("%s bsup %s esup %s", pre, in, end);
	  g_free (in);
	  g_free (pre);
	  g_free (end);
	  return total;
	}
      break;

    case '{':
      p2 = corresponding_bracket (text, p1);
      if ((p2 == 0) || (p2 <= p1 + 1))
        fatal (_("richtext_to_eps (syntax error)"));
      in = richtext_to_eps (text, p1 + 1, p2);
      end = richtext_to_eps (text, p2 + 1, p2i);
      total = g_strdup_printf ("%s %s %s", pre, in, end);
      g_free (pre);
      g_free (in);
      g_free (end);
      return total;
      break;
    }

  pre2 = g_strndup (text + p1i, p2i - p1i);
  pre = convert_latin1 (pre2);
  g_free (pre2);
  total = g_strdup_printf ("%s", pre);
  g_free (pre);
  return total;

#undef IS_CONTROL
}



#define INVERSION	400
#define CONV(x)		((x) * ((double) EPS_LENGTH) / BOND_LENGTH)
void
eps_write_ornament (FILE *file, struct Ornament *orn, const LLINT x,
                    const LLINT y, const double t)
{
  switch (orn->type)
  {
  case ORN_LONE_PAIR:
    fprintf (file, "np %g %g mv %g %g l stroke\n",
      CONV (x - ORN_DEF_SIZE * orn->size / 2 * sin (t)),
      INVERSION - CONV (y - ORN_DEF_SIZE * orn->size / 2 * cos (t)),
      CONV (x + ORN_DEF_SIZE * orn->size / 2 * sin (t)),
      INVERSION - CONV (y + ORN_DEF_SIZE * orn->size / 2 * cos (t)));
    break;

  case ORN_LONE_PAIR_DOTS:
    fprintf (file, "np %g %g %g 0 360 arc fill\n",
	     CONV (x - ORN_DEF_SIZE * orn->size * 1 / 4 * sin(t)),
	     INVERSION - CONV (y - ORN_DEF_SIZE * orn->size * 1 / 4 * cos(t)), 
	     CONV (ORN_DEF_SIZE * orn->size * 0.1));
    fprintf (file, "np %g %g %g 0 360 arc fill\n",
	     CONV (x + ORN_DEF_SIZE * orn->size * 1 / 4 * sin(t)), 
	     INVERSION - CONV (y + ORN_DEF_SIZE * orn->size * 1 / 4 * cos(t)), 
	     CONV (ORN_DEF_SIZE * orn->size * 0.1));
    break;

  case ORN_LONE_ELECTRON:
    fprintf (file, "np %g %g %g 0 360 arc fill\n",
	     CONV (x - ORN_DEF_SIZE * orn->size * 1 / 4 * sin(t)),
	     INVERSION - CONV (y - ORN_DEF_SIZE * orn->size * 1 / 4 * cos(t)), 
	     CONV (ORN_DEF_SIZE * orn->size * 0.1));
    break;

  case ORN_GAP:
    fprintf (file, "np %g %g mv %g %g l %g %g l %g %g l %g %g l stroke\n",
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y - ORN_DEF_SIZE * orn->size / 2),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y - ORN_DEF_SIZE * orn->size / 2),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y + ORN_DEF_SIZE * orn->size / 2),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y + ORN_DEF_SIZE * orn->size / 2),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y - ORN_DEF_SIZE * orn->size / 2));
    break;
    
  case ORN_GAP2:
    fprintf (file, "np %g %g mv %g %g l %g %g l %g %g l %g %g l stroke\n",
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y - ORN_DEF_SIZE * orn->size / 4),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y - ORN_DEF_SIZE * orn->size / 4),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y + ORN_DEF_SIZE * orn->size / 4),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y + ORN_DEF_SIZE * orn->size / 4),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      INVERSION - CONV (y - ORN_DEF_SIZE * orn->size / 4));
    break;

  case ORN_RADICAL:
    fprintf (file, "np %g %g %g 0 360 arc fill\n",
      CONV (x), INVERSION - CONV (y), CONV (ORN_DEF_SIZE * orn->size * 0.6));
    break;
  }
}

void
eps_write_orn_list (FILE *file, struct Ornament *orn,
                    const LLINT x, const LLINT y)
{
  struct Ornament *current = orn;
  unsigned int i;
  double tc, t_first, t, t_spacing;

  while (current != NULL)
  {
    tc = ((double) current->angle) * G_PI / 180;
    t_spacing = ((double) current->spacing) * G_PI / 180;
    t_first = tc - ((current->number - 1) * t_spacing) / 2;

    for (i = 0; i < current->number; i++)
    {
      t = t_first + i * t_spacing;
      eps_write_ornament (file, current,
	                  x + ORN_DEF_DIST * current->dist * sin (t),
                          y - ORN_DEF_DIST * current->dist * cos (t),
                          G_PI_2 - t);
    }

    current = current->next;
  }
}


/* This is used to write the EPS code.
 *       + heading == 0 : print no heading at all (recursive version),
 *                        and no 'showpage'
 *       + heading == 1 : print all heading but %%!PS-Adobe-2.0 EPSF-2.0
 *                        and 'showpage'
 *       + heading > 1  : print all heading and 'showpage'
 * */
void
eps_write (struct Bond *list, FILE * file, const int heading,
	   const int bbox_atend)
{
#define SIZE 40
  struct Bond *group1, *group2, *current;
  gchar *str, *str2, buff[SIZE], *left, *right;
  time_t t;
  int dir, fonts;
  double ex1, ey1, ex2, ey2, ex3, ey3, px, py, r, t1, t2, phi, xa, ya, dx, dy;

  if (heading > 1)
    fprintf (file, "%%!PS-Adobe-2.0 EPSF-2.0\n");
  if (heading != 0)
  {
    fprintf (file, "%%%%Title: \n");
    fprintf (file, "%%%%Creator: EasyChem " VERSION "\n");
    t = time (NULL);
    fprintf (file, "%%%%CreationDate: %s", ctime (&t));
    str = (gchar *) g_get_user_name ();
    fprintf (file, "%%%%For: %s", str);

#ifdef UNIX
    gethostname (buff, SIZE);
    fprintf (file, "@%s", buff);
#endif

    str = (gchar *) g_get_real_name ();
    fprintf (file, " (%s)\n", str);

#undef SIZE

    fprintf (file, "%%%%Magnification: 1.000\n");
    if (bbox_atend != 0)
      fprintf (file, "%%%%BoundingBox: (atend)\n");

/* This is the core of the postscript code */
#include "postscript/preamble.c"

/* And we need to load the proper fonts... */
    if (prop.latex_export)
    {
      fonts = fonts_used (list);
      if (fonts & FONT_R)
      {
#include "postscript/cm.c"
      }
      if (fonts & FONT_I)
      {
#include "postscript/cmi.c"
      }
      if (fonts & FONT_B)
      {
#include "postscript/cmb.c"
      }
      if ((fonts & FONT_I) && (fonts & FONT_B))
      {
#include "postscript/cmbi.c"
      }
#include "postscript/cm_common.c"
    }
    else
    {
#include "postscript/times.c"
    }
  }

  if (list == NULL)
    return;

  current = list;
  do
    {
      ex1 = CONV (current->x1);
      ey1 = INVERSION - CONV (current->y1);
      ex2 = CONV (current->x2);
      ey2 = INVERSION - CONV (current->y2);
      ex3 = CONV (current->x3);
      ey3 = INVERSION - CONV (current->y3);

      px = ex2 - ex1;
      py = ey2 - ey1;
      r = hypot (px, py);
      px /= r;
      py /= r;

      if (((current->color.red != 0) || (current->color.green != 0)
	  || (current->color.blue != 0)) && current->type != BOND_GROUP)
	fprintf (file, "%g %g %g c ",
		 (double) current->color.red / FULL_COLOR,
		 (double) current->color.green / FULL_COLOR,
		 (double) current->color.blue / FULL_COLOR);

      if (current->type <= BOND_DASHED)
	{
	  group1 = NULL;
	  group2 = NULL;
	  ends_of_bond (list, current, &group1, &group2);
	  fprintf (file, "%g %g %g %g ", ex1, ey1, ex2, ey2);
	  if (group1 != NULL)
	    {
	      if (group2 != NULL)
		{
		  str = centered_part_of_group (group2);
		  str2 = LATIN1 (str);
		  g_free (str);
		  str = richtext_to_eps (str2, 0, strlen (str2));
		  fprintf (file, "{%s}", str);
		  g_free (str);
		  g_free (str2);
		  str = centered_part_of_group (group1);
		  str2 = LATIN1 (str);
		  g_free (str);
		  str = richtext_to_eps (str2, 0, strlen (str2));
		  fprintf (file, "{%s}b12 ", str);
		  g_free (str);
		  g_free (str2);
		}
	      else
		{
		  str = centered_part_of_group (group1);
		  str2 = LATIN1 (str);
		  g_free (str);
		  str = richtext_to_eps (str2, 0, strlen (str2));
		  fprintf (file, "{%s}b1 ", str);
		  g_free (str);
		  g_free (str2);
		}
	    }
	  else
	    {
	      if (group2 != NULL)
		{
		  str = centered_part_of_group (group2);
		  str2 = LATIN1 (str);
		  g_free (str);
		  str = richtext_to_eps (str2, 0, strlen (str2));
		  fprintf (file, "{%s}b2 ", str);
		  g_free (str);
		  g_free (str2);
		}
	    }
	}

      switch (current->type)
	{
	case BOND_SIMPLE:
	  fprintf (file, "b-spl\n");
	  break;

	case BOND_DOUBLE:
	  dir = invert_double_style (double_style (list, current));
	  fprintf (file, "%d %g b-dbl\n", dir, current->width);
	  break;

	case BOND_TRIPLE:
	  fprintf (file, "%g b-tpl\n", current->width);
	  break;

	case BOND_UP:
	  fprintf (file, "%g b-up\n", current->width);
	  break;

	case BOND_DOWN:
	  fprintf (file, "%g b-down\n", current->width);
	  break;

	case BOND_DASHED:	/* FIXME: should be improved */
	  fprintf (file, "[4] 0 setdash b-spl [] 0 setdash\n");
	  break;

	case BOND_CIRCLE:
	  fprintf (file, "newpath\n  %g %g %g 0 360 arc\nstroke\n",
		   (ex1 + ex2) / 2, (ey1 + ey2) / 2,
		   hypot (ex1 - ex2, ey1 - ey2) / 2);
	  break;

	case BOND_ARROW:
	  fprintf (file, "%g %g %g %g b-spl\n", ex1, ey1, ex2, ey2);
	  if (current->x4 != 0)
	    fprintf (file, "%" LLFORMAT " %g %g %g %g %g arrowhead\n",
		     current->x4, current->width, ex2, ey2, px, py);
	  if (current->y4 != 0)
	    fprintf (file, "%" LLFORMAT " %g %g %g %g %g arrowhead\n",
		     current->y4, current->width, ex1, ey1, - px, - py);
	  break;

	case BOND_ARC:
	  info_arc_export (&px, &py, &t1, &t2, &dir, ex1, ey1, ex2, ey2, ex3,
			   ey3);
	  if (dir > 0)
	    fprintf (file, "newpath\n  %g %g %g %g %g arc\nstroke\n",
		     px, py, hypot (ex1 - px, ey1 - py), -t1 - t2, -t1);
	  else
	    fprintf (file, "newpath\n  %g %g %g %g %g arc\nstroke\n",
		     px, py, hypot (ex1 - px, ey1 - py), -t1, -t1 - t2);

#define CORR 3.2
	  if (current->x4 != 0)
	    {
	      r = hypot (ex1 - px, ey1 - py);
	      /* CORR (in asin) should not be constant, but related to the
	         length of the arrowhead */
	      phi = 2 * asin (CORR / (2 * hypot (ex1 - px, ey1 - py)));
	      xa = px + r * cos (G_PI * (- t1 - t2) / 180 + dir * phi);
	      ya = py + r * sin (G_PI * (- t1 - t2) / 180 + dir * phi);

	      dx = ex2 - xa;
	      dy = ey2 - ya;
	      r = hypot (dx, dy);
	      dx /= r;
	      dy /= r;
	      fprintf (file, "%" LLFORMAT " %g %g %g %g %g arrowhead\n",
		       current->x4, current->width, ex2, ey2, dx, dy);
	    }

	  if (current->y4 != 0)
	    {
  	      r = hypot (ex1 - px, ey1 - py);
	      /* CORR (in asin) should not be constant, but related to the
	         length of the arrowhead */
	      phi = 2 * asin (CORR / (2 * hypot (ex1 - px, ey1 - py)));
	      xa = px + r * cos (G_PI * (- t1) / 180 - dir * phi);
	      ya = py + r * sin (G_PI * (- t1) / 180 - dir * phi);

	      dx = ex1 - xa;
	      dy = ey1 - ya;
	      r = hypot (dx, dy);
	      dx /= r;
	      dy /= r;
	      fprintf (file, "%" LLFORMAT " %g %g %g %g %g arrowhead\n",
		       current->y4, current->width, ex1, ey1, dx, dy);
	    }
#undef CORR
	  break;

	case BOND_ATOM:
	  str = centered_part_of_group (current);
	  str2 = LATIN1 (str);
	  g_free (str);
	  str = richtext_to_eps (str2, 0, strlen (str2));
	  g_free (str2);
	  fprintf (file, "/relfs{%g}bd sf %g %g {%s}center-text\n",
	           current->width, ex3, ey3, str);
	  break;

	case BOND_GROUP_L:
	  parts_of_group_text (current, &left, &right);
	  str2 = LATIN1 (left);
	  str = richtext_to_eps (str2, 0, strlen (str2));
	  fprintf (file, "/relfs{%g}bd sf %g %g {%s}", current->width,
	           ex3, ey3, str);
	  g_free (str);
	  g_free (str2);
	  str2 = LATIN1 (right);
	  str = richtext_to_eps (str2, 0, strlen (str2));
	  fprintf (file, "{%s}left-text\n", str);
	  g_free (str);
	  g_free (str2);
	  break;

	case BOND_GROUP_R:
	  parts_of_group_text (current, &left, &right);
	  str2 = LATIN1 (left);
	  str = richtext_to_eps (str2, 0, strlen (str2));
	  fprintf (file, "/relfs{%g}bd sf %g %g {%s}", current->width,
	           ex3, ey3, str);
	  g_free (str);
	  g_free (str2);
	  str2 = LATIN1 (right);
	  str = richtext_to_eps (str2, 0, strlen (str2));
	  fprintf (file, "{%s}right-text\n", str);
	  g_free (str);
	  g_free (str2);
	  break;

	case BOND_GROUP:
	  eps_write (current->group_members, file, 0, 0);
	  break;

	default:
	  bug_in ("eps_write");
	}
      if ((current->color.red != 0) || (current->color.green != 0)
	  || (current->color.blue != 0))
	fprintf (file, "0 0 0 c\n");

      if (BOND_HAS_TEXT (current))
 	eps_write_orn_list (file, current->ornaments[0], current->x3,
	                    current->y3);
      else
      {
 	eps_write_orn_list (file, current->ornaments[0], current->x1,
	                    current->y1);
 	eps_write_orn_list (file, current->ornaments[1], current->x2,
	                    current->y2);
      }
    }
  while ((current = current->next) != NULL);

  if (heading != 0)
    fprintf (file, "\n\nshowpage\n");
  fflush (file);

}


void
eps_poor_bbox (struct Bond *list, int *i, int *j, int *k, int *l)
{
  LLINT xmin, xmax, ymin, ymax;
  
  bounds_of_list (list, &xmin, &xmax, &ymin, &ymax);
  *i = CONV (xmin) - 1;
  *j = INVERSION - CONV (ymax);
  *k = CONV (xmax) + 1; 
  *l = INVERSION - CONV (ymin) + 2;
}

#undef CONV
#undef INVERSION


void
eps_bbox (struct Bond *list, char *filename, GtkWindow * parent,
          int *i, int *j, int *k, int *l)
{
  GtkWidget *dialog;

#ifdef UNIX
  FILE *output;
  int f[2], pid, devnull, result;
  char *argv[7] = { "gs", "-dNOPAUSE", "-q", "-sDEVICE=bbox", "", "-dBATCH",
    NULL
  };
#endif

  *i = -1;
  *j = -1;
  *k = -1;
  *l = -1;

#ifdef UNIX
/* Now we run 'gs' to determine the bounding box of the file we just
 * created. */
  if (pipe (f) == -1)
    fatal (strerror (errno));
  pid = fork ();
  if (pid < 0)
    fatal (strerror (errno));
  if (pid == 0)			/* Fils */
    {
      close (f[0]);
      dup2 (f[1], 2);
      close (f[1]);
      devnull = open ("/dev/null", O_WRONLY);
      dup2 (devnull, 1);
      dup2 (devnull, 0);
      close (devnull);
      argv[4] = filename;
      if (prop.path_gs != NULL)
	execv (prop.path_gs, argv);
#ifdef GS_PATH
      execv (GS_PATH "/gs", argv);
#endif
      execvp ("gs", argv);
      execv ("/usr/bin/gs", argv);
      execv ("/usr/local/bin/gs", argv);
      execv ("/sw/bin/gs", argv);
      fputs ("%%BoundingBox: -1 -1 -1 -1\n", stderr);
      _exit (0);
    }
  close (f[1]);			/* Père */

  wait (NULL);
  output = fdopen (f[0], "r");

  while ((result =
	  fscanf (output, "%%%%BoundingBox: %d %d %d %d\n", i, j, k, l)) != 4)
    {
      if (feof (output))
	break;
    }
  fclose (output);
#endif

/* If gs didn't work, we have to determine the bb ourselves. */
  if ((*i == -1) && (*j == -1) && (*k == -1) && (*l == -1))
    {
      dialog = gtk_message_dialog_new
	(parent, GTK_DIALOG_DESTROY_WITH_PARENT,
	 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
	 _("Cannot find 'gs'. Will do poor man's bouding box determination."));
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      eps_poor_bbox (list, i, j, k, l);
    }
}


/* This is the routine that exports a bond list to an EPS file.  */
void
eps_export (struct Bond *list, char *filename, GtkWindow * parent,
            int try_gs)
{
  FILE *file;
  GtkWidget *dialog;
  int i, j, k, l;

  file = fopen (filename, "w");
  if (file == NULL)
    {
      dialog = gtk_message_dialog_new
	(parent, GTK_DIALOG_DESTROY_WITH_PARENT,
	 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Cannot open file '%s'"),
	 filename);
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      return;
    }
  eps_write (list, file, 2, 1);
  if (try_gs)
    eps_bbox (list, filename, parent, &i, &j, &k, &l);
  else
    eps_poor_bbox (list, &i, &j, &k, &l);

/* Now we modify the file to add the bounding box. */
  fputs ("%%Trailer\n", file);
  fprintf (file, "%%%%BoundingBox: %d %d %d %d\n", i, j, k, l);
  fputs ("%%EOF\n", file);
  fclose (file);
}





#define CONV(x)		((int) ((x) * ((double) FIG_LENGTH) / BOND_LENGTH))
void
fig_write_ornament (FILE *file, struct Ornament *orn, const LLINT x,
                    const LLINT y, const double t)
{
  switch (orn->type)
  {
  case ORN_LONE_PAIR:
    fprintf (file, "2 1 0 2 0 -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t");
    fprintf (file, "%d %d %d %d\n",
      CONV (x - ORN_DEF_SIZE * orn->size / 2 * sin (t)),
      CONV (y - ORN_DEF_SIZE * orn->size / 2 * cos (t)),
      CONV (x + ORN_DEF_SIZE * orn->size / 2 * sin (t)),
      CONV (y - ORN_DEF_SIZE * orn->size / 2 * cos (t)));
    break;

  case ORN_GAP: 
    fprintf (file, "2 1 0 2 0 -1 50 0 -1 0.0 0 1 -1 0 0 5\n\t");
    fprintf (file, "%d %d %d %d %d %d %d %d %d %d\n",
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      CONV (y - ORN_DEF_SIZE * orn->size / 2),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      CONV (y - ORN_DEF_SIZE * orn->size / 2),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      CONV (y + ORN_DEF_SIZE * orn->size / 2),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      CONV (y + ORN_DEF_SIZE * orn->size / 2),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      CONV (y - ORN_DEF_SIZE * orn->size / 2));
    break; 

  case ORN_GAP2: 
    fprintf (file, "2 1 0 2 0 -1 50 0 -1 0.0 0 1 -1 0 0 5\n\t");
    fprintf (file, "%d %d %d %d %d %d %d %d %d %d\n",
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      CONV (y - ORN_DEF_SIZE * orn->size / 4),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      CONV (y - ORN_DEF_SIZE * orn->size / 4),
      CONV (x + ORN_DEF_SIZE * orn->size / 2),
      CONV (y + ORN_DEF_SIZE * orn->size / 4),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      CONV (y + ORN_DEF_SIZE * orn->size / 4),
      CONV (x - ORN_DEF_SIZE * orn->size / 2),
      CONV (y - ORN_DEF_SIZE * orn->size / 4));
    break; 

  case ORN_RADICAL:
    fprintf (file, "np %d %d %d 0 360 arc fill\n",
      CONV (x), CONV (y), CONV (ORN_DEF_SIZE * orn->size * 0.6));
    break;
  }
}


void
fig_write_orn_list (FILE *file, struct Ornament *orn,
                    const LLINT x, const LLINT y)
{
  struct Ornament *current = orn;
  unsigned int i;
  double tc, t_first, t, t_spacing;

  while (current != NULL)
  {
    tc = current->angle * G_PI / 180;
    t_spacing = current->spacing * G_PI / 180;
    t_first = tc - ((current->number - 1) * t_spacing) / 2;

    for (i = 0; i < current->number; i++)
    {
      t = t_first + i * t_spacing;
      fig_write_ornament (file, current,
                          x + ORN_DEF_DIST * current->dist * sin (t),
                          y - ORN_DEF_DIST * current->dist * cos (t),
                          G_PI_2 - t);
    }

    current = current->next;
  }
}


void
fig_write (struct Bond *list, FILE * file)
{
  struct Bond *current;
  LLINT x1, y1, x2, y2;
  unsigned int colornum = 40, color;
  int ex1, ey1, ex2, ey2, ex3, ey3, dir, i;
  double px, py, r, cx, cy;

  if (list == NULL)
    return;

  current = list;
  do
    {
      if ((current->color.red != 0) || (current->color.green != 0)
	  || (current->color.blue != 0))
	{
	  colornum++;
	  fprintf (file, "0 %d #%.2x%.2x%.2x\n", colornum,
		   current->color.red / 256, current->color.green / 256,
		   current->color.blue / 256);
	  color = colornum;
	}
      else
	color = 0;

      x1 = current->x1;
      y1 = current->y1;
      x2 = current->x2;
      y2 = current->y2;

#define DOUBLE_ADJUST	(0.03 * FIG_LENGTH)
#define DOUBLE_SHIFT	(0.08 * FIG_LENGTH * current->width)
#define TRIPLE_SHIFT	(0.14 * FIG_LENGTH * current->width)
#define STEREO_SHIFT	(0.14 * FIG_LENGTH * current->width)
#define ARROW_SHIFT	(0.12 * FIG_LENGTH * current->width)
#define ARROW2_SHIFT	(0.24 * FIG_LENGTH * current->width)

      ex1 = CONV (x1);
      ey1 = CONV (y1);
      ex2 = CONV (x2);
      ey2 = CONV (y2);
      ex3 = CONV (current->x3);
      ey3 = CONV (current->y3);

      px = ex2 - ex1;
      py = ey2 - ey1;
      r = hypot (px, py);
      px /= r;
      py /= r;

      switch (current->type)
	{
	case BOND_SIMPLE:
	  fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t", color);
	  fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	  break;

	case BOND_DOUBLE:
	  dir = double_style (list, current);
	  switch (dir)
	    {
	    case 3:
	    case 4:
	    case 5:
	      if (dir == 3 || dir == 5)
		{
		  ex2 += DOUBLE_ADJUST * px;
		  ey2 += DOUBLE_ADJUST * py;
		}
	      if (dir == 4 || dir == 5)
		{
		  ex1 -= DOUBLE_ADJUST * px;
		  ey1 -= DOUBLE_ADJUST * py;
		}

	      /* Fall through */
	    case 0:
	      fprintf (file, "6 %d %d %d %d\n",
		       MIN4 (ex1 - (int) (DOUBLE_SHIFT * py),
			     ex2 - (int) (DOUBLE_SHIFT * py),
			     ex1 + (int) (DOUBLE_SHIFT * py),
			     ex2 + (int) (DOUBLE_SHIFT * py)),
		       MIN4 (ey1 + (int) (DOUBLE_SHIFT * px),
			     ey2 + (int) (DOUBLE_SHIFT * px),
			     ey1 - (int) (DOUBLE_SHIFT * px),
			     ey2 - (int) (DOUBLE_SHIFT * px)),
		       MAX4 (ex1 - (int) (DOUBLE_SHIFT * py),
			     ex2 - (int) (DOUBLE_SHIFT * py),
			     ex1 + (int) (DOUBLE_SHIFT * py),
			     ex2 + (int) (DOUBLE_SHIFT * py)),
		       MAX4 (ey1 + (int) (DOUBLE_SHIFT * px),
			     ey2 + (int) (DOUBLE_SHIFT * px),
			     ey1 - (int) (DOUBLE_SHIFT * px),
			     ey2 - (int) (DOUBLE_SHIFT * px)));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 - (int) (DOUBLE_SHIFT * py),
		       ey1 + (int) (DOUBLE_SHIFT * px),
		       ex2 - (int) (DOUBLE_SHIFT * py),
		       ey2 + (int) (DOUBLE_SHIFT * px));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 + (int) (DOUBLE_SHIFT * py),
		       ey1 - (int) (DOUBLE_SHIFT * px),
		       ex2 + (int) (DOUBLE_SHIFT * py),
		       ey2 - (int) (DOUBLE_SHIFT * px));
	      fprintf (file, "-6\n");
	      break;

	    case 1:
	      fprintf (file, "6 %d %d %d %d\n",
		       MIN4 (ex1 - (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 - (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MIN4 (ey1 + (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 + (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py),
			     ey1, ey2),
		       MAX4 (ex1 - (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 - (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MAX4 (ey1 + (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 + (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py), ey1, ey2));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 - (int) (2 * DOUBLE_SHIFT * py) +
		       (int) (DOUBLE_SHIFT * px),
		       ey1 + (int) (2 * DOUBLE_SHIFT * px) +
		       (int) (DOUBLE_SHIFT * py),
		       ex2 - (int) (2 * DOUBLE_SHIFT * py) -
		       (int) (DOUBLE_SHIFT * px),
		       ey2 + (int) (2 * DOUBLE_SHIFT * px) -
		       (int) (DOUBLE_SHIFT * py));
	      fprintf (file, "-6\n");
	      break;

	    case 2:
	      fprintf (file, "6 %d %d %d %d\n",
		       MIN4 (ex1 + (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 + (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MIN4 (ey1 - (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 - (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py),
			     ey1, ey2),
		       MAX4 (ex1 + (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 + (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MAX4 (ey1 - (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 - (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py), ey1, ey2));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 + (int) (2 * DOUBLE_SHIFT * py) +
		       (int) (DOUBLE_SHIFT * px),
		       ey1 - (int) (2 * DOUBLE_SHIFT * px) +
		       (int) (DOUBLE_SHIFT * py),
		       ex2 + (int) (2 * DOUBLE_SHIFT * py) -
		       (int) (DOUBLE_SHIFT * px),
		       ey2 - (int) (2 * DOUBLE_SHIFT * px) -
		       (int) (DOUBLE_SHIFT * py));
	      fprintf (file, "-6\n");
	      break;

	    case 6:
	      fprintf (file, "6 %d %d %d %d\n",
		       MIN4 (ex1 - (int) (2 * DOUBLE_SHIFT * py),
			     ex2 - (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MIN4 (ey1 + (int) (2 * DOUBLE_SHIFT * px),
			     ey2 + (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py),
			     ey1, ey2),
		       MAX4 (ex1 - (int) (2 * DOUBLE_SHIFT * py),
			     ex2 - (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MAX4 (ey1 + (int) (2 * DOUBLE_SHIFT * px),
			     ey2 + (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py), ey1, ey2));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 - (int) (2 * DOUBLE_SHIFT * py),
		       ey1 + (int) (2 * DOUBLE_SHIFT * px),
		       ex2 - (int) (2 * DOUBLE_SHIFT * py) -
		       (int) (DOUBLE_SHIFT * px),
		       ey2 + (int) (2 * DOUBLE_SHIFT * px) -
		       (int) (DOUBLE_SHIFT * py));
	      fprintf (file, "-6\n");
	      break;

	    case 7:
	      fprintf (file, "6 %d %d %d %d\n",
		       MIN4 (ex1 + (int) (2 * DOUBLE_SHIFT * py),
			     ex2 + (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MIN4 (ey1 - (int) (2 * DOUBLE_SHIFT * px),
			     ey2 - (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py),
			     ey1, ey2),
		       MAX4 (ex1 + (int) (2 * DOUBLE_SHIFT * py),
			     ex2 + (int) (2 * DOUBLE_SHIFT * py) -
			     (int) (DOUBLE_SHIFT * px),
			     ex1, ex2),
		       MAX4 (ey1 - (int) (2 * DOUBLE_SHIFT * px),
			     ey2 - (int) (2 * DOUBLE_SHIFT * px) -
			     (int) (DOUBLE_SHIFT * py), ey1, ey2));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 + (int) (2 * DOUBLE_SHIFT * py),
		       ey1 - (int) (2 * DOUBLE_SHIFT * px),
		       ex2 + (int) (2 * DOUBLE_SHIFT * py) -
		       (int) (DOUBLE_SHIFT * px),
		       ey2 - (int) (2 * DOUBLE_SHIFT * px) -
		       (int) (DOUBLE_SHIFT * py));
	      fprintf (file, "-6\n");
	      break;

	    case 8:
	      fprintf (file, "6 %d %d %d %d\n",
		       MIN4 (ex1 - (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 - (int) (2 * DOUBLE_SHIFT * py),
			     ex1, ex2),
		       MIN4 (ey1 + (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 + (int) (2 * DOUBLE_SHIFT * px),
			     ey1, ey2),
		       MAX4 (ex1 - (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 - (int) (2 * DOUBLE_SHIFT * py),
			     ex1, ex2),
		       MAX4 (ey1 + (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 + (int) (2 * DOUBLE_SHIFT * px), ey1, ey2));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 - (int) (2 * DOUBLE_SHIFT * py) +
		       (int) (DOUBLE_SHIFT * px),
		       ey1 + (int) (2 * DOUBLE_SHIFT * px) +
		       (int) (DOUBLE_SHIFT * py),
		       ex2 - (int) (2 * DOUBLE_SHIFT * py),
		       ey2 + (int) (2 * DOUBLE_SHIFT * px));
	      fprintf (file, "-6\n");
	      break;

	    case 9:
	      fprintf (file, "6 %d %d %d %d\n",
		       MIN4 (ex1 + (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 + (int) (2 * DOUBLE_SHIFT * py),
			     ex1, ex2),
		       MIN4 (ey1 - (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 - (int) (2 * DOUBLE_SHIFT * px),
			     ey1, ey2),
		       MAX4 (ex1 + (int) (2 * DOUBLE_SHIFT * py) +
			     (int) (DOUBLE_SHIFT * px),
			     ex2 + (int) (2 * DOUBLE_SHIFT * py),
			     ex1, ex2),
		       MAX4 (ey1 - (int) (2 * DOUBLE_SHIFT * px) +
			     (int) (DOUBLE_SHIFT * py),
			     ey2 - (int) (2 * DOUBLE_SHIFT * px), ey1, ey2));
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	      fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       ex1 + (int) (2 * DOUBLE_SHIFT * py) +
		       (int) (DOUBLE_SHIFT * px),
		       ey1 - (int) (2 * DOUBLE_SHIFT * px) +
		       (int) (DOUBLE_SHIFT * py),
		       ex2 + (int) (2 * DOUBLE_SHIFT * py),
		       ey2 - (int) (2 * DOUBLE_SHIFT * px));
	      fprintf (file, "-6\n");
	      break;
	    }

	  break;

	case BOND_TRIPLE:
	  fprintf (file, "6 %d %d %d %d\n",
		   MIN (ex1, ex2) + (int) (TRIPLE_SHIFT * MIN (py, -py)),
		   MIN (ey1, ey2) + (int) (TRIPLE_SHIFT * MIN (px, -px)),
		   MAX (ex1, ex2) + (int) (TRIPLE_SHIFT * MAX (py, -py)),
		   MAX (ey1, ey2) + (int) (TRIPLE_SHIFT * MAX (px, -px)));
	  fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t", color);
	  fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	  fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t", color);
	  fprintf (file, "%d %d %d %d\n",
		   ex1 - (int) (TRIPLE_SHIFT * py),
		   ey1 + (int) (TRIPLE_SHIFT * px),
		   ex2 - (int) (TRIPLE_SHIFT * py),
		   ey2 + (int) (TRIPLE_SHIFT * px));
	  fprintf (file, "2 1 0 2 %d -1 50 0 -1 0.0 0 1 -1 0 0 2\n\t", color);
	  fprintf (file, "%d %d %d %d\n",
		   ex1 + (int) (TRIPLE_SHIFT * py),
		   ey1 - (int) (TRIPLE_SHIFT * px),
		   ex2 + (int) (TRIPLE_SHIFT * py),
		   ey2 - (int) (TRIPLE_SHIFT * px));
	  fprintf (file, "-6\n");
	  break;

	case BOND_UP:
	  fprintf (file, "2 1 0 0 %d 0 50 0 20 0.0 0 0 -1 0 0 4\n\t", color);
	  fprintf (file, "%d %d %d %d %d %d %d %d\n", ex1, ey1,
		   ex2 - (int) (STEREO_SHIFT * py),
		   ey2 + (int) (STEREO_SHIFT * px),
		   ex2 + (int) (STEREO_SHIFT * py),
		   ey2 - (int) (STEREO_SHIFT * px), ex1, ey1);
	  break;

	case BOND_DOWN:
	  fprintf (file, "6 %d %d %d %d\n",
		   MIN (ex1, ex2 + (int) (STEREO_SHIFT * MIN (py, -py))),
		   MIN (ey1, ey2 + (int) (STEREO_SHIFT * MIN (px, -px))),
		   MAX (ex1, ex2 + (int) (STEREO_SHIFT * MAX (py, -py))),
		   MAX (ey1, ey2 + (int) (STEREO_SHIFT * MAX (px, -px))));
	  for (i = 0; i < 9; i++)
	    {
	      cx = ex1 + (2 * i + 1) * (ex2 - ex1) / 18;
	      cy = ey1 + (2 * i + 1) * (ey2 - ey1) / 18;
	      fprintf (file, "2 1 0 1 %d 0 50 0 20 0.0 0 0 -1 0 0 2\n\t",
		       color);
	      fprintf (file, "%d %d %d %d\n",
		       (int) (cx - STEREO_SHIFT * py * (i + 1) / 9),
		       (int) (cy + STEREO_SHIFT * px * (i + 1) / 9),
		       (int) (cx + STEREO_SHIFT * py * (i + 1) / 9),
		       (int) (cy - STEREO_SHIFT * px * (i + 1) / 9));
	    }
	  fprintf (file, "-6\n");
	  break;

	case BOND_DASHED:	/* FIXME: 4.0 is not a magical value! */
	  fprintf (file, "2 1 1 2 %d -1 50 0 -1 4.0 0 1 -1 0 0 2\n\t", color);
	  fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	  break;

	case BOND_CIRCLE:
	  ex3 = (int) (hypot ((double) ex1 - ex2, (double) ey1 - ey2) / 2);
	  fprintf (file, "1 2 0 2 %d -1 50 0 -1 0.0 1 0.0 ", color);
	  fprintf (file, "%d %d %d %d %d %d %d %d\n", (ex1 + ex2) / 2,
		   (ey1 + ey2) / 2, ex3, ex3, ex1, ey1, ex2, ey2);
	  break;

	case BOND_ARROW:
	  fprintf (file, "2 1 0 1 %d -1 50 0 -1 0.0 0 0 -1 1 0 2\n\t", color);
	  fprintf (file, "2 1 1.0 45.0 45.0\n\t");
	  fprintf (file, "%d %d %d %d\n", ex1, ey1, ex2, ey2);
	  break;

	case BOND_ARC:
	  info_arc_export (&px, &py, NULL, NULL, &dir, (double) ex1,
			   (double) ey1, (double) ex2, (double) ey2,
			   (double) ex3, (double) ey3);
	  if (current->x4 == 0)
	    {
	      fprintf (file, "5 1 0 1 %d -1 50 0 -1 0.0 0 %d 0 0 ", color,
		       dir);
	      fprintf (file, "%f %f %d %d %d %d %d %d\n", px, py, ex1, ey1,
		       ex3, ey3, ex2, ey2);
	    }
	  else
	    {
	      fprintf (file, "5 1 0 1 %d -1 50 0 -1 0.0 0 %d 1 0 ", color,
		       dir);
	      fprintf (file, "%f %f %d %d %d %d %d %d\n\t", px, py, ex1, ey1,
		       ex3, ey3, ex2, ey2);
	      fprintf (file, "2 1 1.0 45.0 45.0\n");
	    }
	  break;

	case BOND_ATOM:
	  fprintf (file, "4 1 0 50 %d 0 10.0 0.0 %d ", color,
	           prop.latex_export ? 3 : 5);
	  fprintf (file, "-1 -1 %d %d ", ex3, ey1 + ey2);
	  for (i = 0; i < (signed) strlen (current->text); i++)
	    if ((current->text)[i] == '\\')
	      fprintf (file, "\\\\");
	    else
	      fprintf (file, "%c", (current->text)[i]);
	  fprintf (file, "\\001\n");
	  break;

	case BOND_GROUP_L:
	  fprintf (file, "4 0 0 50 %d 1 10.0 0.0 3 ", color);
	  fprintf (file, "-1 -1 %d %d ", ex3, ey1 + ey2);
	  for (i = 0; i < (signed) strlen (current->text); i++)
	    if ((current->text)[i] == '\\')
	      fprintf (file, "\\\\");
	    else
	      fprintf (file, "%c", (current->text)[i]);
	  fprintf (file, "\\001\n");
	  break;

	case BOND_GROUP_R:
	  fprintf (file, "4 2 0 50 %d 1 10.0 0.0 3 ", color);
	  fprintf (file, "-1 -1 %d %d ", ex3, ey1 + ey2);
	  for (i = 0; i < (signed) strlen (current->text); i++)
	    if ((current->text)[i] == '\\')
	      fprintf (file, "\\\\");
	    else
	      fprintf (file, "%c", (current->text)[i]);
	  fprintf (file, "\\001\n");
	  break;

	case BOND_GROUP:
	  fig_write (current->group_members, file);
	  break;
	
	default:
	  bug_in ("fig_write");
	}

      if (BOND_HAS_TEXT (current))
        fig_write_orn_list (file, current->ornaments[0], current->x3,
                            current->y3);
      else
      {
        fig_write_orn_list (file, current->ornaments[0], current->x1,
                            current->y1);
        fig_write_orn_list (file, current->ornaments[1], current->x2,
                            current->y2);
      }
    }
  while ((current = current->next) != NULL);

}




void
fig_export (struct Bond *list, char *filename, GtkWindow * parent)
{
  GtkWidget *dialog;
  FILE *file;

  file = fopen (filename, "w");
  if (file == NULL)
    {
      dialog = gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT,
				       GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
				       _("Cannot open file '%s'"), filename);
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      return;
    }

  fprintf (file,
	   "#FIG 3.2\nLandscape\nCenter\nMetric\nLetter\n100.00\nSingle\n-2\n1200 2\n");

  fig_write (list, file);
  fclose (file);

}


void
pdf_export (struct Bond *list, char *filename, GtkWindow * parent)
{
#ifdef UNIX
  char *epsfile;
  gchar *option;
  int fd, pid, i, j, k, l;
  FILE *file;
  char *argv[9] = { "gs", "-dNOPAUSE", "-q", "-sDEVICE=pdfwrite", "-dBATCH",
    "-dSAFER", "", "", NULL
  };

/* First, we generate the intermediate EPS file */
  epsfile = g_strconcat (g_get_tmp_dir (), "/easychem_eps.XXXXXX", NULL);
  fd = mkstemp (epsfile);
  file = fdopen (fd, "w");
  eps_write (list, file, 2, 1);
  fclose (file);
  eps_bbox (list, epsfile, parent, &i, &j, &k, &l);
  unlink (epsfile);
  g_free (epsfile);

  epsfile = g_strconcat (g_get_tmp_dir (), "/easychem_eps.XXXXXX", NULL);
  fd = mkstemp (epsfile);
  file = fdopen (fd, "w");
  fprintf (file, "%%!PS-Adobe-2.0 EPSF-2.0\n");
  fprintf (file, "%%%%BoundingBox: 0 0 %d %d\n", k - i, l - j);
  fprintf (file, "<< /PageSize [%d %d] >> setpagedevice\n", k - i, l - j);
  fprintf (file, "gsave %d %d translate\n", -i, -j);
  eps_write (list, file, 1, 0);
  fclose (file);

  option = g_strdup_printf ("-sOutputFile=%s", filename);
  argv[6] = option;
  argv[7] = epsfile;
  pid = fork ();
  if (pid == 0)
    {
      if (prop.path_gs != NULL)
	execv (prop.path_gs, argv);
#ifdef GS_PATH
      execv (GS_PATH "/gs", argv);
#endif
      execvp ("gs", argv);
      execv ("/usr/bin/gs", argv);
      execv ("/usr/local/bin/gs", argv);
      execv ("/sw/bin/gs", argv);
      _exit (0);
    }
  wait (NULL);
  unlink (epsfile);
  g_free (epsfile);
#endif
}


/* This is used to export to a size-optimized EPS file (we write the
 * postscript code, and then use 'gs -sDEVICE=epswrite'). */
void
eps_size_export (struct Bond *list, char *filename, GtkWindow * parent)
{
#ifdef UNIX

#define BUFLEN 1024
  char buf[BUFLEN];
  char *epsfile, *epsfile2;
  gchar *option;
  int fd, pid, i, j, k, l;
  FILE *file, *in, *out;
  char *argv[11] = { "gs", "-dNOPAUSE", "-q", "-sDEVICE=epswrite", "-dBATCH",
    "-dSAFER", "", "", "-dDEVICEWIDTH=250000", "-dDEVICEHEIGHT=250000", NULL
  };

/* First, we generate the intermediate EPS file */
  epsfile = g_strconcat (g_get_tmp_dir (), "/easychem_eps.XXXXXX", NULL);
  fd = mkstemp (epsfile);
  file = fdopen (fd, "w");
  eps_write (list, file, 2, 1);
  eps_bbox (list, epsfile, parent, &i, &j, &k, &l);
  fputs ("%%Trailer\n", file);
  fprintf (file, "%%%%BoundingBox: %d %d %d %d\n", i, j, k, l);
  fputs ("%%EOF\n", file);
  fclose (file);

/* We run gs on it to optimize the size of the code */
  epsfile2 = g_strconcat (g_get_tmp_dir (), "/easychem_eps2.XXXXXX", NULL);
  option = g_strdup_printf ("-sOutputFile=%s", epsfile2);
  argv[6] = option;
  argv[7] = epsfile;
  pid = fork ();
  if (pid == 0)
    {
      if (prop.path_gs != NULL)
	execv (prop.path_gs, argv);
#ifdef GS_PATH
      execv (GS_PATH "/gs", argv);
#endif
      execvp ("gs", argv);
      execv ("/usr/bin/gs", argv);
      execv ("/usr/local/bin/gs", argv);
      execv ("/sw/bin/gs", argv);
      _exit (0);
    }
  wait (NULL);
  unlink (epsfile);
  g_free (epsfile);

/* We correct the bouding box */
  in = fopen (epsfile2, "r");
  out = fopen (filename, "w");

  while (fgets (buf, BUFLEN, in) != NULL)
  {
    if (strncmp (buf, "%%BoundingBox:", 14) == 0)
      fprintf (out, "%%%%BoundingBox: %d %d %d %d\n", i, j, k, l);
    else
      if (strncmp (buf, "%%HiResBoundingBox:", 19) != 0)
        fputs (buf, out);
  }

  fclose (in);
  fclose (out);

  unlink(epsfile2);
  g_free(epsfile2);

#endif
}


void
fig_pstoedit_export (struct Bond *list, char *filename, GtkWindow * parent)
{
#ifdef UNIX

  char *epsfile;
  int fd, pid, i, j, k, l;
  FILE *file;
  char *argv[6] = { "pstoedit", "-f", "xfig", "", "", NULL };

/* First, we generate the intermediate EPS file */
  epsfile = g_strconcat (g_get_tmp_dir (), "/easychem_eps.XXXXXX", NULL);
  fd = mkstemp (epsfile);
  file = fdopen (fd, "w");
  eps_write (list, file, 2, 1);
  fclose (file);
  eps_bbox (list, filename, parent, &i, &j, &k, &l);

/* Now we modify the file to add the bounding box. */
  fputs ("%%Trailer\n", file);
  fprintf (file, "%%%%BoundingBox: %d %d %d %d\n", i, j, k, l);
  fputs ("%%EOF\n", file);
  fclose (file);

  argv[3] = epsfile;
  argv[4] = filename;
  pid = fork ();
  if (pid == 0)
    {
      if (prop.path_pstoedit != NULL)
	execv (prop.path_pstoedit, argv);
#ifdef PSTOEDIT_PATH
      execv (PSTOEDIT_PATH "/pstoedit", argv);
#endif
      execvp ("pstoedit", argv);
      execv ("/usr/bin/pstoedit", argv);
      execv ("/usr/local/bin/pstoedit", argv);
      execv ("/sw/bin/pstoedit", argv);
      _exit (0);
    }
  wait (NULL);
  unlink (epsfile);
  g_free (epsfile);

#endif
}
