package fr.umlv.uidemo.slider;

import java.util.*;

import javax.swing.*;
import javax.swing.event.*;

/**
 * @author Remi Forax
 *
 */
public class DateSliderExample2 {

  static class DateModel {
    public DateModel(Date date) {
      this.time=date.getTime();
    }
    
    public long getTime() {
      return time;
    }

    public void setTime(long time) {
      this.time=time;
      fireStateChanged();
    }
    
    public void addChangeListener(ChangeListener l) {
      list.add(l);
    }

    public void removeChangeListener(ChangeListener l) {
      list.remove(l);
    }
    
    protected void fireStateChanged() {
      ChangeEvent event=new ChangeEvent(this);
      for(int i=list.size();--i>=0;)
        ((ChangeListener)list.get(i)).stateChanged(event);
    }
    
    private long time;
    private ArrayList list=new ArrayList();
  }

  static class SpinnerDateModel implements SpinnerModel {
    public SpinnerDateModel(DateModel model,int calendarField) {
      this.model=model;
      this.calendarField=calendarField;
    }
    
    public Object getNextValue() {
      nextCalendar.setTimeInMillis(model.getTime());
      nextCalendar.add(calendarField,1);
      return nextCalendar.getTime();
    }

    public Object getPreviousValue() {
      previousCalendar.setTimeInMillis(model.getTime());
      previousCalendar.add(calendarField,-1);
      return previousCalendar.getTime();
    }
    
    public Object getValue() {
      return new Date(model.getTime());
    }

    public void setValue(Object value) {
      model.setTime(((Date)value).getTime());
    }
    
    public void addChangeListener(ChangeListener l) {
      model.addChangeListener(l);
    }

    public void removeChangeListener(ChangeListener l) {
      model.removeChangeListener(l);
    }
    
    private final DateModel model;
    private final int calendarField;
    
    private final transient Calendar nextCalendar=Calendar.getInstance();
    private final transient Calendar previousCalendar=Calendar.getInstance();
  }
  
  
  
  static class SliderDateModel implements BoundedRangeModel {
    public SliderDateModel(DateModel model,int calendarField) {
      this.model=model;
      this.calendarField=calendarField;
    }
    
    public int getExtent() {
      return 1;
    }

    public int getMaximum() {
      calendar.setTimeInMillis(model.getTime());
      return calendar.getActualMaximum(calendarField);
    }

    public int getMinimum() {
      calendar.setTimeInMillis(model.getTime());
      return calendar.getActualMinimum(calendarField);
    }

    public int getValue() {
      calendar.setTimeInMillis(model.getTime());
      return calendar.get(calendarField);
    }

    public boolean getValueIsAdjusting() {
      return valueIsAdjusting;
    }

    public void setExtent(int newExtent) {
      throw new UnsupportedOperationException();
    }

    public void setMaximum(int newMaximum) {
      throw new UnsupportedOperationException();
    }

    public void setMinimum(int newMinimum) {
      throw new UnsupportedOperationException();
    }

    public void setValue(int newValue) {
      calendar.setTimeInMillis(model.getTime());
      calendar.set(calendarField,newValue);
      model.setTime(calendar.getTimeInMillis());
    }

    public void setRangeProperties(int value, int extent, int min, int max, boolean adjusting) {
      throw new UnsupportedOperationException();
    }

    public void setValueIsAdjusting(boolean valueIsAdjusting) {
      this.valueIsAdjusting=valueIsAdjusting;
    }

    public void addChangeListener(ChangeListener l) {
      model.addChangeListener(l);
    }

    public void removeChangeListener(ChangeListener l) {
      model.addChangeListener(l);
    }
    
    private boolean valueIsAdjusting;
    private int calendarField;
    private final DateModel model;
    private final transient Calendar calendar=Calendar.getInstance();
  }

  private static JPanel createPanel(DateModel model,int calendarField,String label) {
    
    SpinnerDateModel spinnerModel=new SpinnerDateModel(model,calendarField);
    SliderDateModel sliderModel=new SliderDateModel(model,calendarField);
    
    JSpinner spinner=new JSpinner(spinnerModel);
    JSlider slider=new JSlider(sliderModel);
    
    JPanel panel=new JPanel();
    panel.add(new JLabel(label));
    panel.add(slider);
    panel.add(spinner);
    return panel;
  }

  public static void main(String[] args) {
    int[] fields=new int[] {
      Calendar.WEEK_OF_YEAR,Calendar.WEEK_OF_MONTH, Calendar.DAY_OF_MONTH,
      Calendar.DAY_OF_YEAR,Calendar.DAY_OF_WEEK,Calendar.DAY_OF_WEEK_IN_MONTH,
      Calendar.AM_PM,Calendar.HOUR,Calendar.HOUR_OF_DAY,Calendar.MINUTE 
    };
    
    String[] labels=new String[] {
      "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
      "DAY_OF_YEAR",  "DAY_OF_WEEK",   "DAY_OF_WEEK_IN_MONTH",
      "AM_PM",        "HOUR",          "HOUR_OF_DAY,",         "MINUTE" 
    };
    
    DateModel model=new DateModel(new Date());
    
    JPanel panel=new JPanel(null);
    panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
    for(int i=0;i<fields.length;i++) {
      panel.add(createPanel(model,fields[i],labels[i]));
    }
    
    JFrame frame=new JFrame();
    frame.setContentPane(panel);
    frame.pack();
    frame.show();
  }
}
