package de.gurkenlabs.utiliti.swing.panels;

import java.awt.LayoutManager;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import de.gurkenlabs.litiengine.Game;
import de.gurkenlabs.litiengine.entities.LightSource;
import de.gurkenlabs.litiengine.environment.tilemap.IMapObject;
import de.gurkenlabs.litiengine.environment.tilemap.MapObjectProperty;
import de.gurkenlabs.utiliti.swing.ColorComponent;
import de.gurkenlabs.utiliti.swing.Icons;

@SuppressWarnings("serial")
public class LightSourcePanel extends PropertyPanel {
  private final JComboBox<String> comboBoxLightShape;
  private JSpinner spinnerIntensity;
  private JCheckBox checkBoxIsActive;
  private JSpinner offsetX;
  private JSpinner offsetY;
  private final ColorComponent colorControl;

  public LightSourcePanel() {
    super("panel_lightSource", Icons.LIGHT);

    this.colorControl = new ColorComponent();

    this.comboBoxLightShape = new JComboBox<>();
    this.comboBoxLightShape.setModel(new DefaultComboBoxModel<>(new String[] { "ellipse", "rectangle" }));

    this.spinnerIntensity = new JSpinner(new SpinnerNumberModel(0, 0, 255, 5));
    this.checkBoxIsActive = new JCheckBox("is active");
    this.checkBoxIsActive.setSelected(true);

    this.offsetX = new JSpinner(new SpinnerNumberModel(0.0, -0.5, 0.5, 0.1));
    this.offsetY = new JSpinner(new SpinnerNumberModel(0.0, -0.5, 0.5, 0.1));

    setLayout(this.createLayout());
    this.setupChangedListeners();
  }

  @Override
  protected void clearControls() {
    this.spinnerIntensity.setValue(LightSource.DEFAULT_INTENSITY);
    this.colorControl.clear();
    this.checkBoxIsActive.setSelected(true);
  }

  @Override
  protected void setControlValues(IMapObject mapObject) {
    final String color = mapObject.getStringValue(MapObjectProperty.LIGHT_COLOR);
    final String shape = mapObject.getStringValue(MapObjectProperty.LIGHT_SHAPE);
    final String active = mapObject.getStringValue(MapObjectProperty.LIGHT_ACTIVE);

    boolean isActive = active == null || active.isEmpty() || Boolean.parseBoolean(active);
    this.spinnerIntensity.setValue(mapObject.getIntValue(MapObjectProperty.LIGHT_INTENSITY, LightSource.DEFAULT_INTENSITY));
    this.colorControl.setHexColor(color);
    this.comboBoxLightShape.setSelectedItem(shape);
    this.checkBoxIsActive.setSelected(isActive);
    this.offsetX.setValue((int) Math.max(Math.min(100 * mapObject.getDoubleValue(MapObjectProperty.LIGHT_FOCUSOFFSETX), 100), -100));
    this.offsetY.setValue((int) Math.max(Math.min(100 * mapObject.getDoubleValue(MapObjectProperty.LIGHT_FOCUSOFFSETY), 100), -100));
  }

  private void setupChangedListeners() {
    this.colorControl.addActionListener(new MapObjectPropertyActionListener(m -> {
      if (getDataSource() != null) {
        getDataSource().setValue(MapObjectProperty.LIGHT_COLOR, this.colorControl.getHexColor());
        getDataSource().setValue(MapObjectProperty.LIGHT_INTENSITY, (int) this.spinnerIntensity.getValue());
        Game.world().environment().updateLighting(getDataSource().getBoundingBox());
      }
    }));
    this.setup(this.spinnerIntensity, MapObjectProperty.LIGHT_INTENSITY);
    this.spinnerIntensity.addChangeListener(m -> Game.world().environment().updateLighting(getDataSource().getBoundingBox()));

    this.setup(this.comboBoxLightShape, MapObjectProperty.LIGHT_SHAPE);
    this.comboBoxLightShape.addActionListener(m -> Game.world().environment().updateLighting(getDataSource().getBoundingBox()));

    this.setup(this.checkBoxIsActive, MapObjectProperty.LIGHT_ACTIVE);
    this.checkBoxIsActive.addActionListener(m -> Game.world().environment().updateLighting(getDataSource().getBoundingBox()));

    this.setup(this.offsetX, MapObjectProperty.LIGHT_FOCUSOFFSETX);
    this.offsetX.addChangeListener(m -> Game.world().environment().updateLighting(getDataSource().getBoundingBox()));

    this.setup(this.offsetY, MapObjectProperty.LIGHT_FOCUSOFFSETY);
    this.offsetY.addChangeListener(m -> Game.world().environment().updateLighting(getDataSource().getBoundingBox()));
  }

  private LayoutManager createLayout() {

    LayoutItem[] layoutItems = new LayoutItem[] { new LayoutItem("panel_shape", this.comboBoxLightShape), new LayoutItem("panel_color", this.colorControl, this.colorControl.getPreferredSize().height), new LayoutItem("panel_intensity", this.spinnerIntensity), new LayoutItem("offsetX", this.offsetX),
        new LayoutItem("offsetY", this.offsetY), };

    return this.createLayout(layoutItems, this.checkBoxIsActive);
  }
}

@@ -1602,32 +1602,150 @@
 steners();%0D%0A  %7D%0D
+%0A  @Override%0D%0A  public void bind(IMapObject mapObject) %7B%0D%0A    super.bind(mapObject);%0D%0A    this.updateLighting();%0D%0A  %7D%0D
 %0A%0D%0A  @Override%0D%0A
@@ -3505,84 +3505,30 @@
  -%3E 
-Game.world().environment().updateLighting(getDataSource().getBoundingBox
+this.updateLighting
 ())
-)
 ;%0D%0A%0D
@@ -3656,82 +3656,28 @@
  -%3E 
-Game.world().environment().updateLighting(getDataSource().getBoundingBox()
+this.updateLighting(
 ));%0D
@@ -3804,82 +3804,28 @@
  -%3E 
-Game.world().environment().updateLighting(getDataSource().getBoundingBox()
+this.updateLighting(
 ));%0D
@@ -3940,82 +3940,28 @@
  -%3E 
-Game.world().environment().updateLighting(getDataSource().getBoundingBox()
+this.updateLighting(
 ));%0D
@@ -4071,16 +4071,247 @@
 ner(m -%3E
+ this.updateLighting());%0D%0A  %7D%0D%0A%0D%0A  private void updateLighting() %7B%0D%0A    if (this.isFocussing) %7B%0D%0A      return;%0D%0A    %7D%0D%0A%0D%0A    final IMapObject datasource = getDataSource();%0D%0A    if (datasource == null) %7B%0D%0A      return;%0D%0A    %7D%0D%0A%0D%0A   
  Game.wo
@@ -4378,17 +4378,16 @@
 ngBox())
-)
 ;%0D%0A  %7D%0D%0A

Update lighting only one when setting control values