# include "Ximage.h"
# define MIN_RANGE 1e-10
# define DrawLine(X,Y,DX,DY) (XDrawLine (graphic->display, graphic->window, graphic->gc, (int)(X), (int)(Y), (int)(X+DX), (int)(Y+DY)))
  
static Graphic *graphic;

void DrawFrame (KapaGraphWidget *graph) {
  
  int i, fx, fy, dfx, dfy, P, IsLabel, IsMajor;
  double range, major, minor, first, next, lweight;

  graphic = GetGraphic();

  /* each axis is drawn independently, but ticks and labels are placed according to
     perpendicular distance. */
  for (i = 0; i < 4; i++) {
    fx = graph[0].axis[i].fx;
    fy = graph[0].axis[i].fy;
    dfx = graph[0].axis[i].dfx;
    dfy = graph[0].axis[i].dfy;
    P = hypot ((double)graph[0].axis[(i+1)%2].dfx, (double)graph[0].axis[(i+1)%2].dfy);

    lweight = MAX (0, MIN (10, graph[0].axis[i].lweight));
    XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CapNotLast, JoinMiter);
    XSetForeground (graphic->display, graphic->gc, graphic->color[graph[0].axis[i].color]);
    DrawRotTextInit (graphic->display, graphic->window, graphic->gc, graphic->color[graph[0].axis[i].color], graphic->back);

    if (graph[0].axis[i].isaxis) {
      DrawLine (fx, fy, dfx, dfy);
    }
    
    if (graph[0].axis[i].areticks) {
      if (isnan(graph[0].axis[i].min) || isinf(graph[0].axis[i].min)) continue;
      if (isnan(graph[0].axis[i].max) || isinf(graph[0].axis[i].max)) continue;

      range = graph[0].axis[i].max - graph[0].axis[i].min;
      if (fabs(range) < MIN_RANGE) continue;

      if (fabs(range) < MIN_RANGE) {
	range = (range < 0) ? -MIN_RANGE : +MIN_RANGE;
      }

      AxisTickScale (&graph[0].axis[i], &major, &minor);

      first = minor*((int)(graph[0].axis[i].min/minor));
      if ((range > 0) && (first < graph[0].axis[i].min)) {
	first += minor;
      }
      if ((range < 0) && (first > graph[0].axis[i].min)) {
	first -= minor;
      }
      for (next = first; ((range > 0) && (next <= graph[0].axis[i].max)) || ((range < 0) && (next >= graph[0].axis[i].max));) {
	IsMajor = FALSE;
	IsMajor |= (fabs((int)(next/major) - (next/major)) < 0.5*(minor/major));
	IsMajor |= (fabs((int)((next + 0.5*minor)/major) - (next/major)) < 0.5*(minor/major));
	IsMajor |= (fabs ((int)((next - 0.5*minor)/major) - (next/major)) < 0.5*(minor/major));
	IsLabel = (IsMajor && graph[0].axis[i].islabel);
	DrawTick (fx, fy, dfx, dfy, P, graph[0].axis[i].min, graph[0].axis[i].max, next, IsLabel, IsMajor, i);
	if (range > 0) 
	  next += minor;
	else 
	  next -= minor;
      }
    }
  }
}

void DrawTick (int fx, int fy, int dfx, int dfy, 
	       int P, double min, double max, 
	       double value, int IsLabel, int IsMajor, int naxis) {
  
  int x, y, dx, dy, pos, dir, fontsize;
  double size, n;
  char string[64], *fontname;

  if (IsMajor) { 
    size = MAX (0.02, 7.0 / P); 
  } else {
    size = MAX (0.01, 4.0 / P); 
  }
  
  n = P / sqrt ((double)(dfx*dfx + dfy*dfy));
  x = fx + (value-min)*dfx/(max - min);
  y = fy + (value-min)*dfy/(max - min);

  dir = +1;
  if ((naxis == 0) || (naxis == 1)) dir *= -1;
  dx = dir*size*dfy*n;	
  dy = dir*size*dfx*n;
  
  DrawLine (x, y, dx, dy);

# ifdef IN_AND_OUT_TICKS
# define GAP 0.03
# else
# define GAP 0.01
# endif

  if (IsLabel) {
    fontname = GetRotFont (&fontsize);
    pos = 0;
    
    /* temporarily assume rectilinear axes */
    if (naxis == 0) { dx = 0; dy = -dir*(0.8*fontsize + 1); pos = 1; }
    if (naxis == 2) { dx = 0; dy = -dir*(0.8*fontsize + 1); pos = 7; }

    if (naxis == 1) { dy = 0; dx = -(0.8*fontsize + 1); pos = 3; }
    if (naxis == 3) { dy = 0; dx = +(0.8*fontsize + 1); pos = 5; }

    x = fx + (value-min)*dfx/(max - min) + dx;
    y = fy + (value-min)*dfy/(max - min) + dy;
    if (fabs(value/(max-min)) < 0.001) { value = 0.0; }
    sprintf (string, "%4g", value);
    DrawRotText (x, y, string, pos, 0.0);
  }
  
}


void AxisTickScale (Axis *axis, double *major, double *minor) {

  double range, lrange, factor, mantis, fmantis, power;

  range = axis[0].max - axis[0].min;
  if (fabs(range) < MIN_RANGE) {
    range = (range < 0) ? -MIN_RANGE : +MIN_RANGE;
  }

  lrange = log10(MAX(fabs(range), MIN_RANGE));
  mantis = modf (lrange, &factor);
  if (mantis < 0.0) {
    mantis += 1.0;
    factor -= 1.0;
  }
  
  power = MAX(pow(10.0, factor), MIN_RANGE);
  fmantis = pow(10.0, mantis);
  *major = MAX(0.5 * power, MIN_RANGE);
  *minor = MAX(0.1 * power, MIN_RANGE);
  
  if ((fmantis >= 1.0) && (fmantis <  1.999)) {
    *major = 0.5 * power;
    *minor = 0.1 * power;
    if (axis[0].areticks == 1) {
      *major = 1.0 * power;
      *minor = 0.2 * power;
    }	  
  }
  if ((fmantis >= 1.999) && (fmantis <  3.999)) {
    *major = 1.0 * power;
    *minor = 0.2 * power;
    if (axis[0].areticks == 1) {
      *major = 2.0 * power;
      *minor = 0.5 * power;
    }	  
  }
  if ((fmantis >= 3.999) && (fmantis <  5.999)) {
    *major = 1.0 * power;
    *minor = 0.5 * power;
    if (axis[0].areticks == 1) {
      *major = 2.0 * power;
      *minor = 0.5 * power;
    }	  
  }
  if ((fmantis >= 5.999) && (fmantis <   7.999)) {
    *major = 2.0 * power;
    *minor = 0.5 * power;
    if (axis[0].areticks == 1) {
      *major = 2.5 * power;
      *minor = 0.5 * power;
    }	  
  }
  if ((fmantis >= 7.999) && (fmantis <  10.000)) {
    *major = 2.5 * power;
    *minor = 0.5 * power;
    if (axis[0].areticks == 1) {
      *major = 5.0 * power;
      *minor = 1.0 * power;
    }	  
  }
}
