/*
    arrayfuncs - handy functions for math arrays
    
    Copyright (C) 1995, Adam Fedor
*/
#ifdef NEXT_FOUNDATION
#import <foundation/NSString.h>
#import <foundation/NSData.h>
#import <foundation/NSRange.h>
#else
#import <Foundation/NSString.h>
#import <Foundation/NSData.h>
#import <Foundation/NSRange.h>
#endif
#include <math.h>
#include "MathArray/array_encoding.h"

/* Convenient functions for determining the size of the arrays */
unsigned long 
array_sizeof_elements(const char* type)
{
    return math_sizeof_type(type);
}

unsigned long 
array_aligned_sizeof_elements(const char* type)
{
    return math_aligned_size(type);
}

unsigned long
array_num_elements(unsigned dimension, const unsigned* size)
{
    unsigned i;
    unsigned long num;
    
    /* Also works in special case for a scalar (dimension = 0) */
    num = 1;
    for (i=0; i < dimension; i++)
    	num *= size[i];
    return num;
}

unsigned long 
array_num_bytes(unsigned dimension, const unsigned* size, const char* type)
{
    return array_num_elements(dimension, size) * array_sizeof_elements(type);
}


/* Convienent functions for stepping through the array */
unsigned long 
ordered_index(unsigned dimension, NSData* sizes, unsigned* index)
{
    int i;
    unsigned long order_index;
    unsigned offset;
    const unsigned *size = (const unsigned *)[sizes bytes];
    
    offset = 1;
    order_index = 0;
    for (i=dimension-1; i >= 0; i--) {
    	order_index += offset * index[i];
	offset *= size[i];
    }
    return order_index;
}

/* Used only by transpose (so far), but kept here for convienience */
unsigned long 
inverted_ordered_index(unsigned dimension, NSData* sizes, unsigned* index)
{
    int i;
    unsigned long order_index;
    unsigned offset;
    const unsigned *size = (const unsigned *)[sizes bytes];
    
    offset = 1;
    order_index = 0;
    for (i=dimension-1; i >= 0; i--) {
    	order_index += offset * index[dimension - i - 1];
	offset *= size[i];
    }
    return order_index;
}

unsigned* 
start_index_from_range(unsigned dimension, NSRange *range,
		unsigned *buf)
{
    int i;
    
    for (i=0; i < dimension; i++)
    	buf[i] = range[i].location;
    return buf;
}

/* Steps through the index array in a range specified by the range array.
   Returns 1 if the index goes outside the range */
int 
increment_index_in_range(unsigned dimension, 
		NSRange *range, unsigned *index, unsigned step)
{
    int i, length;
    
    for (i=dimension-1; i >= 0; i--) {
    	index[i] += step;
	length = (range[i].length != 0) ? range[i].length : 1; 
    	if (index[i] >= NSMaxRange(range[i])) {
    	    step = (index[i] - range[i].location) / length;
            index[i] = (index[i] - range[i].location) % length 
	      + range[i].location;
    	} else
	    step = 0;
    }
    return step;
}

