/* Copyright (C) 1997, 2000 artofcode LLC.  All rights reserved.
  
  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  59 Temple Place, Suite 330, Boston, MA, 02111-1307.

*/

/*$Id: gsfunc.c,v 1.4.6.1.2.1 2003/01/17 00:49:02 giles Exp $ */
/* Generic Function support */
#include "gx.h"
#include "gserrors.h"
#include "gsparam.h"
#include "gxfunc.h"

/* GC descriptors */
public_st_function();

/* Generic free_params implementation. */
void
fn_common_free_params(gs_function_params_t * params, gs_memory_t * mem)
{
    gs_free_const_object(mem, params->Range, "Range");
    gs_free_const_object(mem, params->Domain, "Domain");
}

/* Generic free implementation. */
void
fn_common_free(gs_function_t * pfn, bool free_params, gs_memory_t * mem)
{
    if (free_params)
	gs_function_free_params(pfn, mem);
    gs_free_object(mem, pfn, "fn_common_free");
}

/* Check the values of m, n, Domain, and (if supplied) Range. */
int
fn_check_mnDR(const gs_function_params_t * params, int m, int n)
{
    int i;

    if (m <= 0 || n <= 0)
	return_error(gs_error_rangecheck);
    for (i = 0; i < m; ++i)
	if (params->Domain[2 * i] > params->Domain[2 * i + 1])
	    return_error(gs_error_rangecheck);
    if (params->Range != 0)
	for (i = 0; i < n; ++i)
	    if (params->Range[2 * i] > params->Range[2 * i + 1])
		return_error(gs_error_rangecheck);
    return 0;
}

/* Get the monotonicity of a function over its Domain. */
int
fn_domain_is_monotonic(const gs_function_t *pfn, gs_function_effort_t effort)
{
#define MAX_M 16		/* arbitrary */
    float lower[MAX_M], upper[MAX_M];
    int i;

    if (pfn->params.m > MAX_M)
	return gs_error_undefined;
    for (i = 0; i < pfn->params.m; ++i) {
	lower[i] = pfn->params.Domain[2 * i];
	upper[i] = pfn->params.Domain[2 * i + 1];
    }
    return gs_function_is_monotonic(pfn, lower, upper, effort);
}

/* Return default function information. */
void
gs_function_get_info_default(const gs_function_t *pfn, gs_function_info_t *pfi)
{
    pfi->DataSource = 0;
    pfi->Functions = 0;
}

/* Write generic parameters (FunctionType, Domain, Range) on a parameter list. */
int
fn_common_get_params(const gs_function_t *pfn, gs_param_list *plist)
{
    int ecode = param_write_int(plist, "FunctionType", &FunctionType(pfn));
    int code;

    if (pfn->params.Domain) {
	code = param_write_float_values(plist, "Domain", pfn->params.Domain,
					2 * pfn->params.m, false);
	if (code < 0)
	    ecode = code;
    }
    if (pfn->params.Range) {
	code = param_write_float_values(plist, "Range", pfn->params.Range,
					2 * pfn->params.n, false);
	if (code < 0)
	    ecode = code;
    }
    return ecode;
}
