/*
 * @(#)FloatArray.java    2.4.0   6 September 2005
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.util;

import java.awt.geom.*;

/**
 * <P>Class <CODE>FloatArray</CODE> encapsulates utilities for arrays of
 * <CODE>float</CODE>.</P>
 *
 * <P>Class <CODE>FloatArray</CODE> cannot be instantiated.</P>
 *
 * @author  Richard Rasala
 * @version 2.4.0
 * @since   2.3
 */
public class FloatArray {

    /** Private constructor to prevent instantiation. */
    private FloatArray() {}
    
    
    /**
     * <p>Returns a deep clone of an array float[].</p>
     *
     * <p>Returns <code>null</code> if the given data
     * is <code>null</code>.</p>
     *
     * @param  data the array to deep clone
     * @return the deep clone
     */
    public static float[] deepclone(float[] data) {
        if (data == null)
            return null;
        
        return (float[])data.clone();
    }
    
    
    /**
     * <p>Returns a deep clone of an array float[][].</p>
     *
     * <p>Returns <code>null</code> if the given data
     * is <code>null</code>.</p>
     *
     * @param  data the array to deep clone
     * @return the deep clone
     */
    public static float[][] deepclone(float[][] data) {
        if (data == null)
            return null;
        
        int N = data.length;
        
        float[][] result = new float[N][];
        
        for (int i = 0; i < N; i++)
            result[i] = deepclone(data[i]);
        
        return result;
    }
    
    
    /**
     * <P>Returns a deep merge of the given arrays of float[].  This means:</P>
     *
     * <UL>
     *   <LI> If both arrays are <CODE>null</CODE>,
     *        return <CODE>null</CODE>;</LI>
     *   <LI> If one array is <CODE>null</CODE>,
     *        return a deep clone of the other array;</LI>
     *   <LI> If both arrays are not <CODE>null</CODE>,
     *        return an array whose length is the sum of the lengths
     *        of the given arrays and whose data is the data of the
     *        first array followed by the data of the second array.</LI>
     * </UL>
     *
     * @param  array1 the first  array to deep merge
     * @param  array2 the second array to deep merge
     * @return the deep merge of array1 and array2
     */
    public static float[] deepmerge(float[] array1, float[] array2) {
        if ((array1 == null) && (array2 == null))
            return null;
        
        if (array1 == null)
            return deepclone(array2);
        
        if (array2 == null)
            return deepclone(array1);
        
        int M = array1.length;
        int N = array2.length;
        int S = M + N;
        
        float[] result = new float[S];
        
        for (int i = 0; i < S; i++)
            result[i] = (i < M) ? array1[i] : array2[i-M];
        
        return result;
    }
    
    
    /**
     * <P>Returns a deep merge of the given arrays of float[][].  This means:</P>
     *
     * <UL>
     *   <LI> If both arrays are <CODE>null</CODE>,
     *        return <CODE>null</CODE>;</LI>
     *   <LI> If one array is <CODE>null</CODE>,
     *        return a deep clone of the other array;</LI>
     *   <LI> If both arrays are not <CODE>null</CODE>,
     *        return an array whose length is the maximum of the lengths
     *        of the given arrays and whose rows are created
     *        by performing a deep merge of the rows of the given arrays.</LI>
     * </UL>
     *
     * @param  array1 the first  array to deep merge
     * @param  array2 the second array to deep merge
     * @return the deep merge of array1 and array2
     */
    public static float[][] deepmerge(float[][] array1, float[][] array2) {
        if ((array1 == null) && (array2 == null))
            return null;
        
        if (array1 == null)
            return deepclone(array2);
        
        if (array2 == null)
            return deepclone(array1);
        
        int M = array1.length;
        int N = array2.length;
        int S = Math.max(M, N);
        
        float[][] result = new float[S][];
        
        for (int i = 0; i < S; i++) {
            float[] temp1 = (i < M) ? array1[i] : null;
            float[] temp2 = (i < N) ? array2[i] : null;
            
            result[i] = deepmerge(temp1, temp2);
        }
        
        return result;
    }
    
    
    /**
     * Returns true if and only if the data array is non-<CODE>null</CODE>
     * and has S float numbers in each row.
     *
     * @param  array the array to check
     * @param  S the desired size of each row
     * @return true if and only if array has the form float[N][S] for some N
     */
    public static boolean checkArray(float[][] array, int S) {
        if (array == null)
            return false;
        
        int length = array.length;
        
        for (int i = 0; i < length; i++)
            if ((array[i] == null) || (array[i].length != S))
                return false;
        
        return true;
    }
    
    
    /**
     * Returns true if and only if both data arrays are non-<CODE>null</CODE>,
     * have the same length N, and have S float numbers in each row.
     *
     * @param  array1 the first  array to check
     * @param  array2 the second array to check
     * @param  S the desired size of each row
     * @return true if and only if both arrays have the form float[N][S] for some N
     */
    public static boolean checkArrayPair(float[][] array1, float[][] array2, int S) {
        return (array1 != null)
            && (array2 != null)
            && (array1.length == array2.length)
            && checkArray(array1, S)
            && checkArray(array2, S);
    }
    
    
    /**
     * Returns true if the two arrays are both <CODE>null</CODE> or are
     * both non-<CODE>null</CODE> and have the same size and data.
     *
     * @param  array1 the first  array
     * @param  array2 the second array
     */
    public static boolean equals(float[] array1, float[] array2) {
        if (array1 == array2)
            return true;
        
        if ((array1 == null) && (array2 != null))
            return false;
        
        if ((array1 != null) && (array2 == null))
            return false;
        
        int m = array1.length;
        int n = array2.length;
        
        if (m != n)
            return false;
        
        for (int i = 0; i < m; i++)
            if (array1[i] != array2[i])
                return false;
        
        return true;
    }
    
    
    /**
     * Returns true if the two arrays are both <CODE>null</CODE> or are
     * both non-<CODE>null</CODE> and have the same structure and data.
     *
     * @param  array1 the first  array
     * @param  array2 the second array
     */
    public static boolean equals(float[][] array1, float[][] array2) {
        if (array1 == array2)
            return true;
        
        if ((array1 == null) && (array2 != null))
            return false;
        
        if ((array1 != null) && (array2 == null))
            return false;
        
        int m = array1.length;
        int n = array2.length;
        
        if (m != n)
            return false;
        
        for (int i = 0; i < m; i++)
            if (! equals(array1[i], array2[i]))
                return false;
        
        return true;
    }
    
    
    /**
     * <p>Returns a new size 2 <code>float[]</code> corresponding to the given
     * <code>Point2D</code>.</p>
     *
     * <p>Returns <code>null</code> if the parameter is <code>null</code>.</p>
     *
     * @param point the point to convert 
     */
    public static float[] fromPoint2D(Point2D point) {
        if (point == null)
            return null;
        
        float x = (float) point.getX();
        float y = (float) point.getY();
        
        return new float[] { x, y };
    }
    
    
    /**
     * <p>Returns a new <code>float[][]</code> of size N-by-2 corresponding to
     * the given <code>Point2D[]</code> of size N.</p>
     *
     * <p>Returns <code>null</code> if the parameter is <code>null</code>.</p>
     *
     * @param points the points to convert 
     */
    public static float[][] fromPoint2D(Point2D[] points) {
        if (points == null)
            return null;
        
        int N = points.length;
        
        float[][] result = new float[N][];
        
        for (int i = 0; i < N; i++)
            result[i] = fromPoint2D(points[i]);
        
        return result;
    }
    
    
    /**
     * <p>Returns a new <code>Point2D</code> corresponding to the given
     * <code>float[]</code> provided the parameter is non-<code>null</code>
     * and of size 2.</p>
     *
     * <p>Returns <code>null</code> if the preconditions are not met.</p>
     *
     * @param array to array to convert
     */
    public static Point2D toPoint2D(float[] array) {
        if ((array == null) || (array.length != 2))
            return null;
        
        return new Point2D.Double(array[0], array[1]);
    }
    
    
    /**
     * <p>Returns a new <code>Point2D[]</code> of size N corresponding to
     * the given <code>float[][]</code> of size N-by-2.</p>
     *
     * <p>Returns <code>null</code> if the parameter is <code>null</code>.</p>
     *
     * @param array to array to convert
     */
    public static Point2D[] toPoint2D(float[][] array) {
        if (array == null)
            return null;
        
        int N = array.length;
        
        Point2D[] result = new Point2D[N];
        
        for (int i = 0; i < N; i++)
            result[i] = toPoint2D(array[i]);
        
        return result;
    }
    
}
