/*
 *****************************************************
 *
 *  SaVi by Robert Thurman (thurman@geom.umn.edu) and
 *          Patrick Worfolk (worfolk@alum.mit.edu).
 *
 *  Copyright (c) 1997 by The Geometry Center.
 *  This file is part of SaVi.  SaVi is free software;
 *  you can redistribute it and/or modify it only under
 *  the terms given in the file COPYRIGHT which you should
 *  have received along with this file.  SaVi may be
 *  obtained from:
 *  http://savi.sourceforge.net/
 *  http://www.geom.uiuc.edu/locate/SaVi
 *
 *****************************************************
 *
 * fisheye.c
 *
 * $Id: fisheye.c,v 1.8 2004/03/09 16:45:13 lloydwood Exp $
 */

#include <math.h>
#include <stdlib.h>

#include "constants.h"
#include "globals.h"
#include "sats.h"
#include "tcl_utils.h"
#include "tkPlot.h"

#include "fisheye.h"

static unsigned int fisheye_flag = FALSE;
static unsigned int fisheye_labels_flag = FALSE;
static unsigned int fisheye_vapors_flag = FALSE;
static unsigned int fisheye_reverse_view_flag = FALSE;
static unsigned int fisheye_print_inview_flag = FALSE;
static double lat, lon;
static TkPlot *plotPtr = NULL;
static char fisheye_widget[] = ".fisheye.cmd.p";

static void fisheye_draw(void);

/*
 * set colors globally so that we can save lookup values
 */
static int sat_color, low_sat_color;
static int special_sat_color = -1;
static int bgnd_color, ring_color;
static int angle_ring_color = -1;


/*
 * fisheye_on.c
 *
 * Set flags to indicate that fisheye should be displayed.
 * Call fisheye_display to get updated display.
 */
char *
fisheye_on_cmd(int argc, char *argv[])
{
  Constellation *pconstellation = get_constellation();
  Satellite_list SL = pconstellation->satellites;
  CentralBody *pcb = pconstellation->pcb;

  /* set variables so that fisheye will be displayed */
  fisheye_flag = TRUE;

  /* get plotPtr */
  plotPtr = (TkPlot *) get_ClientData(fisheye_widget);

  /* display the fisheye view */
  fisheye_display(SL, TRUE, pcb);

  return EMPTY_str;
}

char *
fisheye_off_cmd(int argc, char *argv[])
{
  fisheye_flag = FALSE;

  return EMPTY_str;
}

char *
fisheye_labels_on_cmd(int argc, char *argv[])
{
  fisheye_labels_flag = TRUE;
  return EMPTY_str;
}

char *
fisheye_labels_off_cmd(int argc, char *argv[])
{
  fisheye_labels_flag = FALSE;
  return EMPTY_str;
}


char *
fisheye_vapors_on_cmd(int argc, char *argv[])
{
  fisheye_vapors_flag = TRUE;
  return EMPTY_str;
}

char *
fisheye_vapors_off_cmd(int argc, char *argv[])
{
  fisheye_vapors_flag = FALSE;
  return EMPTY_str;

}

char *
fisheye_reverse_view_on_cmd(int argc, char *argv[])
{
  Constellation *pconstellation = get_constellation();
  Satellite_list SL = pconstellation->satellites;
  CentralBody *pcb = pconstellation->pcb;

  fisheye_reverse_view_flag = TRUE;

  /* get plotPtr */
  plotPtr = (TkPlot *) get_ClientData(fisheye_widget);

  /* display the fisheye view */
  fisheye_display(SL, TRUE, pcb);

  return EMPTY_str;
}

char *
fisheye_reverse_view_off_cmd(int argc, char *argv[])
{
  Constellation *pconstellation = get_constellation();
  Satellite_list SL = pconstellation->satellites;
  CentralBody *pcb = pconstellation->pcb;

  fisheye_reverse_view_flag = FALSE;

  /* get plotPtr */
  plotPtr = (TkPlot *) get_ClientData(fisheye_widget);

  /* display the fisheye view */
  fisheye_display(SL, TRUE, pcb);

  return EMPTY_str;
}

char *
fisheye_print_inview_on_cmd(int argc, char *argv[])
{
  fisheye_print_inview_flag = TRUE;

  /* really should just draw mask circle here if vapors already on */

  return EMPTY_str;
}

char *
fisheye_print_inview_off_cmd(int argc, char *argv[])
{
  fisheye_print_inview_flag = FALSE;
  return EMPTY_str;
}

/*
 * fisheye_set
 *
 * Sets the lat and lon for the fisheye display and redisplays it
 */
char *
fisheye_set_cmd(int argc, char *argv[])
{
  Constellation *pconstellation = get_constellation();
  Satellite_list sl = pconstellation->satellites;
  CentralBody *pcb = pconstellation->pcb;
  double new_lat = (double) atoi(argv[2]);
  double new_lon = (double) atoi(argv[4]);	/* was 3 gjl */
  const char format1[] = "set fisheye_lat_lon \"%d %.4f %c  %d %.4f %c\"";
  char cmd[sizeof(format1) + 20];
  int lat_deg, lon_deg;
  char latNS, lonEW;
  double lat_min, lon_min;

  new_lat = (new_lat >= 0) ? new_lat + atof(argv[3]) / 60.0 :
    new_lat - atof(argv[3]) / 60.0;
  new_lon = (new_lon >= 0) ? new_lon + atof(argv[5]) / 60.0 :
    new_lon - atof(argv[5]) / 60.0;

  lat = new_lat;
  lon = new_lon;

  /* display lat lon */
  if (lat >= 0) {
    latNS = 'N';
    lat_deg = (int) floor(lat);
    lat_min = (lat - lat_deg) * 60.0;
  } else {
    latNS = 'S';
    lat_deg = (int) floor(-lat);
    lat_min = (-lat - lat_deg) * 60.0;
  }
  if (lon >= 0) {
    lonEW = 'E';
    lon_deg = (int) floor(lon);
    lon_min = (lon - lon_deg) * 60.0;
  } else {
    lonEW = 'W';
    lon_deg = (int) floor(-lon);
    lon_min = (-lon - lon_deg) * 60.0;
  }
  sprintf(cmd, format1, lat_deg, lat_min, latNS, lon_deg, lon_min, lonEW);

  tcl_script(cmd);

  /* display sky view */
  fisheye_display(sl, TRUE, pcb);
  return EMPTY_str;
}


/*
 * fisheye_draw
 *
 * clears and redraws the display
 *
 */
static void
fisheye_draw()
{

  unsigned int r;
  int offset, fisheye_old_diameter;
  char cmd[] = "fisheye(resize)";
  float coverage_pct = (90.0 - coverage_angle) / 90.0;

  if (!plotPtr)
    return;

  /*
   * Resize and clear plot window only if necessary.
   */
  fisheye_old_diameter = Fisheye_Diameter;
  tcl_script(cmd);
  Tk_PlotClear(plotPtr);
  if (fisheye_old_diameter != Fisheye_Diameter) {
    plotPtr->width = Fisheye_Diameter;
    plotPtr->height = Fisheye_Diameter;
    build_pixmap(plotPtr);
  }

  /* this is an attempt to avoid calling these more than once */
  if (angle_ring_color < 0) {
    bgnd_color = Tk_PlotColorLookup("white");
    ring_color = Tk_PlotColorLookup("grey");
    angle_ring_color = Tk_PlotColorLookup("blue");
  }

  r = Fisheye_Diameter / 2 - 1;
  offset = r + 2;

  /* draw bullseye */
  Tk_PlotSymbol(plotPtr, offset, offset, bgnd_color, DISK, r);
  Tk_PlotSymbol(plotPtr, offset, offset, ring_color, CIRCLE, r);
  Tk_PlotSymbol(plotPtr, offset, offset, ring_color, CIRCLE, r * 2 / 3);
  Tk_PlotSymbol(plotPtr, offset, offset, ring_color, CIRCLE, r / 3);
  Tk_PlotSymbol(plotPtr, offset, offset, ring_color, POINT, 0);

  if (r > 100) {
    Tk_PlotSymbol(plotPtr, offset, offset, ring_color, CIRCLE, r / 2);
    Tk_PlotSymbol(plotPtr, offset, offset, ring_color, CIRCLE, r / 6);
    Tk_PlotSymbol(plotPtr, offset, offset, ring_color, CIRCLE, r * 5 / 6);
  }

  /* should only draw threshold if using mask elevation */
  if (fisheye_print_inview_flag) {
    Tk_PlotSymbol(plotPtr, offset, offset, angle_ring_color, CIRCLE,
		  (unsigned int) (coverage_pct * r));
  }
}



/*
 * fisheye_display
 *
 * update the Tk image
 */
void
fisheye_display(const Satellite_list SL, unsigned int force,
		const CentralBody * pcb)
{
  unsigned int r;
  int offset;
  float coverage_pct = (90.0 - coverage_angle) / 90.0;


  if (!fisheye_flag && !force)
    return;

  /*
   * get plotPtr - this is repeatedly called during the sats update
   * cycle - and we need to ensure that plotPtr is correct!
   */
  plotPtr = (TkPlot *) get_ClientData(fisheye_widget);
  if (!plotPtr)
    return;

  if (force || !fisheye_vapors_flag)
    fisheye_draw();

  r = Fisheye_Diameter / 2 - 1;
  offset = r + 2;

  if (special_sat_color < 0) {
    sat_color = Tk_PlotColorLookup("red");
    low_sat_color = Tk_PlotColorLookup("green");
    special_sat_color = Tk_PlotColorLookup("magenta");
  }

  /* plot satellite positions */
  {
    CartesianCoordinates s;
    double sky[2];
    double t = current_time();
    double interval_time;
    Satellite_list sl = SL;
    char plotStr[16];
    int color;

    while (sl) {
      oe_time_to_geocentric(&s, t, &(sl->s->oe), pcb);
      if (sat_to_fisheye(&s, lat, lon, pcb, t, sky)) {
	if ((sky[0] * sky[0] + sky[1] * sky[1]) <
	    (coverage_pct * coverage_pct)) {
	  if (sl->s->gs_into_view == 0) {
	    sl->s->gs_into_view = t;
	    sl->s->gs_last_into_view = t;
	  }
	} else {
	  /*
	   * could add delta_t for half of interval before and after
	   * passing view test - but assumes delta_t unchanged!
	   */
	  if (sl->s->gs_into_view != 0) {
	    sl->s->gs_last_pass = t - sl->s->gs_into_view;
	  }
	  sl->s->gs_into_view = 0;
	}

	if (fisheye_reverse_view_flag) {
	  sky[0] = -sky[0];
	}
	if (fisheye_print_inview_flag) {
	  color = low_sat_color;
	} else {
	  color = sat_color;
	}

	/* should only do this if mask elev selected in coverage */
	if (fisheye_print_inview_flag && (sl->s->gs_into_view > 0)) {
	  color = sat_color;
	  interval_time = t - sl->s->gs_into_view;
	  sprintf(plotStr, "%d %.1f", sl->s->id, interval_time);
	} else {
	  sprintf(plotStr, "%d", sl->s->id);
	}
	if (fisheye_labels_flag) {
	  Tk_PlotString(plotPtr, (int) (offset + r * sky[0]), (int)
			(offset - r * sky[1]), color, plotStr, 16);
	}
	if (sl->s->tag == 1) {
	  color = special_sat_color;
	}
	Tk_PlotSymbol(plotPtr, (int) (offset + r * sky[0]), (int)
		      (offset - r * sky[1]), color, CROSSHAIR, 5);
      } else if (sl->s->gs_last_pass != 0) {
	/*
	 * any recorded output needs formatting into a proper tracefile,
	 * including lat/long, estimated margin of error (delta_t/2).
	 * currently disabled.
	 */
	if (0) {
	  fprintf(stderr,
		  "Sat: %2d, first seen: %6.1f secs, for: %.1f secs.\n",
		  sl->s->id, sl->s->gs_last_into_view, sl->s->gs_last_pass);
	}
	sl->s->gs_into_view = 0;
      }

      sl = sl->next;
    }
  }

  /* force display */
  Tk_PlotQueueRefresh(plotPtr);
}
