#define AS_CELLHD 1
#define AS_WINDOW 0
#define AS_DEF_WINDOW -1

/* modified 26nov to use word region instead of window
 * as far as the USER is concerned.
 */
/*
 **********************************************************************
 *
 *   E_edit_cellhd (cellhd, type)
 *      struct Cell_head *cellhd   (cellhd to be defined)
 *      int type 
 *        0 = region - user input resolutions
 *       -1 = default region - user input resolutions
 *        1 = cellhd - rows and cols must be set
 *
 *   Screen oriented user interactive session for modifying a cell header
 *   or region.
 *   Uses the visual_ask V_ask routines.  As such, programs including
 *   this must load the GRASS library $(VASKLIB) and include $(CURSES) in
 *   in the compile line
 *
 *   returns:
 *      -1 error of some sort, or user cancels the edit
 *       0 ok
 *
 **********************************************************************/
#include <string.h>
#include <stdlib.h>
#include <grass/vask.h>
#include <grass/gis.h>
#include <grass/edit.h>


static void format_value(int (*func)(double, char *, int), 
                         double x, char *buf, int projection);
static void format_northing(double north, char *buf, int projection);
static void format_easting(double east, char *buf, int projection);
static void format_resolution(double res, char *buf, int projection);
static int hitreturn(void);


static char *cellhd_screen[] = {
"                           IDENTIFY CELL HEADER",
"",
"           ============================= DEFAULT REGION ========",
"           |          Default North:                           |",
"           |                                                   |",
"           |           =======  CELL HEADER  =======           |",
"           |           | NORTH EDGE:               |           |",
"           |           |                           |           |",
" Def. West |WEST EDGE  |                           |EAST EDGE  | Def. East",
"           |           |                           |           |",
"           |           | SOUTH EDGE:               |           |",
"           |           =============================           |",
"           |                                                   |",
"           |          Default South:                           |",
"           =====================================================",
"           PROJECTION:                                ZONE:",
NULL};

static char *window_screen[] = {
"                              IDENTIFY REGION",
"",
"           ============================= DEFAULT REGION ========",
"           |          Default North:                           |",
"           |                                                   |",
"           |           =======  YOUR REGION  =======           |",
"           |           | NORTH EDGE:               |           |",
"           |           |                           |           |",
" Def. West |WEST EDGE  |                           |EAST EDGE  | Def. East",
"           |           |                           |           |",
"           |           | SOUTH EDGE:               |           |",
"           |           =============================           |",
"           |                                                   |",
"           |          Default South:                           |",
"           =====================================================",
"           PROJECTION:                                ZONE:",
"",
"                   Default   GRID RESOLUTION   Region",
"                            --- East-West ---",
"                            -- North-South --",
NULL};

static char *def_window_screen[] = {
"                         DEFINE THE DEFAULT REGION",
"",
"",
"",
"",
"                       ====== DEFAULT REGION =======",
"                       | NORTH EDGE:               |",
"                       |                           |",
"            WEST EDGE  |                           |EAST EDGE",
"                       |                           |",
"                       | SOUTH EDGE:               |",
"                       =============================",
"",
"",
"",
"           PROJECTION:                                ZONE:",
"",
"                             GRID RESOLUTION",
"                                 East-West:",
"                               North-South:",
NULL};


static void format_value(int (*func)(double, char *, int), 
                         double x, char *buf, int projection)
{
    if (projection != PROJECTION_XY)
    {
	int k = (projection == PROJECTION_LL) ? 3600 : 1;
	int i = (int) (x * k + (x < 0 ? -0.5 : 0.5));
	x = (double) i / k;
    }

    func (x, buf, projection);
    buf[10] = '\0';
}


static void format_northing(double north, char *buf, int projection)
{
	format_value(G_format_northing, north, buf, projection);
}


static void format_easting(double east, char *buf, int projection)
{
	format_value(G_format_easting, east, buf, projection);
}


static void format_resolution(double res, char *buf, int projection)
{
	format_value(G_format_resolution, res, buf, projection);
}


int E_edit_cellhd (struct Cell_head *cellhd , int type)
{
    char ll_north[20];
    char ll_south[20];
    char ll_east[20];
    char ll_west[20];
    char ll_nsres[20];
    char ll_ewres[20];
    char ll_def_north[20];
    char ll_def_south[20];
    char ll_def_east[20];
    char ll_def_west[20];
    char ll_def_ewres[20];
    char ll_def_nsres[20];
    char projection[80];
    char **screen;

    struct Cell_head def_wind ;
    double north, south, east, west ;
    double nsres, ewres;
    char buf[64], buf2[30], *p;
    short ok ;
    int line;
    char *prj;
    char *err;

    if (type == AS_CELLHD && (cellhd->rows <= 0 || cellhd->cols <= 0))
    {
	G_message("E_edit_cellhd() - programmer error");
	G_message("  ** rows and cols must be positive **");
	return -1;
    }
    if (type != AS_DEF_WINDOW)
    {
	if (G_get_default_window(&def_wind) != 1)
	    return -1 ;

	if(cellhd->proj < 0)
	{
	    cellhd->proj        = def_wind.proj ;
	    cellhd->zone        = def_wind.zone ;
	}
	else if(cellhd->zone < 0)
	    cellhd->zone        = def_wind.zone ;
    }

    prj = G__projection_name (cellhd->proj);
    if (!prj) prj = "** unknown **";
    sprintf (projection, "%d (%s)", cellhd->proj, prj) ;

    if (type !=AS_DEF_WINDOW)
    {
	if (cellhd->west >= cellhd->east || cellhd->south >= cellhd->north) 
	{
	    cellhd->north       = def_wind.north     ; 
	    cellhd->south       = def_wind.south     ;
	    cellhd->west        = def_wind.west      ; 
	    cellhd->east        = def_wind.east      ;

	    if (type != AS_CELLHD)
	    {
	    cellhd->ew_res      = def_wind.ew_res    ;
	    cellhd->ns_res      = def_wind.ns_res    ;
	    cellhd->rows        = def_wind.rows      ;
	    cellhd->cols        = def_wind.cols      ;
	    }
	}

	if (cellhd->proj != def_wind.proj)
	{
            if (type == AS_CELLHD)
	        G_message("header projection %d differs from default projection %d",
		            cellhd->proj, def_wind.proj);
            else
	        G_message("region projection %d differs from default projection %d",
		            cellhd->proj, def_wind.proj);

	    if (!G_yes("do you want to make them match? ", 1))
		return -1;

	    cellhd->proj = def_wind.proj;
	    cellhd->zone = def_wind.zone;
	}

	if (cellhd->zone != def_wind.zone)
	{
            if (type == AS_CELLHD)
	        G_message("header zone %d differs from default zone %d",
		            cellhd->zone, def_wind.zone);
            else
	        G_message("region zone %d differs from default zone %d",
		            cellhd->zone, def_wind.zone);

	    if (!G_yes("do you want to make them match? ", 1))
		    return -1;

	    cellhd->zone = def_wind.zone;
	}

	*ll_def_north = 0;
	*ll_def_south = 0;
	*ll_def_east = 0;
	*ll_def_west = 0;
	*ll_def_ewres = 0;
	*ll_def_nsres = 0;
	format_northing (def_wind.north, ll_def_north, def_wind.proj);
	format_northing (def_wind.south, ll_def_south, def_wind.proj);
	format_easting  (def_wind.east,  ll_def_east,  def_wind.proj);
	format_easting  (def_wind.west,  ll_def_west, def_wind.proj);
	format_resolution (def_wind.ew_res, ll_def_ewres, def_wind.proj);
	format_resolution (def_wind.ns_res, ll_def_nsres, def_wind.proj);
    }

    *ll_north = 0;
    *ll_south = 0;
    *ll_east = 0;
    *ll_west = 0;
    *ll_ewres = 0;
    *ll_nsres = 0;
    format_northing (cellhd->north, ll_north, cellhd->proj);
    format_northing (cellhd->south, ll_south, cellhd->proj);
    format_easting  (cellhd->east, ll_east, cellhd->proj);
    format_easting  (cellhd->west, ll_west, cellhd->proj);
    format_resolution (cellhd->ew_res, ll_ewres, cellhd->proj);
    format_resolution (cellhd->ns_res, ll_nsres, cellhd->proj);

while(1)
{
    ok = 1;

    /* List window options on the screen for the user to answer */
    switch(type)
    {
    case AS_CELLHD: screen = cellhd_screen; break;
    case AS_DEF_WINDOW: screen = def_window_screen; break;
    default: screen = window_screen; break;
    }

    V_clear() ;
    line = 0;
    while (*screen)
	V_line (line++, *screen++);

    /* V_ques ( variable, type, row, col, length) ; */
    V_ques (ll_north, 's',  6, 36, 10);
    V_ques (ll_south, 's', 10, 36, 10) ;
    V_ques (ll_west,  's',  9, 12, 10) ;
    V_ques (ll_east,  's',  9, 52, 10) ;

    if (type != AS_CELLHD)
    {
	V_ques (ll_ewres, 's', 18, 48, 10) ;
	V_ques (ll_nsres, 's', 19, 48, 10) ;
    }

    if (type != AS_DEF_WINDOW)
    {
	V_const (ll_def_north, 's',  3, 36, 10) ;
	V_const (ll_def_south, 's', 13, 36, 10) ;
	V_const (ll_def_west,  's',  9,  1, 10) ;
	V_const (ll_def_east,  's',  9, 65, 10) ;

	if (type != AS_CELLHD)
	{
	    V_const (ll_def_ewres, 's', 18, 21, 10) ;
	    V_const (ll_def_nsres, 's', 19, 21, 10) ;
	}
    }

    V_const (projection,   's', 15, 23, (int)strlen(projection));
    V_const (&cellhd->zone,'i', 15,60,3);

    V_intrpt_ok();
    if(!V_call())
	return -1;

    G_squeeze (ll_north);
    G_squeeze (ll_south);
    G_squeeze (ll_east);
    G_squeeze (ll_west);

    if (type != AS_CELLHD)
    {
	G_squeeze (ll_ewres);
	G_squeeze (ll_nsres);
    }

    if (!G_scan_northing (ll_north, &cellhd->north, cellhd->proj))
    {
        G_warning("Illegal value for north: %s", ll_north);
	ok = 0;
    }

    if (!G_scan_northing (ll_south, &cellhd->south, cellhd->proj))
    {
        G_warning("Illegal value for south: %s", ll_south);
	ok = 0;
    }

    if (!G_scan_easting (ll_east, &cellhd->east, cellhd->proj))
    {
        G_warning("Illegal value for east: %s", ll_east);
	ok = 0;
    }

    if (!G_scan_easting (ll_west, &cellhd->west, cellhd->proj))
    {
        G_warning("Illegal value for west: %s", ll_west);
	ok = 0;
    }

    if (type != AS_CELLHD)
    {
	if (!G_scan_resolution (ll_ewres, &cellhd->ew_res, cellhd->proj))
	{
	    G_warning("Illegal east-west resolution: %s", ll_ewres);
	    ok = 0;
	}

	if (!G_scan_resolution (ll_nsres, &cellhd->ns_res, cellhd->proj))
	{
	    G_warning("Illegal north-south resolution: %s", ll_nsres);
	    ok = 0;
	}
    }

    if (!ok)
    {
	hitreturn();
	continue;
    }

    /* Adjust and complete the cell header */
    north = cellhd->north;
    south = cellhd->south;
    east  = cellhd->east ;
    west  = cellhd->west ;
    nsres = cellhd->ns_res;
    ewres = cellhd->ew_res;

    if ((err = G_adjust_Cell_head(cellhd,type==AS_CELLHD,type==AS_CELLHD)))
    {
	G_message("%s", err);
	hitreturn();
	continue;
    }

    if (type==AS_CELLHD)
    {
	nsres = cellhd->ns_res;
	ewres = cellhd->ew_res;
    }

SHOW:
    fprintf (stderr, "\n\n") ;
    G_message("  projection:   %s", projection);
    G_message("  zone:         %d", cellhd->zone);

    G_format_northing (cellhd->north, buf,  cellhd->proj);
    G_format_northing (north,         buf2, cellhd->proj);
    fprintf (stderr, "  north:       %s", buf);

    if (strcmp (buf, buf2) != 0)
    {
	ok = 0;
        fprintf (stderr, "  (Changed to match resolution)");
    }
    fprintf (stderr, "\n");

    G_format_northing (cellhd->south, buf,  cellhd->proj);
    G_format_northing (south,         buf2, cellhd->proj);
    fprintf (stderr, "  south:       %s", buf);
    if (strcmp (buf, buf2) != 0)
    {
	ok = 0;
        fprintf (stderr, "  (Changed to match resolution)");
    }
    fprintf (stderr, "\n");

    G_format_easting (cellhd->east, buf,  cellhd->proj);
    G_format_easting (east,         buf2, cellhd->proj);
    fprintf (stderr, "  east:        %s", buf);
    if (strcmp (buf, buf2) != 0)
    {
	ok = 0;
        fprintf (stderr, "  (Changed to match resolution)");
    }
    fprintf (stderr, "\n");

    G_format_easting (cellhd->west, buf,  cellhd->proj);
    G_format_easting (west,         buf2, cellhd->proj);
    fprintf (stderr, "  west:        %s", buf);
    if (strcmp (buf, buf2) != 0)
    {
	ok = 0;
        fprintf (stderr, "  (Changed to match resolution)");
    }
    fprintf (stderr, "\n\n");

    G_format_resolution (cellhd->ew_res, buf,  cellhd->proj);
    G_format_resolution (ewres,          buf2, cellhd->proj);
    fprintf (stderr, "  e-w res:     %s", buf);
    if (strcmp (buf, buf2) != 0)
    {
	ok = 0;
        fprintf (stderr, "  (Changed to conform to grid)");
    }
    fprintf (stderr, "\n");

    G_format_resolution (cellhd->ns_res, buf,  cellhd->proj);
    G_format_resolution (nsres,          buf2, cellhd->proj);
    fprintf (stderr, "  n-s res:     %s", buf);
    if (strcmp (buf, buf2) != 0)
    {
	ok = 0;
        fprintf (stderr, "  (Changed to conform to grid)");
    }
    fprintf (stderr, "\n\n");

    G_message("  total rows:  %15d",    cellhd->rows);
    G_message("  total cols:  %15d",    cellhd->cols);

    sprintf(buf,"%lf",    (double) cellhd->rows * cellhd->cols);
    *(p = strchr(buf, '.')) = 0;
    G_insert_commas(buf);
    G_message("  total cells: %15s",    buf);
    fprintf (stderr, "\n");

    if (type != AS_DEF_WINDOW)
    {
	if (cellhd->north > def_wind.north)
	{
	    G_warning("north falls outside the default region");
	    ok = 0;
	}

	if (cellhd->south < def_wind.south)
	{
	    G_warning("south falls outside the default region");
	    ok = 0;
	}

	if (cellhd->proj != PROJECTION_LL)
	{
	    if (cellhd->east > def_wind.east)
	    {
		G_warning("east falls outside the default region");
		ok = 0;
	    }

	    if (cellhd->west < def_wind.west)
	    {
		G_warning("west falls outside the default region");
		ok = 0;
	    }
	}
    }

ASK:
    fflush(stdin);
    if (type == AS_CELLHD)
        fprintf(stderr, "\nDo you accept this header? (y/n) [%s] > ",
	            ok ? "y" : "n");
    else
        fprintf(stderr, "\nDo you accept this region? (y/n) [%s] > ",
	            ok ? "y" : "n");

    if(!G_gets(buf))
	goto SHOW;

    G_strip (buf);
    switch (*buf)
    {
    case 0:
	    break;
    case 'y':
    case 'Y':
	    ok = 1 ;
	    break;
    case 'n':
    case 'N':
	    ok = 0;
	    break;
    default:
	    goto ASK;
    }

    if (ok)
	return 0;
}
}


static int hitreturn(void)
{
    char buf[100];

    fprintf (stderr, "hit RETURN -->");
    if (!fgets(buf, 100, stdin))
        exit(EXIT_SUCCESS);

    G_strip (buf);
    if (!strncmp(buf, "exit", sizeof(buf)))
        exit(EXIT_SUCCESS);

    return 0;
}
