/* Copyright (C) 1999-2002 by Peter Eastman

   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. */

package artofillusion;

import java.awt.*;
import java.util.*;
import java.lang.reflect.*;


/** A set of static methods which are useful for general purpose.
 *  All methods for handling arrays will be moved to package datahandling
 *  and will be deprecated here.
 *
 *  Methods for handling the UI can be found in artofillusion.ui.UIUtilities
 *
 * @author Michael Butscher
 */

public class Utilities
{

  /** Returns the lowest i for which (array[i] == tofind) is true or -1 if not possible.
  */
  public static int findIndexIdent(Object[] array, Object tofind)
  {
    for(int i=0; i < array.length; ++i)
    {
      if (array[i] == tofind)
        return i;
    }
    return -1;
  }
  
  /** Returns the lowest i for which (array[i] == tofind) is true or -1 if not possible.
  */
  public static int findIndexIdent(int[] array, int tofind)
  {
    for(int i=0; i < array.length; ++i)
    {
      if (array[i] == tofind)
        return i;
    }
    return -1;
  }

  /** Returns the lowest i for which tofind.equals(array[i]) is true or -1 if not possible. */
  public static int findIndexEqual(Object[] array, Object tofind)
  {
    if (tofind == null)
      return findIndexIdent(array, null);    // TODO(MB) Better answer?
    
    for(int i=0; i < array.length; ++i)
    {
      if (tofind.equals(array[i]))
        return i;
    }
    return -1;
  }

  /** Returns an array of all indices i for which boolarr[i] is true, in ascending order. */
  public static int[] createIndexList(boolean[] boolarr)
  {
    Vector idx = new Vector();  // Vector of Integer
    int i;

    for(i = 0; i < boolarr.length; ++i)
    {
      if (boolarr[i])
        idx.add(new Integer(i));
    }

    Integer[] idx2 = (Integer[])idx.toArray(new Integer[0]);
    int[] idx3 = new int[idx2.length];

    for(i = 0; i < idx2.length; ++i)
      idx3[i] = idx2[i].intValue();

    return idx3;
  }

  /** Copies an array of objects which implement the Copieable interface.
    The elements in the new array are created by calling the
    #Copieable.createCopy method of each element.

    <P>Example:<br>
    Vertex[] vertex = ...;<br>
    Vertex[] newvert = (Vertex[]) deepArrayCopy(vertex);<br>

    @param objs   the array to copy
    @return   a deep copy of objs which can be casted to the original type of objs
  */

  public static Copieable[] deepArrayCopy(Copieable[] objs)
  {
    Class cmpclass = objs.getClass().getComponentType();
    Copieable[] result = (Copieable[]) Array.newInstance(cmpclass, objs.length);

    for(int i = 0; i < objs.length; ++i)
    {
      result[i] = objs[i].createCopy();
    }

    return result;
  }

  /** Appends an object to the end of an array. The returned array type
    can be casted to the same type the parameter array had.

    @param array the array, the object will be appended
    @param obj the object to append
    @return a new array with the obj as last element.*/

  public static Object[] arrayAppend(Object[] array, Object obj)
  {
    Class cmpclass = array.getClass().getComponentType();
    Object[] result = (Object[]) Array.newInstance(cmpclass, array.length+1);

    System.arraycopy(array, 0, result, 0, array.length);
    result[array.length] = obj;

    return result;
  }

  /** Appends an int to the end of an int array and returns the new array. */

  public static int[] arrayAppend(int[] array, int obj)
  {
    int[] result = new int[array.length+1];

    System.arraycopy(array, 0, result, 0, array.length);
    result[array.length] = obj;

    return result;
  }
  
  /** Remove element with index i from array. The returned array type
    can be casted to the same type the parameter array had.
  */
  public static Object[] arrayRemove(Object[] array, int i)
  {
    Class cmpclass = array.getClass().getComponentType();
    Object[] result = (Object[]) Array.newInstance(cmpclass, array.length-1);
    
    System.arraycopy(array, 0, result, 0, i);
    if (i < result.length)
      System.arraycopy(array, i+1, result, i, result.length-i-1);

    return result;
  }
  
  /** Remove element with index i from array. The returned array type
    can be casted to the same type the parameter array had.
  */
  public static int[] arrayRemove(int[] array, int i)
  {
    int[] result = new int[array.length-1];
    
    System.arraycopy(array, 0, result, 0, i);
    if (i < result.length)
      System.arraycopy(array, i+1, result, i, result.length-i);

    return result;
  }
  
  /** Concatenate two arrays and return a new one. */
  public static double[] arrayConcat(double[] array1, double[] array2)
  {
    double[] result = new double[array1.length + array2.length];
    
    System.arraycopy(array1, 0, result, 0, array1.length);
    System.arraycopy(array2, 0, result, array1.length, array2.length);
    
    return result;
  }
  
  /** Ensures that an array has exactly the desired length.
    @param array if array has the desired length, it is returned,
                 otherwise a new array is created. If array is null
                 a new array is created anyway.
    @param len the desired length of the array
    @return array if array.length == len, otherwise a new array is created.
            The returned array type can be casted to the same type the
            parameter array had.
  */
  
  public static boolean[] arrayEnsureLength(boolean[] array, int len)
  {
    if (array == null || array.length != len)
      return new boolean[len];
    
    return array;
  }
  
  
  /** Return the maximum of two values. */
  public static int max(int a, int b)
  {
    if (a > b)
      return a;
    return b;
  }
  
  /** Separate a line into pieces divided by whitespace. */

  public static String [] breakLine(String line)   //TODO(MB) Move or remove
  {
    StringTokenizer st = new StringTokenizer(line);
    Vector v = new Vector();

    while (st.hasMoreTokens())
      v.addElement(st.nextToken());
    String result[] = new String [v.size()];
    v.copyInto(result);
    return result;
  }



  /* Returns a result array of boolean with length len where
    result[i] is true iff i is a value in indexarr.  public static boolean[] createBooleanSelection(int[] indexarr, int len)
  {
    boolean[] result = new
    Vector idx = new Vector();  // Vector of Integer
    int i;

    for(i = 0; i < boolarr.length; ++i)
    {
      if (boolarr[i])
        idx.add(new Integer(i));
    }

    Integer[] idx2 = (Integer[])idx.toArray(new Integer[0]);
    int[] idx3 = new int[idx2.length];

    for(i = 0; i < idx2.length; ++i)
      idx3[i] = idx2[i].intValue();

    return idx3;
  } */



}
