/**
 *  Licensed under GPL. For more information, see
 *    http://jaxodraw.sourceforge.net/license.html
 *  or the LICENSE file in the jaxodraw distribution.
 */
package net.sf.jaxodraw.gui.swing.spinner;

import java.text.NumberFormat;

import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;


/** Specialization of SpinnerNumberModel that only allows integers to avoid
 * rounding issues. Treats them as rotation angles, normalizing to the
 * interval ]-180, 180]. getPrevious/NextValue also act circularly.
 * The minimum and maximum are always set to [-179, 180] and should not be changed.
 * @since 2.0
 */
public class JaxoSpinnerRotationModel extends SpinnerNumberModel {
    private static final long serialVersionUID = 7526471155622776147L;

    /** With initial value 0 and step size 1.*/
    public JaxoSpinnerRotationModel() {
        this(0);
    }

    /** With given initial value and step size 1.
     * @param value initial value.
     */
    public JaxoSpinnerRotationModel(final int value) {
        super(0, -179, 180, 1);
        setRotationValue(value);
    }

    /** {@link #getValue} as an int.
     * @return int
     */
    public final int getRotationValue() {
        return getNumber().intValue();
    }

    /** {@inheritDoc} */
    @Override
    public void setValue(final Object value) {
        if (!(value instanceof Integer)) {
            throw new IllegalArgumentException();
        }

        setRotationValue(((Integer) value).intValue());
    }

    /** {@link #setValue} with int argument.
     * @param newValue new rotation value.
     */
    public final void setRotationValue(final int newValue) {
        int value = newValue % 360;

        if (value < -180) {
            value += 360;
        } else if (value > 180) {
            value -= 360;
        }

        super.setValue(Integer.valueOf(value));
    }

    /** {@inheritDoc} */
    @Override
    public Object getPreviousValue() {
        Object result = super.getPreviousValue();

        if (result == null) {
            result = super.getMaximum();
        }

        return result;
    }

    /** {@inheritDoc} */
    @Override
    public Object getNextValue() {
        Object result = super.getNextValue();

        if (result == null) {
            result = super.getMinimum();
        }

        return result;
    }

    /** A new JSpinner with an editor better fit to edit
     *  angles than the default number editor.
     * @return JSpinner
     */
    public JSpinner newSpinner() {
        final JSpinner result = new JaxoFixedJSpinner(this);

        result.setEditor(new RotationEditor(result));

        return result;
    }

    private static class RotationEditor extends JSpinner.NumberEditor {
        private static final long serialVersionUID = 7526471155622776147L;

        // TODO: Locale update
        RotationEditor(final JSpinner s) {
            super(s);

            final DefaultFormatterFactory f =
                (DefaultFormatterFactory) getTextField().getFormatterFactory();

            NumberFormatter n = (NumberFormatter) f.getDefaultFormatter();

            n = new NumberFormatter((NumberFormat) n.getFormat());
            n.setValueClass(Integer.class);

            getTextField().setFormatterFactory(new DefaultFormatterFactory(n));

            getTextField().setColumns(4);
        }
    }
}
