/*
    MathComplexArrayPrivate - functions shared by complex MathArrays
    
    Copyright (C) 1995, Adam Fedor
    
    $Id: MathComplexArrayPrivate.m,v 1.9 2005/04/17 21:22:16 fedor Exp $
*/

#include <math.h>
#include <sys/param.h>	/* MIN, MAX */
#include "MathArray/complex.h"
#include "MathArray/MaskedException.h"
#include "MathComplexArrayPrivate.h"

complex_double 
find_cmin(complex_double a, complex_double b)
{
    return (a.real < b.real) ? a : b;
}

complex_double 
find_cmax(complex_double a, complex_double b)
{
    return (a.real > b.real) ? a : b;
}

complex_double 
find_csum(complex_double sum, complex_double num)
{
    return c_add(sum, num);
}

complex_double
complexf2d(const void *data, unsigned long loc) 
{
    complex_double t;
    t.real =  ((complex_float*)data + loc)->real;
    t.imag =  ((complex_float*)data + loc)->imag;
    return t;
}

complex_float
complexd2f(const void *data, unsigned long loc) 
{
    complex_float t;
    t.real =  ((complex_double*)data + loc)->real;
    t.imag =  ((complex_double*)data + loc)->imag;
    return t;
}

/* All the functions which know how to operate on this type */
static inline complex_double
op_exponent(complex_double a, complex_double b) {return cpow(a,b);}

static inline complex_double
op_multiply(complex_double a, complex_double b) {return c_mult(a, b);}

static inline complex_double
op_divide(complex_double a, complex_double b) {return c_div(a, b);}

static inline complex_double
op_add(complex_double a, complex_double b) {return c_add(a,b);}

static inline complex_double
op_subtract(complex_double a, complex_double b) {return c_sub(a, b);}

/*
static inline complex_double
op_mod(complex_double a, complex_double b) { }
*/

static inline complex_double
op_minimum(complex_double a, complex_double b) {return (a.real < b.real) ? a : b;}

static inline complex_double
op_maximum(complex_double a, complex_double b) {return (a.real > b.real) ? a : b;}

/*
static inline complex_double
op_not(complex_double a, complex_double b) { }
*/

static inline complex_double
op_equal(complex_double a, complex_double b)
{
    if (a.real == b.real && a.imag == b.imag) 
	a.real = 1;
    else
	a.real = 0;
    return a;
}

static inline complex_double
op_not_equal(complex_double a, complex_double b)
{
    if (a.real != b.real || a.imag != b.imag)
	a.real = 1;
    else
	a.real = 0;
    return a;
}

/*
static inline complex_double
op_less_or_equal(complex_double a, complex_double b) { }

static inline complex_double
op_less(complex_double a, complex_double b) { }

static inline complex_double
op_greater_or_equal(complex_double a, complex_double b) { }

static inline complex_double
op_greater(complex_double a, complex_double b) { }

static inline complex_double
op_and(complex_double a, complex_double b) { }

static inline complex_double
op_or(complex_double a, complex_double b) { }

static inline complex_double
op_xor(complex_double a, complex_double b) { }
*/

operate_f_t
operate_function(ma_operator_t operator)
{

    switch(operator) {
    case ma_exponent:
	return op_exponent;
	break;
    case ma_multiply:
	return op_multiply;
	break;
    case ma_matrix_multiply:
	NSCAssert(0, @"Invalid operator reference");
	break;
    case ma_divide:
	return op_divide;
	break;
    case ma_add:
	return op_add;
	break;
    case ma_subtract:
	return op_subtract;
	break;
    case ma_mod:
	return NULL;
	break;
    case ma_minimum:
	return op_minimum;
	break;
    case ma_maximum:
	return op_maximum;
	break;
    case ma_not:
	return NULL;
	break;
    case ma_equal:
	return op_equal;
	break;
    case ma_not_equal:
	return op_not_equal;
	break;
    case ma_less_or_equal:
	return NULL;
	break;
    case ma_less:
	return NULL;
	break;
    case ma_greater_or_equal:
	return NULL;
	break;
    case ma_greater:
	return NULL;
	break;
    case ma_and:
	return NULL;
	break;
    case ma_or:
	return NULL;
	break;
    case ma_xor:
	return NULL;
	break;
    }
    
    return NULL;
}

complex_func_t
replace_function(double_func_t cf)
{
    if (cf ==  (double_func_t)fabs)
	return (complex_func_t)NULL;
    else if (cf ==  (double_func_t)cos)
	return ccos;
    else if (cf ==  (double_func_t)exp)
	return cexp;
    else if (cf ==  (double_func_t)log)
	return clog;
    else if (cf ==  (double_func_t)log10)
	return clog10;
    else if (cf ==  (double_func_t)sin)
	return csin;
    else if (cf ==  (double_func_t)sqrt)
	return csqrt;
    else if (cf ==  (double_func_t)acos)
	return cacos;
    else if (cf ==  (double_func_t)asin)
	return casin;
    else if (cf ==  (double_func_t)atan)
	return catan;
    else if (cf ==  (double_func_t)cosh)
	return ccosh;
    else if (cf ==  (double_func_t)sinh)
	return csinh;
    else if (cf ==  (double_func_t)tan)
	return ctan;
    else if (cf ==  (double_func_t)tanh)
	return ctanh;
    
    return (complex_func_t)NULL;
}

