package org.csstudio.display.builder.representation.javafx.widgets;

import static org.csstudio.display.builder.representation.ToolkitRepresentation.logger;

import java.util.logging.Level;

import org.csstudio.display.builder.model.DirtyFlag;
import org.csstudio.display.builder.model.WidgetProperty;
import org.csstudio.display.builder.model.util.VTypeUtil;
import org.csstudio.display.builder.model.widgets.CheckBoxWidget;
import org.csstudio.display.builder.representation.javafx.JFXUtil;
import org.diirt.vtype.VType;

import javafx.scene.control.ButtonBase;
import javafx.scene.control.CheckBox;

/** Creates JavaFX item for model widget
 *  @author Amanda Carpenter
 */
public class CheckBoxRepresentation extends JFXBaseRepresentation<CheckBox, CheckBoxWidget>
{
    private final DirtyFlag dirty_size = new DirtyFlag();
    private final DirtyFlag dirty_content = new DirtyFlag();
    private final DirtyFlag dirty_label = new DirtyFlag();

    //TODO: why Integer and int on BoolButton? thread-safety implications?
    protected volatile int bit = 0;
    protected volatile Integer value = 0;
    protected volatile boolean state = false;
    protected volatile String label = "";

    @Override
    protected final CheckBox createJFXNode() throws Exception
    {
        final CheckBox checkbox = new CheckBox(label);
        checkbox.setMinSize(ButtonBase.USE_PREF_SIZE, ButtonBase.USE_PREF_SIZE);
        checkbox.setOnAction(event -> handlePress());
        return checkbox;
    }

    /** @param respond to button press */
    @SuppressWarnings("nls")
    private void handlePress()
    {
        logger.log(Level.FINE, "{0} pressed", model_widget);
        int new_val = (bit < 0) ? (value == 0 ? 1 : 0) : (value ^ (1 << bit));
        toolkit.fireWrite(model_widget, new_val);
    }

    @Override
    protected void registerListeners()
    {
        super.registerListeners();
        model_widget.positionWidth().addUntypedPropertyListener(this::sizeChanged);
        model_widget.positionHeight().addUntypedPropertyListener(this::sizeChanged);
        model_widget.displayAutoSize().addUntypedPropertyListener(this::sizeChanged);

        labelChanged(model_widget.displayLabel(), null, model_widget.displayLabel().getValue());
        model_widget.displayLabel().addPropertyListener(this::labelChanged);
        model_widget.displayFont().addUntypedPropertyListener(this::fontChanged);

        bitChanged(model_widget.behaviorBit(), null, model_widget.behaviorBit().getValue());
        model_widget.behaviorBit().addPropertyListener(this::bitChanged);
        model_widget.runtimeValue().addPropertyListener(this::contentChanged);
   }

    private void sizeChanged(final WidgetProperty<?> property, final Object old_value, final Object new_value)
    {
        dirty_size.mark();
        toolkit.scheduleUpdate(this);
    }

    private void labelChanged(final WidgetProperty<String> property, final String old_value, final String new_value)
    {
        label = new_value != null ? new_value : model_widget.displayLabel().getValue();
        dirty_label.mark();
        toolkit.scheduleUpdate(this);
    }
    
    private void fontChanged(final WidgetProperty<?> property, final Object old_value, final Object new_value)
    {
        dirty_label.mark();
        toolkit.scheduleUpdate(this);
    }

    private void bitChanged(final WidgetProperty<Integer> property, final Integer old_value, final Integer new_value)
    {
        bit = (new_value != null ? new_value : model_widget.behaviorBit().getValue());
        stateChanged(bit, value);
    }

    private void contentChanged(final WidgetProperty<VType> property, final VType old_value, final VType new_value)
    {
        value = VTypeUtil.getValueNumber(new_value).intValue();
        stateChanged(bit, value);
    }

    private void stateChanged(final int new_bit, final int new_value)
    {
        state  = (new_bit < 0) ? new_value != 0 : ((new_value >> new_bit) & 1) == 1;
        dirty_content.mark();
        toolkit.scheduleUpdate(this);
    }

    @Override
    public void updateChanges()
    {
        super.updateChanges();
        if (dirty_size.checkAndClear())
        {
            jfx_node.setPrefWidth(model_widget.positionWidth().getValue());
            jfx_node.setPrefHeight(model_widget.positionHeight().getValue());
            if (model_widget.displayAutoSize().getValue())
                jfx_node.autosize();
        }
        if (dirty_content.checkAndClear())
        {
            jfx_node.setSelected(state);
        }
        if (dirty_label.checkAndClear())
        {
            jfx_node.setText(label);
            jfx_node.setFont(JFXUtil.convert(model_widget.displayFont().getValue()));
        }
    }
}

@@ -1,8 +1,482 @@
+/*******************************************************************************%0D%0A * Copyright (c) 2015-2016 Oak Ridge National Laboratory.%0D%0A * All rights reserved. This program and the accompanying materials%0D%0A * are made available under the terms of the Eclipse Public License v1.0%0D%0A * which accompanies this distribution, and is available at%0D%0A * http://www.eclipse.org/legal/epl-v10.html%0D%0A *******************************************************************************/%0D%0A
 package 
@@ -1163,16 +1163,42 @@
 r%0D%0A */%0D%0A
+@SuppressWarnings(%22nls%22)%0D%0A
 public c
@@ -1472,84 +1472,8 @@
 %0D%0A%0D%0A
-    //TODO: why Integer and int on BoolButton? thread-safety implications?%0D%0A
     
@@ -1528,23 +1528,19 @@
 olatile 
-I
+i
 nt
-eger
  value =
@@ -1996,38 +1996,8 @@
 */%0D%0A
-    @SuppressWarnings(%22nls%22)%0D%0A
     
@@ -3083,23 +3083,21 @@
 r(this::
-content
+value
 Changed)
@@ -3591,20 +3591,16 @@
 %0A    %7D%0D%0A
-    
 %0D%0A    pr
@@ -4064,23 +4064,21 @@
 te void 
-content
+value
 Changed(
@@ -4965,35 +4965,24 @@
 ndClear())%0D%0A
-        %7B%0D%0A
             
@@ -5007,35 +5007,24 @@
 ed(state);%0D%0A
-        %7D%0D%0A
         if (

Remove warnings and TODOs