package nl.tudelft.bw4t.environmentstore.editor.controller;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import nl.tudelft.bw4t.map.BlockColor;
/**
* The ColorSequenceEditor class contains the sequence that should be completed by the agents.
*
*/
public class ColorSequenceEditor extends JComponent {
/** Random generated serial version UID. */
private static final long serialVersionUID = 2112401621332684899L;
/** length of the sequence */
private static final int DEFAULT_LENGTH = 10;
private static final int COLOR_SIZE = 15;
private static final int BORDER = 2;
private int maxLength = DEFAULT_LENGTH;
private List<BlockColor> sequence = new ArrayList<>(DEFAULT_LENGTH);
private Set<ChangeListener> onChange = new HashSet<>();
/**
* Constructor sets up listeners and aperance.
* calls setupListeners method and setupAperance method.
*/
public ColorSequenceEditor() {
setupListeners();
this.setupAperance();
}
/**
* Constructor sets a sequence with a maximum length.
* @param maxLength is the maximum length of the sequence.
*/
public ColorSequenceEditor(int maxLength) {
setupListeners();
this.setMaxLength(maxLength);
}
/**
* Setup all the listeners for the ColorSequenceEditor.
*/
private void setupListeners() {
setFocusable(true);
addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
Character chr = Character.toUpperCase(e.getKeyChar());
if (chr == 'D') {
return;
}
try {
int n = Integer.parseInt(chr.toString());
if (n > 0 && n <= BlockColor.getAvailableColors().size()) {
addColor(BlockColor.getAvailableColors().get(n - 1));
}
} catch (NumberFormatException exc) {
addColor(chr);
}
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE || e.getKeyCode() == KeyEvent.VK_DELETE) {
removeColor();
return;
}
if (e.getKeyCode() == KeyEvent.VK_TAB && e.getSource() instanceof Component) {
((Component) e.getSource()).transferFocus();
}
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
requestFocus();
}
});
}
/**
* Set the dimensions and border of the ColorSequenceEditor.
*/
private void setupAperance() {
this.setBackground(Color.WHITE);
Dimension d = new Dimension(BORDER * 2 + COLOR_SIZE * maxLength, BORDER * 2 + COLOR_SIZE);
setMinimumSize(d);
setPreferredSize(d);
this.setBorder(BorderFactory.createLoweredBevelBorder());
}
/**
*
* @param cl
*/
public void addChangeListener(ChangeListener cl) {
onChange.add(cl);
}
/**
*
* @param cl
*/
public void removeChangeListener(ChangeListener cl) {
onChange.remove(cl);
}
/**
* Revalidate and Repaint on change.
*/
private void notifyValueChange() {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener l : onChange) {
l.stateChanged(evt);
}
this.revalidate();
this.repaint();
}
public int getMaxLength() {
return maxLength;
}
public boolean isFull() {
return getSequenceSize() >= getMaxLength();
}
/**
* changes the current length to maxLength
* @param maxLength the length of the sequence and updates the sequence
*/
public void setMaxLength(int maxLength) {
this.maxLength = maxLength;
this.setupAperance();
}
public List<BlockColor> getSequence() {
return sequence;
}
public int getSequenceSize() {
return getSequence().size();
}
/**
* If a sequence given as parameter, set the sequence to this given sequence.
* Else set it to clear.
* @param sequence is the sequence the current sequence is set to.
*/
public void setSequence(List<BlockColor> sequence) {
if (sequence == null) {
this.sequence.clear();
} else {
this.sequence = new ArrayList<BlockColor>(sequence);
}
notifyValueChange();
}
/**
* add the color to the sequence list
* @param chr the color to be added as character
*/
public void addColor(Character chr) {
BlockColor color;
try {
color = BlockColor.toAvailableColor(chr);
} catch (IllegalArgumentException iae) {
return;
}
addColor(color);
}
/**
* add the color to the sequence list
* @param c the BlockColor to be added
*/
public void addColor(BlockColor c) {
if (isFull() || c == null) {
return;
}
sequence.add(c);
notifyValueChange();
}
public void removeColor() {
if (getSequenceSize() <= 0) {
return;
}
sequence.remove(sequence.size() - 1);
notifyValueChange();
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(getBackground());
g.clearRect(BORDER, BORDER, getWidth() - BORDER * 2, getHeight() - BORDER * 2);
Dimension s = this.getSize();
int width = Math.max(1, (s.width - BORDER * 2) / maxLength);
int height = s.height - BORDER * 2;
int startX = BORDER;
for (BlockColor c : getSequence()) {
g.setColor(c.getColor());
g.fillRect(startX, BORDER, width, height);
g.setColor(Color.BLACK);
g.drawRect(startX, BORDER, width - 1, height - 1);
startX += width;
}
}
}