#include "alberta.h"

#define X(x)  ((x-x_min)*diam_x_1)
#define Y(y)  ((y-y_min)*diam_y_1)

void write_mesh_ps(MESH *mesh, const char *filename, const char *title,
		   const REAL x[2], const REAL y[2],
		   bool keepaspect, bool draw_bound)
{
  FUNCNAME("write_mesh_ps");
#if DIM_OF_WORLD == 2
  REAL               x_min, x_max, y_min, y_max, diam_x_1, diam_y_1;
  int                i, m;
  MACRO_EL           *mel;
  FILE               *psFile;
  TRAVERSE_STACK     *stack = get_traverse_stack();
  const EL_INFO      *el_info;
#endif

  if (!mesh) return;

  if((mesh->dim != 2) || (DIM_OF_WORLD != 2)) {
    ERROR("This routine is only implemented for dim==DIM_OF_WORLD==2!\n");
    return;
  } 

#if DIM_OF_WORLD == 2
  x_max = y_max = -LARGE;
  x_min = y_min = LARGE;
  for (m = 0; m < mesh->n_macro_el; m++) {
    mel = mesh->macro_els + m;

    for (i = 0; i < N_VERTICES_2D; i++)
    {
      x_max = MAX(x_max, (*mel->coord[i])[0]);
      y_max = MAX(y_max, (*mel->coord[i])[1]);
      x_min = MIN(x_min, (*mel->coord[i])[0]);
      y_min = MIN(y_min, (*mel->coord[i])[1]);
    }
  }

  if (x && x[0] != x[1]) {
    REAL xx;
    xx = MAX(x[1], x_min);
    x_max = MIN(x_max,xx);
    xx = MIN(x[0], x_max);
    x_min = MAX(x_min,xx);
  }

  if (y && y[0] != y[1])
  {
    REAL yy;
    yy = MAX(y[1], y_min);
    y_max = MIN(y_max,yy);
    yy = MIN(y[0], y_max);
    y_min = MAX(y_min,yy);
  }
  diam_x_1 = x_max - x_min ? 1.0/(x_max - x_min) : 1.0;
  diam_y_1 = y_max - y_min ? 1.0/(y_max - y_min) : 1.0;
  if (keepaspect)
    diam_x_1 = diam_y_1 = MIN(diam_x_1, diam_y_1);

  if (!(psFile = fopen(filename, "w")))
  {
    MSG("cannot open PS file for writing\n");
    return;
  }

  fprintf(psFile,"%%!PS-Adobe-2.0 EPSF-1.2\n");
  fprintf(psFile,"%%%%Creator: ALBERTAPostScript driver for 2d\n");
  fprintf(psFile,"%%%%Title: %s\n", title ? title : "ALBERTAOutput");
  fprintf(psFile,"%%%%Pages: 1\n");
  fprintf(psFile,"%%%%DocumentFonts: Times-Roman\n");
  fprintf(psFile,"%%%%BoundingBox: 200 200 %.3f %.3f\n", 
	  200.0*(1.0 + X(x_max)), 200.0*(1.0 + Y(y_max)));
  fprintf(psFile,"%%%%EndComments\n");
  fprintf(psFile,"%%begin(plot)\n");
  fprintf(psFile,"200 200 translate\n");
  fprintf(psFile,"200 200 scale %% 72 = 1in, 200 ~ 7cm\n");
  fprintf(psFile,"/mm { 0.01132 mul } def\n");
  fprintf(psFile,"/m { moveto } def\n");
  fprintf(psFile,"/l { lineto } def\n");
  fprintf(psFile," %.3f %.3f m\n", 0.0, 0.0);
  fprintf(psFile," %.3f %.3f l\n", X(x_max), 0.0);
  fprintf(psFile," %.3f %.3f l\n", X(x_max), Y(y_max));
  fprintf(psFile," %.3f %.3f l\n", 0.0, Y(y_max));
  fprintf(psFile,"closepath\n");
  if (!draw_bound) fprintf(psFile, "%%");
  fprintf(psFile,"gsave 0.5 mm setlinewidth stroke grestore\n");
  fprintf(psFile,"clip\n");
  fprintf(psFile, "0.25 mm setlinewidth 1 setlinejoin 1 setlinecap\n");
  fprintf(psFile," 0 0 0 setrgbcolor\n");
  fprintf(psFile, "/Times-Roman findfont 5 mm scalefont setfont 0 setgray\n");

  fprintf(psFile,"%% ENDE DES PROLOGS XXXXXXXXXXXXXXXXXXX\n");

  if (title) fprintf(psFile,"0.1 1.05 m\n (%s) show\n",title);

  fprintf(psFile, "0.25 mm setlinewidth 1 setlinejoin 1 setlinecap\n");
  for (m = 0; m < mesh->n_macro_el; m++) {
    mel = mesh->macro_els + m;

    for (i = 0; i < N_EDGES_2D; i++) {
      if (!IS_INTERIOR(mel->wall_bound[i])) {
	fprintf(psFile,"newpath\n");
	fprintf(psFile,"%f %f m\n", 
		X((*mel->coord[(i+1)%3])[0]), Y((*mel->coord[(i+1)%3])[1])); 
	fprintf(psFile,"%f %f l\n", 
		X((*mel->coord[(i+2)%3])[0]), Y((*mel->coord[(i+2)%3])[1])); 
	fprintf(psFile,"stroke\n");
      }
    }
  }

  fprintf(psFile, "0.25 mm setlinewidth 1 setlinejoin 1 setlinecap\n");

  if (draw_bound)
  {
    fprintf(psFile,"%% begin domains boundary\n");
#if 1
    fprintf(psFile, "0.5 mm setlinewidth 1 setlinejoin 1 setlinecap\n");
    for (m = 0; m < mesh->n_macro_el; m++) {
      mel = mesh->macro_els + m;

      for (i = 0; i < N_WALLS_2D; i++) {
	if (!IS_INTERIOR(mel->wall_bound[i]))
	{
	  fprintf(psFile,"newpath\n");
	  fprintf(psFile,"%f %f m\n", 
		  X((*mel->coord[(i+1)%3])[0]), Y((*mel->coord[(i+1)%3])[1])); 
	  fprintf(psFile,"%f %f l\n", 
		  X((*mel->coord[(i+2)%3])[0]), Y((*mel->coord[(i+2)%3])[1])); 
	  fprintf(psFile,"stroke\n");
	}
      }
    }
    fprintf(psFile, "0.25 mm setlinewidth 1 setlinejoin 1 setlinecap\n");
#else
    fprintf(psFile,"newpath\n");
    fprintf(psFile,"%f %f m\n", X(x_min), Y(y_min));
    fprintf(psFile,"%f %f l\n", X(x_max), Y(y_min));
    fprintf(psFile,"%f %f l\n", X(x_max), Y(y_max));
    fprintf(psFile,"%f %f l\n", X(x_min), Y(y_max));
    fprintf(psFile,"%f %f l\n", X(x_min), Y(y_min));
    fprintf(psFile,"stroke\n");
#endif
    fprintf(psFile,"%% end domains boundary\n");
  }

  el_info = traverse_first(stack, mesh, -1, CALL_LEAF_EL|FILL_COORDS);
  while(el_info)
  {
    REAL  x, y;
    int   i;

    for (i = 0; i < N_VERTICES_2D; i++)
    {
      x = X(el_info->coord[i][0]);
      y = Y(el_info->coord[i][1]);

      if (x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0)
	break;
    }
    if (i < N_VERTICES_2D)
    {
      fprintf(psFile,"newpath\n");

      fprintf(psFile,"%f %f m\n", 
	      X(el_info->coord[0][0]), Y(el_info->coord[0][1]));
      fprintf(psFile,"%f %f l\n", 
	      X(el_info->coord[1][0]), Y(el_info->coord[1][1])); 
      fprintf(psFile,"%f %f l\n", 
	      X(el_info->coord[2][0]), Y(el_info->coord[2][1])); 

      fprintf(psFile,"stroke\n");
    }

    el_info = traverse_next(stack, el_info);
  }

  fprintf(psFile,"showpage\n");
  fclose(psFile);
#endif /* DIM_OF_WORLD == 2 */
  return;
}
