import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Ellipse2D;

import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSliderUI;

public class CustomSliderUI extends BasicSliderUI {
	private final BasicStroke stroke = new BasicStroke(2f);
	private JSlider slider;

	public CustomSliderUI(JSlider b) {
	    super(b);
	    this.slider = b;
	}

	public static ComponentUI createUI(JComponent c) {
	    return new CustomSliderUI((JSlider)c);
	}


	@Override
	protected void calculateThumbSize() {
	    super.calculateThumbSize();
	    thumbRect.setSize(thumbRect.width, thumbRect.height);
	}

	  /** Creates a listener to handle track events in the specified slider.*/
	@Override
	protected TrackListener createTrackListener(JSlider slider) {
	    return new TrackListener();
	}


	@Override
	protected void calculateThumbLocation() {
	    // Call superclass method for lower thumb location.
	    super.calculateThumbLocation();

	    // Adjust upper value to snap to ticks if necessary.
	    if (slider.getSnapToTicks()) {
	        int upperValue = slider.getValue() + slider.getExtent();
	        int snappedValue = upperValue; 
	        int majorTickSpacing = slider.getMajorTickSpacing();
	        int minorTickSpacing = slider.getMinorTickSpacing();
	        int tickSpacing = 0;

	        if (minorTickSpacing > 0) {
	            tickSpacing = minorTickSpacing;
	        } else if (majorTickSpacing > 0) {
	            tickSpacing = majorTickSpacing;
	        }

	        if (tickSpacing != 0) {
	            // If it's not on a tick, change the value
	            if ((upperValue - slider.getMinimum()) % tickSpacing != 0) {
	                float temp = (float)(upperValue - slider.getMinimum()) / (float)tickSpacing;
	                int whichTick = Math.round(temp);
	                snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
	            }

	            if (snappedValue != upperValue) { 
	                slider.setExtent(snappedValue - slider.getValue());
	            }
	        }
	    }

	    // Calculate upper thumb location.  The thumb is centered over its 
	    // value on the track.
	    if (slider.getOrientation() == JSlider.HORIZONTAL) {
	        int upperPosition = xPositionForValue(slider.getValue() + slider.getExtent());
	        thumbRect.x = upperPosition - (thumbRect.width / 2);
	        thumbRect.y = trackRect.y;

	    } else {
	        int upperPosition = yPositionForValue(slider.getValue() + slider.getExtent());
	        thumbRect.x = trackRect.x;
	        thumbRect.y = upperPosition - (thumbRect.height / 2);
	    }
	    slider.repaint();
	}   

	/** Returns the size of a thumb.
	 * Parent method not use size from LaF
	 * @return size of trumb */
	@Override
	protected Dimension getThumbSize() {
	    return new Dimension(5, 10);
	}


	private Shape createThumbShape(int width, int height) {
	    Ellipse2D shape = new Ellipse2D.Double(0, 0, width, height);
	    return shape;
	}

	@Override
	public void paintTrack(Graphics g) {
	    Graphics2D g2d = (Graphics2D) g;
	    Stroke old = g2d.getStroke();
	    g2d.setStroke(stroke);
	    g2d.setPaint(slider.isEnabled() ? Color.LIGHT_GRAY : Color.WHITE);
	    Color oldColor = slider.isEnabled() ? Color.LIGHT_GRAY : Color.WHITE;
	    Rectangle trackBounds = trackRect;
	    if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
	        g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2, 
	                trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
	        int lowerX = thumbRect.width / 2;
	        int upperX = thumbRect.x + (thumbRect.width / 2);
	        int cy = (trackBounds.height / 2) - 2;
	        g2d.translate(trackBounds.x, trackBounds.y + cy);
	        g2d.setColor(slider.isEnabled() ? Color.BLACK : Color.LIGHT_GRAY);
	        g2d.drawLine(lowerX - trackBounds.x, 2, upperX - trackBounds.x, 2);
	        g2d.translate(-trackBounds.x, -(trackBounds.y + cy));
	        g2d.setColor(oldColor);
	    } 
	    g2d.setStroke(old);
	}



	/** Overrides superclass method to do nothing.  Thumb painting is handled
	 * within the <code>paint()</code> method.*/
	@Override
	public void paintThumb(Graphics g) {
	    Rectangle knobBounds = thumbRect;
	    int w = knobBounds.width;
	    int h = knobBounds.height;      
	    Graphics2D g2d = (Graphics2D) g.create();
	    Shape thumbShape = createThumbShape(w - 1, h - 1);
	    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
	        RenderingHints.VALUE_ANTIALIAS_ON);
	    g2d.translate(knobBounds.x, knobBounds.y);
	    g2d.setColor(slider.isEnabled() ? Color.LIGHT_GRAY : Color.WHITE);
	    g2d.fill(thumbShape);

	    g2d.setColor(slider.isEnabled() ? Color.BLACK : Color.LIGHT_GRAY);
	    g2d.draw(thumbShape);
	    g2d.dispose();
	}
}