/*
Copyright (c) 2004-2005, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  its contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/

#define DKFIGTO2_C 1
#include "dkfig.h"

#line 40 "dkfigto2.ctr"



static char str_mode_read_binary[] = { "rb" };
static char str_mode_read_text[] = { "r" };
static char str_auto[] = { "auto" };
static char str_utf8[] = { ".UTF-8" };
static char str_open_math_mode[] = { "\\(" };
static char str_close_math_mode[] = { "\\)" };

int
dkfig_tool2_compare_image_width DK_P3(void *,l, void *,r, int,c)
{
  int back = 0;
  dkfig_bitmap_width *wl, *wr;
  
  if(l) {
    if(r) {
      wl = (dkfig_bitmap_width *)l; wr = (dkfig_bitmap_width *)r;
      if(wl->width > wr->width) {
        back = 1;
      } else {
        if(wl->width < wr->width) {
	  back = -1;
	}
      }
      if(back == 0) {
        if(wl->colored) {
	  if(!(wr->colored)) {
	    back = 1;
	  }
	} else {
	  if(wr->colored) {
	    back = -1;
	  }
	}
      }
      if(back == 0) {
        if(wl->seprgb) {
	  if(wr->seprgb) {
	    if(wl->height > wr->height) {
	      back = 1;
	    } else {
	      if(wl->height < wr->height) {
	        back = -1;
	      }
	    }
	  } else {
	    back = -1;
	  }
	} else {
	  if(wr->seprgb) {
	    back = -1;
	  }
	}
      }
      /*
      if(back == 0) {
        if(wl->fl == 2) {
	  if(wr->fl != 2) {
	    back = 1;
	  }
	} else {
	  if(wr->fl == 2) {
	    back = -1;
	  }
	}
      } 
      */
    } else {
      back = 1;
    }
  } else {
    if(r) {
      back = -1;
    }
  } 
  return back;
}


dk_storage_t *
dkfig_tool2_image_width_storage DK_P0()
{
  dk_storage_t *back = NULL;
  back = dksto_open(0);
  if(back) {
    dksto_set_comp(back, dkfig_tool2_compare_image_width, 1);
  }
  return back;
}



dkfig_bitmap_width *
dkfig_tool2_find_entry_for_width DK_P6(\
  dk_storage_iterator_t *,it, long,width, long,height,\
  int,colored, int,seprgb,int,fl\
)
{
  dkfig_bitmap_width w, *back = NULL;
  
  if(it) {
    w.width = width;
    w.height = height;
    if(fl == 2) {	
      w.width = height;
      w.height = width;
    }
    w.colored = colored;
    w.seprgb = seprgb;
    back = (dkfig_bitmap_width *)dksto_it_find_like(it, (void *)(&w), 0);
  }
  
  return back;
}



int
dkfig_tool2_add_image_width DK_P7(\
  dk_storage_t *,st,\
  dk_storage_iterator_t *,it,\
  long,width,\
  long,height,\
  int,colored,\
  int,seprgb,\
  int,fl\
)
{
  int back = 0;
  dkfig_bitmap_width w, *ptr;
  
  if(st && it) {
    w.width = width;
    if(dkfig_tool2_find_entry_for_width(
      it, width, height,colored,seprgb,fl)
    )
    {
      back = 1;		
    } else {		
      ptr = dk_new(dkfig_bitmap_width,1);
      if(ptr) {
        ptr->width = width; ptr->height = height;
	ptr->colored = colored; ptr->seprgb = seprgb;
	/* ptr->fl = fl; */
	if(fl == 2) {	
	  ptr->width = height;
	  ptr->height = width;
	} 
	if(dksto_add(st, (void *)ptr)) {
	  back = 1;	
	} else {	
	  dk_delete(ptr);
	}
      } else {		
      }
    }
  } else {		
  }
  
  return back;
}



/* {{{ dkfig_tool2_imple_error_message

   Print simple error message (message consisting
   of one string).

*/
void
dkfig_tool2_simple_error_message DK_P2(\
  dk_fig_conversion *,c, size_t,i\
)
{
  dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, i);
} /* }}} */



/* {{{ dkfig_tool2_simple_error_message

   Print simple error message (message consisting
   of one string).

*/
void
dkfig_tool2_eps_error_message DK_P2(\
  dkfig_eps_output_instruction *,oi, size_t,i\
)
{
  if(oi) {
    dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, i);
  }
} /* }}} */



/* {{{ dkfig_tool2_simple_error_message

   Print simple error message (message consisting
   of one string).

*/
void
dkfig_tool2_svg_error_message DK_P2(\
  dkfig_svg_output_instruction *,oi, size_t,i\
)
{
  if(oi) {
    dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, i);
  }
} /* }}} */



/* {{{ dkfig_tool2_simple_error_message

   Print combined error message (string, filename string).

*/
void
dkfig_tool2_combined_error_message DK_P4(\
  dk_fig_conversion *,c, size_t,i1, size_t,i2, char *,fn\
)
{
  dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, i1, i2, fn);
} /* }}} */



/* {{{ dkfig_tool2_simple_progress_message
*/
void
dkfig_tool2_simple_progress_message DK_P2(dk_fig_conversion *,c, size_t,i)
{
  dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, i);
} /* }}} */



void
dkfig_tool2_report_special_comment DK_P3(\
  dk_fig_conversion *,c,dk_fig_opt *,speccom,int,i\
)
{
  char *msg[3];
  if((c) && (speccom)) {
    if((c->app) && (c->msg1)) {
      switch(i) {
	case 0: {	/* unknown key */
	  dkapp_set_source_lineno(c->app, speccom->number);
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 86, 92, speccom->name);
	  dkapp_set_source_lineno(c->app, 0UL);
	} break;
	case -1: {	/* wrong driver */
	  dkapp_set_source_lineno(c->app, speccom->number);
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 87, 92, speccom->name);
	  dkapp_set_source_lineno(c->app, 0UL);
	} break;
	case -2: {	/* not per-instance */
	  dkapp_set_source_lineno(c->app, speccom->number);
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 88, 92, speccom->name);
	  dkapp_set_source_lineno(c->app, 0UL);
	} break;
	case -3: {	/* other error */
	  dkapp_set_source_lineno(c->app, speccom->number);
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 89, 92, speccom->name);
	  dkapp_set_source_lineno(c->app, 0UL);
	} break;
      }
    }
  }
}




void
dkfig_tool2_report_unused_options DK_P1(\
  dk_fig_conversion *,c\
)
{
  dk_fig_opt *op;
  char *msg[3];
  if(c) {
  if((c->app) && (c->msg1)) {
    char *oldname; unsigned long oldno;
    oldname = dkapp_get_source_filename(c->app);
    oldno = dkapp_get_source_lineno(c->app);
    dkapp_set_source_filename(c->app, NULL);
    dkapp_set_source_lineno(c->app, 0UL);
    /* command line options */
    if((c->opt) && (c->opti)) {
      dksto_it_reset(c->opti);
      while((op = (dk_fig_opt *)dksto_it_next(c->opti)) != NULL) {
        if(!(op->used)) {
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 90, 92, op->name);
	}
      }
    }
    /* config file */
    if(c->cfgfn) {
      dkapp_set_source_filename(c->app, c->cfgfn);
    }
    /* configuration section */
    if((c->optd) && (c->optdi)) {
      dksto_it_reset(c->optdi);
      while((op = (dk_fig_opt *)dksto_it_next(c->optdi)) != NULL) {
        if(!(op->used)) {
	  dkapp_set_source_lineno(c->app, op->number);
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 91, 92, op->name);
	}
      }
    }
    /* driver section */
    if((c->optb) && (c->optbi)) {
      dksto_it_reset(c->optbi);
      while((op = (dk_fig_opt *)dksto_it_next(c->optbi)) != NULL) {
        if(!(op->used)) {
	  dkapp_set_source_lineno(c->app, op->number);
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 91, 92, op->name);
	}
      }
    }
    /* global section */
    if((c->optg) && (c->optgi)) {
      dksto_it_reset(c->optgi);
      while((op = (dk_fig_opt *)dksto_it_next(c->optgi)) != NULL) {
        if(!(op->used)) {
	  dkapp_set_source_lineno(c->app, op->number);
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_WARNING, 91, 92, op->name);
	}
      }
    }
    dkapp_set_source_filename(c->app, oldname);
    dkapp_set_source_lineno(c->app, oldno);
  }
  }
}



static
int
pbm_image_size DK_P4(\
  dk_fig_conversion *,c, char *,fn,\
  unsigned long *,w, unsigned long *,h\
)
{
  int back = 0;
#if HAVE_PNM_H
  FILE *f = NULL;
  xelval maxxelval = 0;
  int cols = 0, rows = 0, format = 0;
  xel **array;
  
  if(c->app) {
    f = dkapp_fopen(c->app, fn, str_mode_read_binary);
  } else {
    f = dksf_fopen(fn, str_mode_read_binary);
  }
  if(f) {
    array = pnm_readpnm(f, &cols, &rows, &maxxelval, &format);
    if(array) {
      *w = (unsigned long)cols;
      *h = (unsigned long)rows;
      back = 1;
      
      pnm_freearray(array, rows);
    }
    fclose(f); f = NULL;
  }
  
#endif
  return back;
}



static
int
png_image_size DK_P4(\
  dk_fig_conversion *,c, char *,fn,\
  unsigned long *,w, unsigned long *,h\
)
{
  int back = 0;
#if DK_HAVE_ZLIB_H
#if HAVE_PNG_H
  FILE *f = NULL;
  png_uint_32 ui32 = 0, width = 0, height = 0;
  int bd = 0, ct = 0, zt = 0, it = 0, ft = 0;
  png_structp pp = NULL; png_infop pi = NULL;
  
  if(c->app) {
    f = dkapp_fopen(c->app, fn, str_mode_read_binary);
  } else {
    f = dksf_fopen(fn, str_mode_read_binary);
  }
  if(f) {
    pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL ,NULL, NULL);
    if(pp) {
      pi = png_create_info_struct(pp);
      if(pi) {
#if HAVE_SETJMP_H
        if(setjmp(pp->jmpbuf) == 0) {
#endif
          png_init_io(pp, f);
	  png_read_info(pp, pi);
	  ui32 = png_get_IHDR(pp, pi, &width, &height, &bd, &ct, &it, &zt, &ft);
	  if(width && height) {
	    *w = (unsigned long)width;
	    *h = (unsigned long)height;
	    back = 1;
	    
	  } else {
	    dkfig_tool2_combined_error_message(c, 96, 97, fn);
	  }
#if HAVE_SETJMP_H
	} else {
	  
	  dkfig_tool2_combined_error_message(c, 96, 97, fn);
	}
#endif
        png_destroy_info_struct(pp, &pi); pi = NULL;
      }
      png_destroy_read_struct(&pp, NULL, NULL); pp = NULL;
    }
    fclose(f); f = NULL;
  }
  
#endif
#endif
  return back;
}


#if HAVE_JPEGLIB_H
static int had_error = 0;
static void error_exit_replacement DK_P1(j_common_ptr,cinfo)
{
  had_error = 1;
}
#endif



static
int
jpg_image_size DK_P4(\
  dk_fig_conversion *,c, char *,fn,\
  unsigned long *,w, unsigned long *,h\
)
{
  int back = 0;
#if HAVE_JPEGLIB_H
  FILE *f = NULL;
  JDIMENSION width, height;
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
  
  had_error = 0;
  cinfo.err = jpeg_std_error(&jerr);
  jerr.error_exit = error_exit_replacement;
  jpeg_create_decompress(&cinfo);
  if(!had_error) {
    if(c->app) {
      f = dkapp_fopen(c->app, fn, str_mode_read_binary);
    } else {
      f = dksf_fopen(fn, str_mode_read_binary);
    }
    if(f) {
      jpeg_stdio_src(&cinfo, f);
      if(!had_error) {
        jpeg_read_header(&cinfo, TRUE);
	if(!had_error) {
	  width = cinfo.output_width;
	  height = cinfo.output_height;
	  if(width && height) {
	    *w = (unsigned long)width;
	    *h = (unsigned long)height;
	    back = 1;
	    
	  }
	}
      }
      jpeg_abort((j_common_ptr)(&cinfo));
      fclose(f); f = NULL;
    }
  }
  
#endif
  return back;
}



static char bb_search[] = { "%%BoundingBox:" };


static
int
eps_image_size DK_P4(\
  dk_fig_conversion *,c, char *,fn,\
  unsigned long *,w, unsigned long *,h\
)
{
  int back = 0;
  int state = 0;
  long llx, lly, urx, ury, deltax, deltay;
  char inputline[1024];
  FILE *f = NULL;
  size_t minlgt; char *ptr;
  
  llx = lly = urx = ury = deltax = deltay = 0L;
  if(c->app) {
    f = dkapp_fopen(c->app, fn, str_mode_read_text);
  } else {
    f = dksf_fopen(fn, str_mode_read_text);
  }
  if(f) {
    minlgt = strlen(bb_search);
    while(state < 2) {
      if(fgets(inputline, sizeof(inputline), f)) {
        if(strlen(inputline) > minlgt) {
	  if(strncmp(inputline, bb_search, minlgt) == 0) {
	    ptr = dkstr_start(&(inputline[minlgt]), NULL);
	    if(ptr) {
	      if(sscanf(ptr, "%ld %ld %ld %ld", &llx, &lly, &urx, &ury) == 4) {
	        back = 1;
		deltax = urx - llx;
		deltay = ury - lly;
		if(deltax < 0L) { deltax = 0L - deltax; }
		if(deltay < 0L) { deltay = 0L - deltay; }
		*w = (unsigned long)deltax;
		*h = (unsigned long)deltay;
		
		if(state == 0) {
		  state = 2;
		}
	      } else {
	        state = 1;
	      }
	    }
	  }
	}
      } else {
        state = 3;
      }
    }
    fclose(f); f = NULL;
  }
  
  return back;
}



int
dkfig_tool2_get_image_size DK_P4(\
  dk_fig_conversion *,c, char *,fn,\
  unsigned long *,w, unsigned long *,h\
)
{
  int back = 0;
  int ft;
  if((fn) && (w) && (h)) {
    *w = 0UL; *h = 0UL;
    ft = dkfig_ei_get_image_type(fn);
    if(ft >= 0) {
      switch(ft) {
        case 0: {	/* PS/EPS */
	  back = eps_image_size(c, fn, w, h);
	} break;
	case 1: {	/* PNG */
	  back = png_image_size(c, fn, w, h);
	} break;
	case 2: {	/* JPEG */
	  back = jpg_image_size(c, fn, w, h);
	} break;
	case 3: {	/* NetPBM */
	  back = pbm_image_size(c, fn, w, h);
	} break;
      }
    }
  }
  return back;
}



int
dkfig_tool2_obj_is_bg_rect DK_P2(dk_fig_object *,o, int,wbgr)
{
  int back = 0;
  
  if(o->layer == 999L) {
    if(o->objtype == DK_FIG_OBJ_POLYLINE) {
      if(o->subtype == 2) {
        if((o->fpd).lt == 0L) {
	  if((o->fpd).af == -1) {
	    if(wbgr) {
	      if((o->fpd).pc == 7) {
	        back = 1;
	      }
	    } else  {
              if((o->fpd).pc == -1) {
	        back = 1;
	      }
	    }
	  }
	}
      }
    }
  } 
  return back;
}



double
dkfig_tool2_drd DK_P3(double,v, dk_fig_conversion *,c, int,w)
{
  double back;
  back = v;
  if(c) {
  switch(w) {
    case 1: {
      back = dkma_double_restrict_digits(back, c->nodcoord);
    } break;
    case 2: {
      back = dkma_double_restrict_digits(back, (c->nodcoord + c->nodtrigo));
    } break;
    default: {
      back = dkma_double_restrict_digits(back, c->nodcolor);
    } break;
  }
  }
  return back;
}



int
dkfig_tool2_utf8_auto DK_P1(dk_fig_conversion *,c)
{
  int back = 0;
  char *ptr1, *ptr2;
  
  if(c) {
    c->opt2 |= DKFIG_OPT_UTF_AUTO;
    ptr1 = getenv("LANG");
    if(ptr1) {
      back = 1;
      ptr2 = strchr(ptr1, '.');
      if(ptr2) {
        if(dkstr_casecmp(ptr2, str_utf8) == 0) {
	  c->opt2 |= DKFIG_OPT_UTF_8;	
	} else {			
	  c->opt2 &= (~(DKFIG_OPT_UTF_8));
	}
      } else {				
        c->opt2 &= (~(DKFIG_OPT_UTF_8));
      }
    } else {				
      c->opt2 &= (~(DKFIG_OPT_UTF_8));
    }
  } 
  return back;
}


int
dkfig_tool2_set_utf8 DK_P3(dk_fig_conversion *,c, char *,v, int,allow_auto)
{
  int back = 0;
  char *ptr1;
  
  if((c) && (v)) {
    ptr1 = dkstr_start(v, NULL);
    if(ptr1) {
      dkstr_chomp(ptr1, NULL);
      if(dkstr_is_bool(ptr1)) {
        if(dkstr_is_on(ptr1)) {	
	  c->opt2 |= DKFIG_OPT_UTF_8;
	} else {		
	  c->opt2 &= (~(DKFIG_OPT_UTF_8));
	}
	c->opt2 &= (~(DKFIG_OPT_UTF_AUTO));
	back = 1;
      } else {
	if(dkstr_casecmp(ptr1, str_auto) == 0) {
	  
	  back = dkfig_tool2_utf8_auto(c);
	}
      }
    }
  } 
  return back;
}



void
dkfig_tool2_msg3 DK_P5(\
  dk_fig_conversion *,c, int,l, size_t,s1, size_t,s2, char *,t\
)
{
  char *msgs[3];
  if((c) && (t)) {
  if(c->msg1) {
    if(c->app) {
      msgs[0] = (c->msg1)[s1];
      msgs[1] = t;
      msgs[2] = (c->msg1)[s2];
      dkapp_log_msg(c->app, l, msgs, 3);
    } else {
    }
  }
  }
}



void
dkfig_tool2_msg1 DK_P3(dk_fig_conversion *,c, int,l, size_t,s1)
{
  if(c) {
  if(c->msg1) {
    if(c->app) {
      dkapp_log_msg(c->app, l, &((c->msg1)[s1]), 1);
    } else {
    }
  }
  }
}



static
void
error_no_table_found DK_P2(dk_fig_conversion *,c, dk_udword,ucb)
{
  char buffer[32];
  sprintf(buffer, "0x%08lx", ucb);
  dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 123, 124, buffer);
}



static
void
error_no_encoding_found DK_P2(dk_fig_conversion *,c, dk_udword,ucb)
{
  char buffer[32];
  sprintf(buffer, "0x%08lx", ucb);
  dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 125, 126, buffer);
}



void
dkfig_tool2_utf8_to_latex DK_P3(dk_stream_t *,os, dk_fig_conversion *,c, char *,t)
{
  dk_udword ucb;
  int cc, mm;
  size_t max, used, avail, step;
  char *found;
  
  cc = 1; max = strlen(t); used = 0; avail = max;
  mm = 0;	/* not in math mode by default */
  while(cc) {
    cc = 0;
    if(avail > 0) {
      step = 0;
      cc = dkenc_utf82uc(&ucb, (unsigned char *)(&(t[used])), avail, &step);
      if(cc) {
	found = NULL;
	if(dkle_load(c->uc2lat, ucb)) {
	  
	  found = dkle_get_encoding(c->uc2lat, ucb, 0);
	  if(found) {
	    
	    if(mm) {
	      
	      dkstream_puts(os, str_close_math_mode); mm = 0;
	    }
	    dkstream_puts(os, found);
	  } else {
	    
	    found = dkle_get_encoding(c->uc2lat, ucb, 1);
	    if(found) {
	      
	      if(mm == 0) {
	        
	        dkstream_puts(os, str_open_math_mode); mm = 1;
	      }
	      dkstream_puts(os, found);
	    } else {
	      if(ucb < 256UL) {
	        
	        found = dk_l2l_encoding((unsigned char)ucb);
		if(found) {
		  
		  if(mm) {
		    
		    dkstream_puts(os, str_close_math_mode); mm = 0;
		  }
		  dkstream_puts(os, found);
		} else {
		  error_no_encoding_found(c, ucb);
		}
	      } else {
		error_no_encoding_found(c, ucb);
	      }
	    }
	  }
	} else {
	  
	  if(ucb < 256UL) {
	    
	    found = dk_l2l_encoding((unsigned char)ucb);
	    if(found) {
	      
	      if(mm) {
	        
	        dkstream_puts(os, str_close_math_mode); mm = 0;
	      }
	      dkstream_puts(os, found);
	    } else {
	      error_no_encoding_found(c, ucb);
	    }
	  } else {
	    error_no_table_found(c, ucb);
	  }
	}
	used = used + step;
	if(avail > step) {
	  avail = avail - step;
	} else {
	  avail = 0;
	}
      }
    }
  }
  if(mm) {
    dkstream_puts(os, str_close_math_mode); mm = 0;
  } 
}



/* {{{ SCCS ID */
#ifndef LINT
static char sccs_id[] = {
"@(#)dkfigto2.ctr 1.62 05/29/07\t(krause) - fig2vect"
};
#endif
/* }}} */
