/*
 *****************************************************
 *
 *  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
 *
 *****************************************************
 *
 * earth.c
 *
 * Routines for creating fancy earth model
 *
 * $Id: earth.c,v 1.22 2005/02/27 21:41:08 lloydwood Exp $
 */
#include <stdio.h>
#include <math.h>

#include "gv_utils.h"
#include "utils.h"
#include "constants.h"
#include "globals.h"
#include "coverage_vis.h"
#include "savi.h"

unsigned int earth_on_flag = FALSE;
unsigned int earth_geom_exists = FALSE;
unsigned int use_fancy_earth = FALSE;

unsigned int given_temp_scratchfile = FALSE;

static unsigned int earth_texture_loaded = FALSE;

static double m[4][4]; /* identity matrix used for rotating Earth */

static void earth_create_geom(void);
static void earth_delete_geom(void);

/*
 * earth_create_geom
 */
static void
earth_create_geom(void)
{
  if (earth_geom_exists)
    return;

  /*
   * initialise the identity matrix
   */
  identity(m);

  if (geomview_module) {
    /* create a simple blue sphere for the earth */
    gv_start();
    gv_create_geom("Central_Body", "central_t", "unit_sphere_h");
    gv_stop();
  }
  earth_geom_exists = TRUE;
}

/*
 * earth_delete_geom
 */
static void
earth_delete_geom(void)
{
  if (!earth_geom_exists)
    return;

  if (geomview_module) {
    gv_start();
    gv_delete_geom("Central_Body");
    gv_stop();
  }
  earth_geom_exists = FALSE;
}

/*
 * earth_on_cmd
 *
 * Displays the earth sphere, dull or detailed.
 */
char *
earth_on_cmd(int argc, char *argv[])
{
  if (earth_on_flag)
    return EMPTY_str;

  earth_on_flag = TRUE;

  if (use_fancy_earth) {
    if (geomview_module) {
      gv_start();
      if (texture_flag) {
	if (earth_texture_loaded) {
	  coverage_send_static_file();
	} else {
	  earth_texture_loaded = gv_sendfile("oogl/earth_h.oogl");
	}
        if (earth_texture_loaded) {
	  if (geomview_texture_with_map || !geomview_dynamic_texture_flag) {
	    /*
	     * scratchfile textures written after foreground map added;
	     * vector Earth redundant.
	     */
	    gv_create_geom("Central_Body", "central_t", "earth_h");
	  } else {
	    gv_create_geom("Central_Body", "central_t", "earth_vect_texture_sphere_h");
	  }
	  earth_geom_exists = TRUE;
	} else {
	  error("could not load earth texture file.");
	}
      } else {
	gv_create_geom("Central_Body", "central_t", "earth_vect_sphere_h");
	earth_geom_exists = TRUE;
      }
      gv_stop();
    }
  } else {
    /* just draw sphere */
    earth_create_geom();
  }

  return EMPTY_str;
}

/*
 * earth_off_cmd
 *
 * Destroy the earth sphere
 */
char *
earth_off_cmd(int argc, char *argv[])
{
  if (!earth_on_flag)
    return EMPTY_str;

  earth_on_flag = FALSE;

  if (use_fancy_earth) {
      /* we nest in gv_start/stop to hide temporary cosmetic changes -
       * this is the same idea used when loading tcl scripts
       * to prevent incremental per-new-satellite drawing updates.
       */
      if (geomview_module) gv_start();
      fancy_off_cmd(argc, argv);
      fancy_on_cmd(argc, argv);
      if (geomview_module) gv_stop();
  } else {
     /* just destroy sphere */
     earth_delete_geom();
  }

  return EMPTY_str;
}

/*
 * fancy_on_cmd
 *
 * Creates a fancy model of the earth by using vector
 * or loading texture-map file.
 */
char *
fancy_on_cmd(int argc, char *argv[])
{
  if (use_fancy_earth)
    return EMPTY_str;

  use_fancy_earth = TRUE;

  if (geomview_module) {
    gv_start();
    if (earth_on_flag) {
      if (texture_flag) {
	if (earth_texture_loaded) {
	  coverage_send_static_file();
	} else {
	  earth_texture_loaded = gv_sendfile("oogl/earth_h.oogl");
	}
        if (earth_texture_loaded) {
	  if (geomview_texture_with_map || !geomview_dynamic_texture_flag) {
	    /*
	     * scratchfile textures written after foreground map added;
	     * vector Earth redundant.
	     */
	    gv_create_geom("Central_Body", "central_t", "earth_h");
	  } else {
	    gv_create_geom("Central_Body", "central_t", "earth_vect_texture_sphere_h");
	  }
	  earth_geom_exists = TRUE;
	} else {
	  error("could not load earth texture file.");
	}
      } else {
	gv_create_geom("Central_Body", "central_t", "earth_vect_sphere_h");
	earth_geom_exists = TRUE;
      }
    } else {
      /*
       * draw only outline continents - ideal for spherical and
       * hyperbolic projections.
       */
      gv_create_geom("Central_Body", "central_t", "earth_vect_clear_h");
      earth_geom_exists = TRUE;
    }
    gv_stop();
  }

  return EMPTY_str;
}


/*
 * fancy_off_cmd
 *
 * Returns to a simple sphere to model the central body
 */
char *
fancy_off_cmd(int argc, char *argv[])
{
  char *status = EMPTY_str;

  if (!use_fancy_earth)
    return EMPTY_str;

  use_fancy_earth = FALSE;

  if (earth_on_flag) {
    if (geomview_module) gv_start();
    status = earth_off_cmd(argc, argv);
    status = earth_on_cmd(argc, argv);
    if (geomview_module) gv_stop();
  } else {
    earth_delete_geom();
  }

  return status;
}

/*
 * texture_on
 *
 * Use texture mapping for fancy earth model
 */
char *
texture_on_cmd(int argc, char *argv[])
{
  char *status = EMPTY_str;

  texture_flag = TRUE;

  if (earth_on_flag) {
    if (geomview_module) gv_start();
    status = earth_off_cmd(argc, argv);
    status = earth_on_cmd(argc, argv);
    if (geomview_module) gv_stop();
  }

  return status;
}

/*
 * texture_off_cmd
 *
 * Use vect model for fancy earth model
 */
char *
texture_off_cmd(int argc, char *argv[])
{
  char *status = EMPTY_str;

  texture_flag = FALSE;

  if (earth_on_flag) {
    if (geomview_module) gv_start();
    status = earth_off_cmd(argc, argv);
    status = earth_on_cmd(argc, argv);
    if (geomview_module) gv_stop();
  }

  return status;
}

/*
 * geomview_dynamic_texture_on
 */
char *
geomview_dynamic_texture_on_cmd(int argc, char *argv[])
{
  char *status = EMPTY_str;

  if (geomview_module) {
    if (!given_temp_scratchfile) {
      given_temp_scratchfile = coverage_tempfile_created();
    }
    if (given_temp_scratchfile) {
      geomview_dynamic_texture_flag = TRUE;
      if (texture_flag) {
	if (geomview_module) gv_start();
	status = texture_off_cmd(argc, argv);
	status = texture_on_cmd(argc, argv);
	if (geomview_module) gv_stop();
      }
    } else {
      error("unable to create coverage scratchfile. Disabling dynamic texturemapping.");
      geomview_dynamic_texture_flag = FALSE;
    }
  }

  return status;
}

/*
 * geomview_dynamic_texture_off
 */
char *
geomview_dynamic_texture_off_cmd(int argc, char *argv[])
{
  char *status = EMPTY_str;

  if (geomview_module && given_temp_scratchfile && geomview_dynamic_texture_flag) {
      if (texture_flag) {
	if (geomview_module) gv_start();
	status = texture_off_cmd(argc, argv);
	geomview_dynamic_texture_flag = FALSE;
	status = texture_on_cmd(argc, argv);
	if (geomview_module) gv_stop();
      }
  } else {
    geomview_dynamic_texture_flag = FALSE;
  }

  return status;
}

/*
 * earth_place
 *
 * rotates the earth to correct position for time t
 */
void
earth_place(double t, const CentralBody * pcb)
{
  double theta, ct, st;

  /*
   * Don't waste time rotating nothing.
   */
  if (!earth_geom_exists)
    return;

  /*
   * Don't waste time rotating a featureless blue sphere.
   */
  if (!use_fancy_earth)
    return;

  theta = t * pcb->rotation_rate;

  ct = cos(theta);
  st = sin(theta);

  /*
   * update elements of an existing identity matrix
   */
  m[0][0] = ct;
  m[0][1] = st;
  m[1][0] = -st;
  m[1][1] = ct;

  gv_transform("central_t", m);

}
