/*=========================================================================
 
  Program:   Orbit Visualization Tool
  Source:    $Source: /stor/devel/ovt2g/ovt/beans/SliderPropertyEditor.java,v $
  Date:      $Date: 2001/04/06 18:57:58 $
  Version:   $Revision: 1.6 $
 
 
Copyright (c) 2000 OVT Team (Kristof Stasiewicz, Mykola Khotyaintsev,
Yuri Khotyaintsev)
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification is permitted provided that the following conditions are met:
 
 * No part of the software can be included in any commercial package without
written consent from the OVT team.
 
 * Redistributions of the source or binary code must retain the above
copyright notice, this list of conditions and the following disclaimer.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT OR
INDIRECT DAMAGES  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE.
 
OVT Team (http://ovt.irfu.se)   K. Stasiewicz, M. Khotyaintsev, Y.
Khotyaintsev
 
=========================================================================*/

/*
 * SliderEditor.java
 *
 * Created on 23 Март 2001 г., 13:35
 */

package ovt.beans;

import ovt.interfaces.*;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.beans.*;

/**
 *
 * @author  oleg
 * @version
 */
public class SliderPropertyEditor extends ComponentPropertyEditor implements PropertyChangeListener {
    
    private ChangeListener changeListener;
    
    private static final int INITIAL = 60;
    
    /** Holds value of property maxScale. */
    private double maxScale = 8.;
    
    /** Holds value of property linear. */
    private boolean linear = true;
    
    /** Holds value of property min. */
    private int min = -INITIAL;
    
    /** Holds value of property max. */
    private int max =  INITIAL;
    
    /** Holds value of property minorTickSpacing. */
    private int minorTickSpacing = INITIAL;
    
    /** Holds value of property majorTickSpacing. */
    private int majorTickSpacing = INITIAL;
    
    private BasicPropertyDescriptor pd;
    
    /** Holds value of property labeled. */
    private boolean labeled = false;
    
    /** Creates new SliderPropertyEditor */
    public SliderPropertyEditor(BasicPropertyDescriptor pd) {
        super(pd);
        this.pd = pd;
    }
    
    public Component getComponent() {
        if (component == null) {
            JSlider slider = new JSlider();
            component = slider;
            changeListener = new ChangeListener() {
                public void stateChanged(ChangeEvent e) {
                    int newPos = ((JSlider)component).getValue();
                    try {
                        String srcType = pd.getWriteMethod().getParameterTypes()[0].getName();
                        if (srcType.equals("int"))      setValue(new Integer((int)Math.round(calcValue(newPos))));
                        if (srcType.equals("double"))   setValue(new Double(calcValue(newPos)));
                        fireEditingFinished();
                    } catch (PropertyVetoException ignore) {}
                }
            };
            slider.addChangeListener(changeListener);
            update();
            //Dimension ps = slider.getPreferredSize();
            //s.width = ps.width * 6 / 5;
            //slider.setMinimumSize(ps);
        }
        return component;
    }
    
    private void update() {
        if (component != null) {
            JSlider slider = (JSlider) component;
            slider.removeChangeListener(changeListener);
            int pos = calcPosition(getdoubleValue());
            slider.setValue(pos);
            slider.setMinimum(min);
            slider.setMaximum(isLinear() ? max : max+1);
            slider.setValue(pos);
            setLabels();
            slider.addChangeListener(changeListener);
        }
    }
    
    private void setLabels() {
        if (component == null) return;
        JSlider s = (JSlider) component;
        if (isLabeled()) {
            s.setMinorTickSpacing(minorTickSpacing);
            s.setMajorTickSpacing(majorTickSpacing);
            s.setPaintTicks(true);
            s.setPaintLabels(true);
            s.setSnapToTicks(isLinear());
            
            Dictionary labels = new Hashtable();
            for(int i = s.getMinimum(); i<=s.getMaximum(); i+=s.getMajorTickSpacing()) {
                String label = isLinear() ? "" + i : "" + calcValue(i);
                labels.put(new Integer(i), new JLabel(label));
            }
            s.setLabelTable(labels);
        }
        else {
            s.setPaintTicks(false);
            s.setPaintLabels(false);
            s.setSnapToTicks(false);
        }
    }
    
    private double calcValue(int pos) {
        if (isLinear()) return (double) pos;
        else {
            double val = Math.exp(pos * Math.log(maxScale) / (max-min) * 2);
            return Math.round(val * 1000.) / 1000.;
        }
    }
    
    private int calcPosition(double value) {
        if (isLinear()) return (int)Math.round(value);
        else {
            return (int)Math.round(Math.log(value) / Math.log(maxScale) * (max-min) / 2);
        }
    }
    
    double getdoubleValue() {
        Object obj = getValue();
        try {
            return (double)((Integer) obj).intValue();
        } catch(ClassCastException e) {}
        try {
            return ((Double) obj).doubleValue();
        } catch(ClassCastException e) {}
        return 0;
    }
    
    /** Getter for property maxScale. Property for non-linear slider
     * @return Value of property maxScale.
     */
    public double getMaxScale() {
        return maxScale;
    }
    
    /** Setter for property maxScale. Property for non-linear slider
     * @param maxScale New value of property maxScale.
     */
    public void setMaxScale(double maxScale) {
        this.maxScale = maxScale;
    }
 
    /** Getter for property linear.
     * @return Value of property linear.
     */
    public boolean isLinear() {
        return linear;
    }
    
    /** Setter for property linear.
     * @param linear New value of property linear.
     */
    public void setLinear(boolean linear) {
        this.linear = linear;
    }
    
    /** Getter for property min.
     * @return Value of property min.
     */
    public int getMin() {
        return min;
    }
    
    /** Setter for property min.
     * @param min New value of property min.
     */
    public void setMin(int min) {
        this.min = min;
    }
    
    /** Getter for property max.
     * @return Value of property max.
     */
    public int getMax() {
        return max;
    }
    
    /** Setter for property max.
     * @param max New value of property max.
     */
    public void setMax(int max) {
        this.max = max;
    }
    
    /** Getter for property minorTickSpacing.
     * @return Value of property minorTickSpacing.
     */
    public int getMinorTickSpacing() {
        return minorTickSpacing;
    }
    
    /** Setter for property minorTickSpacing.
     * @param minorTickSpacing New value of property minorTickSpacing.
 */
    public void setMinorTickSpacing(int minorTickSpacing) {
        this.minorTickSpacing = minorTickSpacing;
    }
    
    /** Getter for property majorTickSpacing.
     * @return Value of property majorTickSpacing.
     */
    public int getMajorTickSpacing() {
        return majorTickSpacing;
    }
    
    /** Setter for property majorTickSpacing.
     * @param majorTickSpacing New value of property majorTickSpacing.
     */
    public void setMajorTickSpacing(int majorTickSpacing) {
        this.majorTickSpacing = majorTickSpacing;
    }
    
    public void makeLinear(int min, int max, int majorTickSpacing, int minorTickSpacing) {
        setLinear(true);
        setLabeled(true);
        setMin(min);
        setMax(max);
        setMinorTickSpacing(minorTickSpacing);
        setMajorTickSpacing(majorTickSpacing);
        update();
    }
    
    public void makeLinear(int min, int max) {
        setLinear(true);
        setLabeled(false);
        setMin(min);
        setMax(max);
        update();
    }

    public void makeExponential(double maxScale, int numberOfLabels) {
        setLinear(false);
        setLabeled(true);
        setMaxScale(maxScale);
        setMin(-INITIAL);
        setMax( INITIAL);
        int tickSpacing = (max - min) / (numberOfLabels - 1);
        setMinorTickSpacing(tickSpacing);
        setMajorTickSpacing(tickSpacing);
        update();
    }
    
    /** Getter for property labeled.
     * @return Value of property labeled.
     */
    public boolean isLabeled() {
        return labeled;
    }
    
    /** Setter for property labeled.
     * @param labeled New value of property labeled.
     */
    public void setLabeled(boolean labeled) {
        this.labeled = labeled;
    }
    
    public void propertyChange(PropertyChangeEvent evt) {
        JSlider slider = (JSlider) component;
        if (slider != null) {
            slider.removeChangeListener(changeListener);
            slider.setValue(calcPosition(getdoubleValue()));
            slider.addChangeListener(changeListener);
        }
    }
    
}
