
/* This file contains those functions that deal with the weather and
relevant variables in the environment */


#include <stdio.h>
#include <math.h>
/*gn*/
#include <suntool/sunview.h>
/*gn*/
#include <suntool/panel.h>
/*gn*/
#include <suntool/canvas.h>
#include "structures.h"
#include "util_fns.h"
#include "env_spec.h"
#include "env_defs.h"
#include "ext_env_decs.h"


/*g*//* function to initialise a display to show what the weather in the
/*g*//*environment is like and also to show the average temperature */
/*g*/void set_up_weather_display()
/*g*/{
/*g*/
/*g*/  weather_frame = window_create(NULL, FRAME,
/*g*/    WIN_SHOW, FALSE,
/*g*/    FRAME_LABEL, "Weather Display",
/*g*/    WIN_X, 6,
/*g*/    WIN_Y, (19 + PANEL_HEIGHT + 13),
/*g*/    WIN_WIDTH, 500,
/*g*/    WIN_HEIGHT, 150,
/*g*/    0);
/*g*/
/*g*/  weather_canvas = window_create(weather_frame, CANVAS,
/*g*/    WIN_SHOW, TRUE,
/*g*/    CANVAS_AUTO_SHRINK, TRUE, 
/*g*/    CANVAS_AUTO_EXPAND, TRUE,
/*g*/    WIN_X, 0,
/*g*/    WIN_Y, 0,
/*g*/    WIN_WIDTH, 30,
/*g*/    WIN_HEIGHT, 30,
/*g*/    0);
/*g*/
/*g*/  weather_pw = canvas_pixwin(weather_canvas);
/*g*/
/*g*/  /* attach colourmap to pixwin */
/*g*/  pw_setcmsname(weather_pw, "doesntmatter");
/*g*/  pw_putcolormap(weather_pw, 0, CMAP_SIZE, red, green, blue);
/*g*/
/*g*/  /* draw weather image into canvas */
/*g*/  switch (env_weather) {
/*g*/    case(0): pw_rop(weather_pw, 0, 6, 30, 20, PIX_SRC, rain_pr, 0, 0);
/*g*/	     break;
/*g*/    case(1): pw_rop(weather_pw, 0, 7, 30, 20, PIX_SRC, cloud_pr, 0, 0);
/*g*/	     break;
/*g*/    case(2): pw_rop(weather_pw, 0, 4, 30, 20, PIX_SRC, ssun_pr, 0, 0);
/*g*/     	     break;
/*g*/  }
/*g*/
/*g*/  weather_panel = window_create(weather_frame, PANEL,
/*g*/    WIN_X, 42,
/*g*/    WIN_Y, 0,
/*g*/    WIN_SHOW, TRUE,
/*g*/    0);
/*g*/
/*g*/  /* slider for current temperature */
/*g*/  temp_slider = panel_create_item(weather_panel, PANEL_SLIDER,
/*g*/    PANEL_LABEL_STRING, "Current Temperature          ",
/*g*/    PANEL_VALUE, ((int) ((1.0 + env_temp) * 50.0)),
/*g*/    PANEL_MIN_VALUE, 0,
/*g*/    PANEL_MAX_VALUE, 100,
/*g*/    PANEL_SHOW_RANGE, FALSE,
/*g*/    PANEL_SLIDER_WIDTH, 250,
/*g*/    PANEL_NOTIFY_PROC, do_nothing_proc,
/*g*/    0);
/*g*/
/*g*/  /* slider for average of recent temperature */
/*g*/  temp_history_slider = panel_create_item(weather_panel, PANEL_SLIDER,
/*g*/    PANEL_LABEL_STRING, "Average of Recent Temperature",
/*g*/    PANEL_VALUE, ((int) ((1.0 + temp_history) * 50.0)),
/*g*/    PANEL_MIN_VALUE, 0,
/*g*/    PANEL_MAX_VALUE, 100,
/*g*/    PANEL_SHOW_RANGE, FALSE,
/*g*/    PANEL_SLIDER_WIDTH, 250,
/*g*/    PANEL_NOTIFY_PROC, do_nothing_proc,
/*g*/    0);
/*g*/
/*g*/  /* slider for current rainfall */
/*g*/  rainfall_slider = panel_create_item(weather_panel, PANEL_SLIDER,
/*g*/    PANEL_LABEL_STRING, "Current Rainfall             ",
/*g*/    PANEL_VALUE, ((int) (env_rainfall * 100.0)),
/*g*/    PANEL_MIN_VALUE, 0,
/*g*/    PANEL_MAX_VALUE, 100,
/*g*/    PANEL_SHOW_RANGE, FALSE,
/*g*/    PANEL_SLIDER_WIDTH, 250,
/*g*/    PANEL_NOTIFY_PROC, do_nothing_proc,
/*g*/    0);
/*g*/
/*g*/  /* slider for average of recent rainfall */
/*g*/  rainfall_history_slider = panel_create_item(weather_panel, PANEL_SLIDER,
/*g*/    PANEL_LABEL_STRING, "Average of Recent Rainfall   ",
/*g*/    PANEL_VALUE, ((int) (rainfall_history * 100.0)),
/*g*/    PANEL_MIN_VALUE, 0,
/*g*/    PANEL_MAX_VALUE, 100,
/*g*/    PANEL_SHOW_RANGE, FALSE,
/*g*/    PANEL_SLIDER_WIDTH, 250,
/*g*/    PANEL_NOTIFY_PROC, do_nothing_proc,
/*g*/    0);
/*g*/
/*g*/  /* set boolean to show that weather is not currently displayed */
/*g*/  weather_display_on = FALSE;
/*g*/
/*g*/  window_fit(weather_panel);
/*g*/  window_fit(weather_frame);
/*g*/}
/*g*/
/*g*/
/*g*//* procedure to turn on the weather display */
/*g*/void weather_change_proc()
/*g*/{
/*g*/
/*g*/  if (window_get(weather_frame, WIN_SHOW) == FALSE) {
/*g*/	turn_on(weather_frame);
/*g*/	weather_display_on = TRUE;
/*g*/  }
/*g*/  else {
/*g*/	turn_off(weather_frame);
/*g*/	weather_display_on = FALSE;
/*g*/  }
/*g*/}


/* function to initialise the state of the weather */
void init_weather()
{

	env_weather = (int) rnd(3.0);
}


/* function to provide an initial rainfall and history of rainfall */
void init_rainfall()
{

  int i;
  int num_updates_missed;

	rainfall_history = 0.0;
	for (i = 0; i < R_H_LENGTH; ++i) {

	  recent_rainfall[i] = (drand48() < 0.3333) ? double_rnd(1.0) : 0.0;
	  rainfall_history += recent_rainfall[i];
	}
	rainfall_history /= (double) R_H_LENGTH;

	env_rainfall = (env_weather == 0) ? double_rnd(1.0) : 0.0;

	total_day_rainfall = 0.0;

	if (INIT_TIMESTEP_VALUE != 0) {

	  num_updates_missed = ((timestep-1) / 10) + 1;

	  for (i = 0; i < num_updates_missed; i++)

		/* get random values for the rainfall updates missed */
		total_day_rainfall += ((drand48() < 0.3333) ? double_rnd(1.0) : 0.0);
	}
}  


/* function to provide an initial temperature and history of temperature */
void init_temp()
{

  int num_updates_missed;
  int i;

	temp_history = 0.0;
	for (i = 0; i < T_H_LENGTH; ++i) {

	  recent_temp[i] = -1.0 + double_rnd(2.0);
	  temp_history += recent_temp[i];
	}
	temp_history /= ((double)T_H_LENGTH);

	env_temp = 0.0;

	total_day_temp = 0.0;

	if (INIT_TIMESTEP_VALUE != 0) {

	  num_updates_missed = ((timestep-1) / 10) + 1;

	  for (i = 0; i < num_updates_missed; i++)

		/* get random values for the temperature updates missed */
		total_day_temp += (1.0 - double_rnd(2.0));
	}
}  


/* initialiase the value of the environment dryness */
void init_dryness()
{

	/* calculate the 'dryness' of the environment, due to lack of rainfall
	and, to a lesser extent, heat */
	env_dryness = ((9.5 * (1.0-rainfall_history)) +
                 (0.5 * ((temp_history+1.0)/2.0))) / 10.0;
}


/* function to change the weather state after every 10 timesteps */
void update_weather()
{

  int new_weather;
  double random;

	random = drand48();

	/* probabilities of following weather states should be dependant on
	current weather state */
	switch(env_weather) {
      case(0): if (random > (RAIN_TO_CLOUD_PROB+RAIN_TO_SUN_PROB))
                                             /* current weather = rain */
				 new_weather = 0;
               else if (random > RAIN_TO_SUN_PROB)
                 new_weather = 1;
               else
                 new_weather = 2;
               break;             
      case(1): if (random > (CLOUD_TO_RAIN_PROB+CLOUD_TO_SUN_PROB))
                                             /* current weather = cloud */
                 new_weather = 1;
               else if (random > CLOUD_TO_SUN_PROB)
                 new_weather = 0;
               else
                 new_weather = 2;
               break;
      case(2): if (random > (SUN_TO_CLOUD_PROB+SUN_TO_RAIN_PROB))
                                            /* current weather = sun */
                 new_weather = 2;
               else if (random > SUN_TO_RAIN_PROB)
                 new_weather = 1;
               else
                 new_weather = 0;
               break;
	}

	env_weather = new_weather;
}


/* function to update the rainfall state after every 10 time steps */
void update_rainfall()
{

	/* add this rainfall to the day total */
	total_day_rainfall += env_rainfall;

	/* get a new rainfall value */
	env_rainfall = (env_weather == 0) ? double_rnd(1.0) : 0.0;
}

/* function to update the temperature state after every 10 time steps */
void update_temp()
{

  double new_temp;

	/* add this temperature to the total for the day */
	total_day_temp += env_temp;

	/* update values of maximum and minimum temperatures for this type of
	weather */
	switch(env_weather) {
      case(0): min_temp = MIN_RAIN_TEMP;
               max_temp = MAX_RAIN_TEMP;
               break;
      case(1): min_temp = MIN_CLOUD_TEMP;
               max_temp = MAX_CLOUD_TEMP;
               break;
      case(2): min_temp = MIN_SUN_TEMP;
               max_temp = MAX_SUN_TEMP;
               break;
	}

	/* get a random new temperature value between the upper and lower limits*/ 
	new_temp = min_temp + (drand48() * (max_temp-min_temp));

	/* add factor to take account of whether it is night, sunset, midday, etc*/
	switch(part_of_day) {
      case(NIGHT) : new_temp += NIGHT_TEMP_INCR;
				    break;
      case(SUNRISE) : new_temp += DUSK_TEMP_INCR;
				      break;
      case(SUNSET) : new_temp += DUSK_TEMP_INCR;
				     break;
	  default : new_temp += DAY_TEMP_INCR;
		        break;
	}

	/* make sure new temperature is still within limits -1.0 to 1.0 */
	if (new_temp <= -1.0)
	  new_temp = -0.99999;
	if (new_temp >= 1.0)
	  new_temp = 0.99999;

	/* don't just set env_temp to new temperature (which is random within
	limits for the type of weather), but have some buffering as well to make
	env_temp move quite slowly towards the new random temperature */
	if (new_temp < env_temp)
      env_temp -= (env_temp-new_temp) * (0.1 + rnd(0.2));
	else
	  env_temp += (new_temp-env_temp) * (0.1 + rnd(0.2));
}

/*g*/
/*g*//* function to update the display showing the weather and temperature */
/*g*/void update_weather_display()
/*g*/{
/*g*/
/*g*/  /* don't waste time changing display if it is not on */
/*g*/  if (weather_display_on) {
/*g*/
/*g*/    /* draw over previous weather image */
/*g*/    pw_rop(weather_pw, 0, 0, 30, 30, PIX_CLR, NULL, 0, 0);
/*g*/
/*g*/    /* draw weather image into canvas */
/*g*/    switch (env_weather) {
/*g*/      case(0): pw_rop(weather_pw, 0, 6, 30, 20, PIX_SRC, rain_pr, 0, 0);
/*g*/  	         break;
/*g*/      case(1): pw_rop(weather_pw, 0, 7, 30, 20, PIX_SRC, cloud_pr, 0, 0);
/*g*/     	     break;
/*g*/      case(2): pw_rop(weather_pw, 0, 4, 30, 20, PIX_SRC, ssun_pr, 0, 0);
/*g*/             break;
/*g*/    }
/*g*/    
/*g*/    /* amend slider values */
/*g*/    panel_set(temp_slider, PANEL_VALUE, ((int) (50.0*(env_temp+1.0))), 0);
/*g*/    panel_set(temp_history_slider, PANEL_VALUE,
/*g*/      ((int) (50.0*(temp_history+1.0))), 0); 
/*g*/    panel_set(rainfall_slider, PANEL_VALUE, ((int) (100.0*env_rainfall)), 0);
/*g*/    panel_set(rainfall_history_slider, PANEL_VALUE,
/*g*/      ((int) (100.0*rainfall_history)), 0); 
/*g*/
/*g*/    window_fit(weather_panel);
/*g*/    window_fit(weather_frame);
/*g*/  }
/*g*/}
  

void update_day_rainfall()
{

  int i;

	/* add current rainfall to array and shunt others along */
	for (i = (R_H_LENGTH-2); i >= 0; --i)
      recent_rainfall[i+1] = recent_rainfall[i];
	recent_rainfall[0] = total_day_rainfall/((double) (DAY_LENGTH/10));

	/* update value of rainfall_history */
	rainfall_history = 0.0;
	for (i = 0; i < R_H_LENGTH; ++i)
      rainfall_history += recent_rainfall[i];
	rainfall_history /= ((double) R_H_LENGTH);

	if (rainfall_history < 0.06)
	  rainfall_history = 0.06;

	total_day_rainfall = 0.0;
}


void update_day_temp()
{

  int i;

	/* add current temp to array and shunt others along */
	for (i = (T_H_LENGTH-2); i >= 0; --i)
	  recent_temp[i+1] = recent_temp[i];
	recent_temp[0] = total_day_temp/((double) (DAY_LENGTH/10));

	/* update value of temp_history */
	temp_history = 0.0;
	for (i = 0; i < T_H_LENGTH; ++i)
	  temp_history += recent_temp[i];
	temp_history /= ((double) T_H_LENGTH);

	total_day_temp = 0.0;
}


void update_day_dryness()
{

	/* recalculate the 'dryness' of the environment due to lack of temp
	and, to a lesser extent, heat */
	env_dryness = ((9.5 * (1.0-rainfall_history)) +
                 (0.5 * ((temp_history+1.0)/2.0))) / 10.0;
}


