package com.airlock.iam.plugin.configeditor.field;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.elog.api.LogTypes;
import com.airlock.iam.plugin.api.exception.InitializeException;
import com.airlock.iam.plugin.configeditor.ConfigEditorApplication;
import com.airlock.iam.plugin.configeditor.ui.dialog.NewPluginDialog;
import com.airlock.iam.plugin.configeditor.util.GuiResources;
import com.airlock.iam.plugin.framework.application.configuration.MutablePluginConfiguration;
import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.server.Sizeable.Unit;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Component;
import com.vaadin.ui.DragAndDropWrapper;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Image;
import com.vaadin.ui.UI;
import com.vaadin.v7.data.Property;
import com.vaadin.v7.data.Property.ReadOnlyException;
import com.vaadin.v7.data.Property.ValueChangeEvent;
import com.vaadin.v7.data.util.converter.Converter.ConversionException;
import com.vaadin.v7.ui.CustomField;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

public class ParentConfigurationField extends CustomField<MutablePluginConfiguration> implements ClickListener {
   private static final ELogger LOG = ELoggerFactory.getLogger(ParentConfigurationField.class);
   private static final int FIELD_WIDTH = 300;
   private final ConfigEditorApplication app;
   private final Image followIcon;
   private final Image newIcon;
   private final PluginComboBox innerField;
   private final MutablePluginConfiguration child;
   private final DragAndDropWrapper dndWrapper;
   private boolean handleNewValues = true;

   @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", justification = "See ALIAM-15315")
   public ParentConfigurationField(MutablePluginConfiguration parentPluginConfig, ConfigEditorApplication app) {
      this.child = parentPluginConfig;
      this.app = app;
      this.innerField = new PluginComboBox();
      this.innerField.setWidth(295.0F, Unit.PIXELS);
      this.innerField.setImmediate(true);
      this.innerField.setBuffered(false);
      this.innerField.setInvalidAllowed(false);
      this.innerField.setNewItemsAllowed(false);
      this.innerField.setNullSelectionAllowed(true);
      this.innerField.addValueChangeListener(this);
      this.dndWrapper = new TransparentDnDWrapper(this.innerField);
      this.dndWrapper.setWidth(300.0F, Unit.PIXELS);
      this.newIcon = new Image(null, GuiResources.ICON_NEW);
      this.newIcon.setDescription("Create a new parent.");
      this.newIcon.addStyleName("with-hand");
      this.newIcon.addClickListener(this);
      this.newIcon.addStyleName("newPluginIcon");
      this.newIcon.setWidth(16.0F, Unit.PIXELS);
      this.newIcon.setHeight(16.0F, Unit.PIXELS);
      this.followIcon = new Image(null, GuiResources.ICON_FOLLOW);
      this.followIcon.setVisible(false);
      this.followIcon.setDescription("Navigate to the parent.");
      this.followIcon.addStyleName("with-hand");
      this.followIcon.addClickListener(this);
      this.followIcon.addStyleName("navigateToPluginIcon");
      this.followIcon.setWidth(16.0F, Unit.PIXELS);
      this.followIcon.setHeight(16.0F, Unit.PIXELS);
   }

   protected Component initContent() {
      HorizontalLayout hl = new HorizontalLayout();
      hl.addComponent(this.dndWrapper);
      hl.addComponent(this.newIcon);
      hl.setComponentAlignment(this.newIcon, Alignment.MIDDLE_LEFT);
      hl.addComponent(this.followIcon);
      hl.setComponentAlignment(this.followIcon, Alignment.MIDDLE_LEFT);
      return hl;
   }

   public PluginComboBox getInnerField() {
      return this.innerField;
   }

   public Class<MutablePluginConfiguration> getType() {
      return MutablePluginConfiguration.class;
   }

   public void setPropertyDataSource(Property newDataSource) {
      super.setPropertyDataSource(newDataSource);
      this.dndWrapper.setDropHandler(new PluginDropHandler(this.app, this.innerField));
   }

   public void click(ClickEvent event) {
      if (event.getSource() == this.newIcon) {
         this.createNewParent();
      } else if (event.getSource() == this.followIcon) {
         this.app.selectConfiguration((MutablePluginConfiguration)this.getPropertyDataSource().getValue());
      }
   }

   private void createNewParent() {
      NewPluginDialog dialog;
      try {
         dialog = new NewPluginDialog(this.child, null, this.child.getPluginClass());
         dialog.makeIdentifierMandatory();
      } catch (InitializeException e) {
         LOG.error(LogTypes.CONFIGURATION_ERROR, "Initialize Exception: " + e.getMessage(), e);
         return;
      }

      UI.getCurrent().addWindow(dialog);
      dialog.addCloseListener(e -> {
         MutablePluginConfiguration pc = ((NewPluginDialog)e.getSource()).getPluginConfiguration();
         if (pc != null) {
            ConfigEditorApplication application = (ConfigEditorApplication)UI.getCurrent();
            application.getConfigurationDictionary().addPluginConfiguration(pc);
            this.handleNewValues = false;
            this.getPropertyDataSource().setValue(pc);
            application.updateValidationState();
            application.updateFormFields();
            if (dialog.isEditAfterCreatingPlugin()) {
               application.selectConfiguration(pc);
            }
         }
      });
   }

   public void valueChange(ValueChangeEvent event) {
      if (this.handleNewValues) {
         MutablePluginConfiguration newValue = this.getValue();
         if (newValue != this.getPropertyDataSource().getValue()) {
            this.getPropertyDataSource().setValue(newValue);
            this.setInternalValue(newValue);
            this.fireValueChange(false);
            this.updateUI(newValue);
         }
      }
   }

   private void updateUI(MutablePluginConfiguration newValue) {
      this.updateIcons(newValue);
      if (this.app != null) {
         this.app.updateValidationState();
         this.app.updateFormFields();
      }
   }

   private void updateIcons(MutablePluginConfiguration newValue) {
      if (this.followIcon != null) {
         this.followIcon.setVisible(newValue != null);
      }
   }

   protected void setInternalValue(MutablePluginConfiguration pc) {
      boolean backupReadonly = this.getInnerField().isReadOnly();
      this.getInnerField().setReadOnly(false);
      this.getInnerField().setValue(pc);
      this.getInnerField().setReadOnly(backupReadonly);
      this.updateIcons(pc);
   }

   public MutablePluginConfiguration getValue() {
      Object innerValue = this.getInnerField().getValue();
      return !(innerValue instanceof MutablePluginConfiguration) ? null : (MutablePluginConfiguration)innerValue;
   }

   public void setValue(MutablePluginConfiguration newFieldValue) throws ReadOnlyException, ConversionException {
      this.innerField.setValue(newFieldValue);
      super.setValue(newFieldValue);
   }
}
