import javax.swing.JPanel;
import javax.swing.text.PlainDocument;
import javax.swing.text.Document;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.FocusListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;

/**
Swing GUI component which handles input of positive integers, with nice
up/down buttons beside it.
@author Daniel Sykes
**/

/*
And you thought JLists were bad.
This is a veritable bucket of objective scum.
*/
class JIntField extends JPanel implements ActionListener
{
  private class JIntTextField extends JTextField
  {
    //arse about...
    private class IntDoc extends PlainDocument
    {
      public void insertString(int o, String s, AttributeSet a) throws BadLocationException
      {
        char in[] = s.toCharArray();
        char out[] = new char[in.length];
        int j = 0;
        
        for (int i = 0; i < out.length; i++)
          if (Character.isDigit(in[i]))
            out[j++] = in[i];
          
        super.insertString(o, new String(out, 0, j), a);
      }
    }
    
    public JIntTextField(int value)
    {
      super(""+Math.abs(value));
    }
    
    protected Document createDefaultModel()
    {
      return new IntDoc();
    }
    
    public void setValue(int v)
    {
      setText(""+Math.abs(v));
    }
    
    public int getValue()
    {
      String t = getText();
      if (!t.equals(""))
        return Integer.parseInt(t);
      return 0;
    }
  }
  
  private class JScrollButton extends JButton
  {
    private boolean up = true;
    
    public JScrollButton(boolean pointsUp)
    {
      up = pointsUp;
    }
    
    protected void paintComponent(Graphics g)
    {
      super.paintComponent(g);
      int midX = getWidth() / 2;
      int midY = getHeight() / 2;
      int qY = midY / 2;
      int x[] = {midX-qY, midX, midX+qY};
      int yUp[] = {midY+qY, midY-qY-1, midY+qY};
      int yDown[] = {midY-qY, midY+qY, midY-qY};
      if (up)
      {
        if (filled)
          g.fillPolygon(x, yUp, 3);
        else
          g.drawPolygon(x, yUp, 3);
      }
      else
      {
        if (filled)
          g.fillPolygon(x, yDown, 3);
        else
          g.drawPolygon(x, yDown, 3);
      }
    }
  }
  
  private JIntTextField text;
  private JButton up;
  private JButton down;
  
  private KeyAdapter key = new KeyAdapter()
    {
      public void keyReleased(KeyEvent e)
      {
        if (e.getKeyCode() == KeyEvent.VK_UP)
          increment();
        if (e.getKeyCode() == KeyEvent.VK_PAGE_UP)
          largeIncrement();
        if (e.getKeyCode() == KeyEvent.VK_DOWN)
          decrement();
        if (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN)
          largeDecrement();
        checkSize();
      }
    };
  
  private int max = 100;
  private int min = 0;
  private int increment = 1;
  private boolean filled = true;
  
  public JIntField()
  {
    this(0);
  }
  
  public JIntField(int initialValue)
  {
    setLayout(null);
    addKeyListener(key);
    text = new JIntTextField(initialValue);
    up = new JScrollButton(true);
    down = new JScrollButton(false);
    up.addActionListener(this);
    up.addKeyListener(key);
    up.setFocusPainted(false);
    down.addActionListener(this);
    down.addKeyListener(key);
    down.setFocusPainted(false);
    text.addKeyListener(key);
    text.addFocusListener(new FocusAdapter() 
      {
        public void focusLost(FocusEvent e)
        {
          checkSize();
        }
        
        public void focusGained(FocusEvent e)
        {
          text.selectAll();
        }
      });
    add(text);
    add(up);
    add(down);
    text.setVisible(true);
    up.setVisible(true);
    down.setVisible(true);
    setVisible(true);
  }
  
  public void setToolTipText(String t)
  {
    super.setToolTipText(t);
    text.setToolTipText(t);
    up.setToolTipText(t);
    down.setToolTipText(t);
  }
  
    
  public void setFont(Font f)
  {
    super.setFont(f);
    if (text != null)
      text.setFont(f);
  }
  
  public Font getFont()
  {
    if (text != null)
      return text.getFont();
    return super.getFont();
  }
 
  public void setLocation(int x, int y)
  {
    setBounds(x, y, getWidth(), getHeight());
  }
  
  public void setBounds(int x, int y, int width, int height)
  {
    int mid = height / 2;
    super.setBounds(x, y, width, height);
    text.setBounds(0, 0, width - mid, height);
    up.setBounds(text.getWidth(), 0, mid, mid);
    down.setBounds(text.getWidth(), mid, mid, mid);
  }
  
  public void setSize(int width, int height)
  {
    setBounds(getX(), getY(), width, height);
  }
  
  public void actionPerformed(ActionEvent e)
  {
    if (e.getSource() == up)
      increment();
    else
      decrement();
    text.requestFocus();
  }
  
  private void increment()
  {
    int val = text.getValue();
    if (val <= max-increment)
      text.setValue(val+increment);
  }
  
  private void largeIncrement()
  {
    int val = text.getValue();
    if (val <= max-(5*increment))
      text.setValue(val+(5*increment));
  }
  
  private void decrement()
  {
    int val = text.getValue();
    if (val >= min+increment)
      text.setValue(val-increment);
  }
  
  private void largeDecrement()
  {
    int val = text.getValue();
    if (val >= min+(5*increment))
      text.setValue(val-(5*increment));
  }
  
  public void setMax(int maximum)
  {
    max = maximum;
  }
  
  public void setMin(int minimum)
  {
    if (minimum >= 0)
      min = minimum;
    else
      min = 0;
  }
  
  public int getMax()
  {
    return max;
  }
  
  public int getMin()
  {
    return min;
  }
  
  public void setIncrement(int i)
  {
    increment = i;
  }
  
  public int getIncrement()
  {
    return increment;
  }
  
  public int getValue()
  {
    return text.getValue();
  }
  
  public void setValue(int value)
  {
    text.setValue(value);
  }
  
  public void setArrowsFilled(boolean filled)
  {
    this.filled = filled;
  }
  
  private void checkSize()
  {
    int val = text.getValue();
    if (val > max)
      text.setValue(max);
    if (val < min)
      text.setValue(min);
  }
}