/*
 * Open Source Physics software is free software as described near the bottom of this code file.
 *
 * For additional information and documentation on Open Source Physics please see:
 * <http://www.opensourcephysics.org/>
 */

package org.opensourcephysics.tools;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import org.opensourcephysics.controls.XMLControl;
import org.opensourcephysics.display.DatasetManager;

/**
 * A FunctionEditor for Parameters.
 *
 * @author Douglas Brown
 */
public class ParamEditor extends FunctionEditor {
  protected double[] paramValues = new double[0];
  private DatasetManager data;
  private FunctionEditor[] functionEditors;

  /**
   * Default constructor
   */
  public ParamEditor() {
    super();
    paramEditor = this;
  }

  /**
   * Constructor using a DatasetManager to define initial parameters
   *
   * @param input the DatasetManager
   */
  public ParamEditor(DatasetManager input) {
    this();
    data = input;
    loadParametersFromData();
  }

  /**
   * Gets an array containing copies of the current parameters.
   *
   * @return an array of Parameters
   */
  public Parameter[] getParameters() {
    Parameter[] params = new Parameter[objects.size()];
    for(int i = 0; i<objects.size(); i++) {
      Parameter next = (Parameter) objects.get(i);
      params[i] = new Parameter(next.paramName, next.expression);
      params[i].setExpressionEditable(next.isExpressionEditable());
      params[i].setNameEditable(next.isNameEditable());
      params[i].setDescription(next.getDescription());
      params[i].value = next.value;
    }
    return params;
  }

  /**
   * Replaces the current parameters with new ones.
   *
   * @param params an array of Parameters
   */
  public void setParameters(Parameter[] params) {
    List<Object> list = new ArrayList<Object>();
    for(int i = 0; i<params.length; i++) {
      list.add(params[i]);
    }
    setObjects(list);
  }

  /**
   * Sets the function editors that use these parameters.
   *
   * @param editors an array of FunctionEditors
   */
  public void setFunctionEditors(FunctionEditor[] editors) {
    functionEditors = editors;
  }

  /**
   * Gets the current parameter values.
   *
   * @return an array of values
   */
  public double[] getValues() {
    return paramValues;
  }

  /**
   * Returns the name of the object.
   *
   * @param obj the object
   * @return the name
   */
  public String getName(Object obj) {
    return(obj==null) ? null : ((Parameter) obj).paramName;
  }

  /**
   * Returns the expression of the object.
   *
   * @param obj the object
   * @return the expression
   */
  public String getExpression(Object obj) {
    return(obj==null) ? null : ((Parameter) obj).expression;
  }

  /**
   * Returns a tooltip for the object.
   *
   * @param obj the object
   * @return the tooltip
   */
  public String getTooltip(Object obj) {
    String s = ((Parameter) obj).getDescription();
    if(s==null) {
      s = ToolsRes.getString("ParamEditor.Table.Cell.Name.Tooltip"); //$NON-NLS-1$
    }
    return s;
  }

  /**
   * Determines if an object's name is editable.
   *
   * @param obj the object
   * @return true if the name is editable
   */
  public boolean isNameEditable(Object obj) {
    return((Parameter) obj).isNameEditable();
  }

  /**
   * Determines if an object's expression is editable.
   *
   * @param obj the object
   * @return true if the expression is editable
   */
  public boolean isExpressionEditable(Object obj) {
    return((Parameter) obj).isExpressionEditable();
  }

  /**
   * Evaluates an object.
   */
  protected void evaluateObject(Object obj) {
    Parameter p = (Parameter) obj;
    p.evaluate(objects);
  }

  /**
   * Evaluates parameters that depend on the named parameter.
   *
   * @param seed the independent parameter
   * @return a list of evaluated dependent parameters
   */
  public ArrayList<Parameter> evaluateDependents(Parameter seed) {
    ArrayList<Parameter> temp = new ArrayList<Parameter>();
    ArrayList<Parameter> toRemove = new ArrayList<Parameter>();
    for(int i = 0; i<evaluate.size(); i++) {
      Parameter param = (Parameter) evaluate.get(i);
      if(param.paramName.equals(seed.paramName)) {
        temp.add(seed);
        toRemove.add(seed);
        for(int j = i+1; j<evaluate.size(); j++) {
          Parameter p = (Parameter) evaluate.get(j);
          temp.add(new Parameter(p.paramName, p.expression));
        }
        // evaluate temp list
        for(int j = 0; j<temp.size(); j++) {
          // for each parameter, evaluate and set paramValues element
          Parameter p = temp.get(j);
          p.evaluate(temp);
          if(getReferences(p.getName(), null).isEmpty()) {
            toRemove.add(p);
          }
        }
        temp.removeAll(toRemove);
        return temp;
      }
    }
    return temp;
  }

  /**
   * Evaluates all current objects.
   */
  public void evaluateAll() {
    super.evaluateAll();
    if(this.getClass()!=ParamEditor.class) {
      return;
    }
    if(paramValues.length!=objects.size()) {
      paramValues = new double[objects.size()];
    }
    for(int i = 0; i<evaluate.size(); i++) {
      Parameter p = (Parameter) evaluate.get(i);
      p.evaluate(objects);
    }
    for(int i = 0; i<objects.size(); i++) {
      Parameter p = (Parameter) objects.get(i);
      paramValues[i] = p.getValue();
    }
  }
  
  /**
   * Sets the description of the named parameter, if any.
   *
   * @param name the name
   * @param description the description
   */
  public void setDescription(String name, String description) {
    for(Object obj: objects) {
      Parameter param = (Parameter)obj;
      if (param.getName().equals(name)) {
      	param.setDescription(description);
      	break;
      }
    }
  }

  /**
   * Returns true if a name is already in use.
   *
   * @param obj the object (may be null)
   * @param name the proposed name for the object
   * @return true if duplicate
   */
  protected boolean isDisallowedName(Object obj, String name) {
    boolean disallowed = super.isDisallowedName(obj, name);
    if(functionEditors!=null) {
      for(int i = 0; i<functionEditors.length; i++) {
        disallowed = disallowed||functionEditors[i].isDisallowedName(null, name);
      }
    }
    return disallowed;
  }

  /**
   * Pastes the clipboard contents.
   */
  protected void paste() {
    XMLControl[] controls = getClipboardContents();
    if(controls==null) {
      return;
    }
    for(int i = 0; i<controls.length; i++) {
      // create a new object
      Parameter param = (Parameter) controls[i].loadObject(null);
      param.setNameEditable(true);
      param.setExpressionEditable(true);
      addObject(param, true);
    }
    evaluateAll();
  }

  /**
   * Returns true if the object expression is invalid.
   */
  protected boolean isInvalidExpression(Object obj) {
    return Double.isNaN(((Parameter) obj).getValue());
  }

  /**
   * Creates an object with specified name and expression.
   * This always returns a new Parameter but copies the editable properties.
   *
   * @param name the name
   * @param expression the expression
   * @param obj ignored
   * @return the object
   */
  protected Object createObject(String name, String expression, Object obj) {
    Parameter original = (Parameter) obj;
    if((original!=null)&&original.paramName.equals(name)&&original.expression.equals(expression)) {
      return original;
    }
    Parameter p = new Parameter(name, expression);
    if(original!=null) {
      p.setExpressionEditable(original.isExpressionEditable());
      p.setNameEditable(original.isNameEditable());
      p.setDescription(original.getDescription());
    }
    return p;
  }

  /**
   * Refreshes the GUI.
   */
  protected void refreshGUI() {
    super.refreshGUI();
    newButton.setToolTipText(ToolsRes.getString("ParamEditor.Button.New.Tooltip"));              //$NON-NLS-1$
    setBorder(BorderFactory.createTitledBorder(ToolsRes.getString("ParamEditor.Border.Title"))); //$NON-NLS-1$
  }

  /**
   * Loads parameters from the current datasetManager.
   */
  public void loadParametersFromData() {
    if(data==null) return;
    String[] names = data.getConstantNames();
    for (String name: names) {
    	String expression = data.getConstantExpression(name);
      Parameter p = (Parameter) getObject(name);
      if(p==null) {
        p = new Parameter(name, expression);
        addObject(p, false);
      }
      else setExpression(name, expression, false);
    }
  }

  /**
   * Refreshes the parameters associated with a user function.
   */
  protected void refreshParametersFromFunction(UserFunction f) {
    // identify values that have changed
    for(int i = 0; i<f.getParameterCount(); i++) {
      String name = f.getParameterName(i);
      String val = String.valueOf(f.getParameterValue(i));
      Parameter p = (Parameter) getObject(name);
      if(p==null) {
        p = new Parameter(name, val);
        p.setNameEditable(false);
        p.setExpressionEditable(false);
        addObject(p, false);
      }
      // change parameter value
      else {
        setExpression(name, val, false);
      }
    }
  }

  /**
   * Returns the default name for newly created objects.
   */
  protected String getDefaultName() {
    return ToolsRes.getString("ParamEditor.New.Name.Default"); //$NON-NLS-1$
  }

}

/*
 * Open Source Physics software is free software; you can redistribute
 * it and/or modify it under the terms of the GNU General Public License (GPL) as
 * published by the Free Software Foundation; either version 2 of the License,
 * or(at your option) any later version.

 * Code that uses any portion of the code in the org.opensourcephysics package
 * or any subpackage (subdirectory) of this package must must also be be released
 * under the GNU GPL license.
 *
 * This software 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
 * or view the license online at http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2007  The Open Source Physics project
 *                     http://www.opensourcephysics.org
 */
