/**
 *  Copyright © 2020-2025, Luis Andrés Lange <https://javacomm.net>
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *  ----------------------------------------------------------------------------
 *
 *  Exhibit B - "Incompatible With Secondary Licenses" Notice
 *
 *  This Source Code Form is "Incompatible With Secondary Licenses",
 *  as defined by the Mozilla Public License, v. 2.0.
 *
 *  In short:
 *  - This file may be used, modified, and distributed under MPL 2.0 only.
 *  - It may NOT be relicensed under GPL, LGPL, AGPL, or any other Secondary License.
 *
 *  Rationale:
 *  - Ensures that the code remains MPL-2.0.
 *  - Avoids legal conflicts with GPL-licensed libraries (e.g., VideoLAN).
 *  - Maximizes usability for commercial and security-critical applications.
 *
 */
package net.javacomm.client.filetransfer;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.text.DecimalFormat;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import javax.swing.plaf.synth.SynthFormattedTextFieldUI;
import javax.swing.text.JTextComponent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nexuswob.gui.swing.NimbusCellRenderer;
import net.javacomm.client.gui.MultilingualServiceButton;
import net.javacomm.client.resource.Resource;
import net.javacomm.multilingual.MultilingualLabel;
import net.javacomm.multilingual.MultilingualString;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;
import net.javacomm.share.Constants;
import net.javacomm.transfer.Helado;
import net.javacomm.transfer.Starttype;
import net.javacomm.window.manager.Control;
import net.javacomm.window.manager.Frames;
import net.javacomm.window.manager.WindowManagerInternalFrame;



public class JServerKonfigurierenFrame extends WindowManagerInternalFrame {

  private final static Logger log = LogManager.getLogger(JServerKonfigurierenFrame.class);
  private static final long serialVersionUID = -6496491609000566340L;
  public final static int WIDTH = 580;
  public final static int HEIGHT = 270;
  private JPanel mainpane = new JPanel(true);
  private GridBagLayout gridbag = new GridBagLayout();
  private GridBagConstraints con = new GridBagConstraints();
  private MultilingualLabel status = new MultilingualLabel(KEY.LABEL_ANGEHALTEN);

  private MultilingualString vonHandAus = new MultilingualString(KEY.STRING_VON_HAND_AUS_STARTEN);
  private MultilingualString automatisch = new MultilingualString(
      KEY.STRING_AUTOMATISCH_NACH_JEDEM_PROGRAMMSTART
  );
  private MultilingualString gestartet = new MultilingualString(KEY.LABEL_GESTARTET);
  private MultilingualLabel label = new MultilingualLabel(KEY.LABEL_SERVICE_STATUS);
  private MultilingualLabel labelPort = new MultilingualLabel(KEY.LABEL_AUF_PORT);
  private JSpinner spinner = new JSpinner();
  private SpinnerNumberModel model = new SpinnerNumberModel();
  private MultilingualServiceButton serviceButton = new MultilingualServiceButton(
      KEY.BUTTON_START_SERVICE, KEY.BUTTON_STOP_SERVICE
  );
  private MultilingualServiceButton knopfleiste = new MultilingualServiceButton(
      KEY.BUTTON_SPEICHERN_SCHLIESSEN, KEY.BUTTON_SCHLIESSEN
  );

  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private ImageIcon startImage;
  private ImageIcon stopImage;
  private JSpinner.NumberEditor editorSpinner;
  private MultilingualLabel labelStarttype = new MultilingualLabel(KEY.LABEL_STARTMODUS);
  private JComboBox<MultilingualString> multilingualTypebox = new JComboBox<>(
      new MultilingualString[] {vonHandAus, automatisch}
  );
  private int port = 29467;
  private DecimalFormat format;
  private boolean isGestartet = false;
  private InternalFrameAdapter internalFrameAdapter;

  public JServerKonfigurierenFrame() {
    Class<? extends JServerKonfigurierenFrame> resource = getClass();
    stopImage = new ImageIcon(resource.getResource(Resource.SHUTDOWN));
    startImage = new ImageIcon(resource.getResource(Resource.SERVERSTART));

    spinner.setModel(model);
    model.setMinimum(Constants.MIN_PORT_RANGE);
    model.setStepSize(1);
    model.setMaximum(Constants.MAX_PORT_RANGE);

    editorSpinner = (JSpinner.NumberEditor) spinner.getEditor();
    format = editorSpinner.getFormat();
    format.setGroupingUsed(false);
    // Bugfix setValue(port) muss nach der Formatierung aufgerufen werden, damit
    // keine Gruppierung für den Startwert wie 29.467 stattfindet.
    model.setValue(port);

    internalFrameAdapter = new InternalFrameAdapter() {
      @Override
      public void internalFrameClosing(InternalFrameEvent event) {
        changes.firePropertyChange(JServerKonfigurierenFrame.class.getName(), Control.NULL, Control.CLOSE);
      }
    };

    addInternalFrameListener(internalFrameAdapter);

  }



  @Override
  public void activated() {
    try {
      setSelected(true);
    }
    catch (PropertyVetoException e) {}
  }



  public void addPeer2PeerListener(PropertyChangeListener l) {
    changes.addPropertyChangeListener(l);
  }



  @Override
  public String getFrameTitleId() {
    return getTitle();
  }



  /**
   * Auf diesem Port horcht der Server.
   * 
   * @return der FTS-Port von 29467-29478
   */
  public int getPort() {
    Object value = model.getValue();
    if (value instanceof Integer) {
      return (Integer) value;
    }
    else {
      return port;
    }
  }



  /**
   * Wird der Server manuell oder automatisch gestartet?
   * 
   * @return manuell oder automatisch
   */
  public String getStarttype() {
    return multilingualTypebox.getSelectedItem().toString();
  }



  @Override
  public Frames getType() {
    return Frames.CONFIGURE;
  }



  public void init() {
    setContentPane(mainpane);
    mainpane.setLayout(gridbag);

    con.gridwidth = 1;
    con.insets = new Insets(0, 0, 12, 0);
    con.anchor = GridBagConstraints.EAST;
    gridbag.setConstraints(labelStarttype, con);
    add(labelStarttype);

    con.gridwidth = 3;
    con.insets = new Insets(0, 12, 12, 0);
    con.anchor = GridBagConstraints.WEST;
    con.fill = GridBagConstraints.HORIZONTAL;
    gridbag.setConstraints(multilingualTypebox, con);
    add(multilingualTypebox);
    multilingualTypebox.setRenderer(new NimbusCellRenderer<>());

    con.anchor = GridBagConstraints.EAST;
    con.insets = new Insets(0, 0, 0, 0);
    con.gridwidth = 1;
    con.gridy = 1;
    con.fill = GridBagConstraints.NONE;
    gridbag.setConstraints(label, con);
    add(label);

    // status = new JLabel(new ImageIcon(resource.getResource(Resource.SHUTDOWN)));
    con.anchor = GridBagConstraints.WEST;
    status.setPreferredSize(new Dimension(151, 32));
    status.setMinimumSize(new Dimension(151, 32));
    status.setMaximumSize(new Dimension(151, 32));

    con.insets = new Insets(0, 12, 0, 0);
    con.fill = GridBagConstraints.BOTH;
    gridbag.setConstraints(status, con);
    add(status);

    con.fill = GridBagConstraints.NONE;
    con.insets = new Insets(0, 18, 0, 0);
    gridbag.setConstraints(labelPort, con);
    add(labelPort);

    con.insets = new Insets(0, 3, 0, 0);
    con.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints(spinner, con);
    add(spinner);

    con.anchor = GridBagConstraints.CENTER;
    con.gridy = 2;
    con.insets = new Insets(24, 12, 0, 0);
    con.gridwidth = 3;
    gridbag.setConstraints(serviceButton, con);
    add(serviceButton);
    serviceButton.setEnabledButton1();
    serviceButton.addButtonListener(event -> {
      Control value = (Control) event.getNewValue();
      switch(value) {
        case BUTTON_1:
          changes.firePropertyChange(JServerKonfigurierenFrame.class.getName(), Control.NULL, Control.START);
          break;
        case BUTTON_2:
          changes.firePropertyChange(JServerKonfigurierenFrame.class.getName(), Control.NULL, Control.STOP);
          break;
        default:
          break;
      }

    });

    con.gridy = 3;
    con.gridwidth = 4;
    con.fill = GridBagConstraints.HORIZONTAL;
    JSeparator separator = new JSeparator();
    gridbag.setConstraints(separator, con);
    add(separator);

    con.gridy = 4;
    con.gridx = 1;
    con.gridwidth = 3;
    con.fill = GridBagConstraints.NONE;
    con.anchor = GridBagConstraints.EAST;
    gridbag.setConstraints(knopfleiste, con);
    add(knopfleiste);
    knopfleiste.addButtonListener(event -> {
      Control value = (Control) event.getNewValue();
      switch(value) {
        case BUTTON_1:
          try {
            JServerKonfigurierenFrame.this.setClosed(true);
            changes.firePropertyChange(JServerKonfigurierenFrame.class.getName(), Control.NULL, Control.SAVE);
          }
          catch (PropertyVetoException e1) {
            log.error(e1.getMessage(), e1);
          }
          break;
        case BUTTON_2:
          try {
            JServerKonfigurierenFrame.this.setClosed(true);
            changes
                .firePropertyChange(JServerKonfigurierenFrame.class.getName(), Control.NULL, Control.CLOSE);
          }
          catch (PropertyVetoException e) {
            log.warn(e.getMessage(), e.getCause());
          }
          break;
        default:
          break;
      }
    });
    knopfleiste.setEnabledButton1();

  }



  public void removeAllListener() {
    serviceButton.removeAllListener();
    knopfleiste.removeAllListener();
    removeInternalFrameListener(internalFrameAdapter);
  }



  public void removePeer2PeerListener(PropertyChangeListener l) {
    changes.removePropertyChangeListener(l);
  }



  @Override
  public void setBackgroundGradient(Color top, Color bottom) {
    windowManager.setBackgroundGradient(top, bottom);
  }



  /**
   * Die Hintergrundfarbe für den Spinner.
   * 
   * @param sorte
   *              die Hintergrundfarbe
   */
  public void setEissorte(Helado helado) {
    Color color;
    switch(helado) {
      case Arando:
        color = Resource.JQUERY_HELLBLAU;
        break;
      case Fresa:
        color = Resource.JQUERY_ERDBEERE;
        break;
      case Limón:
        color = Resource.JQUERY_LEMON;
        break;
      case Moca:
        color = Resource.JQUERY_MOKKA;
        break;
      case Vainilla:
        color = Resource.JQUERY_VANILLE;
        break;
      case Yogur:
        color = Color.WHITE;
        break;
      default:
        color = Color.WHITE;
        break;
    }

    final JComponent editor = spinner.getEditor();
    int c = editor.getComponentCount();
    for (int i = 0; i < c; i++) {
      final Component comp = editor.getComponent(i);
      if (comp instanceof JTextComponent) {
        ((JTextComponent) comp).setUI(new SynthFormattedTextFieldUI() {
          @Override
          protected void paint(javax.swing.plaf.synth.SynthContext context, java.awt.Graphics g) {
            g.setColor(color);
            g.fillRect(3, 3, getComponent().getWidth() - 3, getComponent().getHeight() - 6);
            super.paint(context, g);
          }
        });
      }
    }

  }



  @Override
  public void setFrameTitleId(String id) {
    setTitle(id);
  }



  @Override
  public void setLanguage(ISO639 code) {
    knopfleiste.setLanguage(code);
    serviceButton.setLanguage(code);
    setLanguage(KEY.FRAME_SERVER_KONFIGURIEREN, code); // der Fenstertitel wird gesetzt
    labelStarttype.setLanguage(code);
    label.setLanguage(code);
    status.setLanguage(code);
    labelPort.setLanguage(code);
    gestartet.setLanguage(code);
    if (isGestartet) status.setText(gestartet.toString());
    vonHandAus.setLanguage(code);
    automatisch.setLanguage(code);
  }



  /**
   * Der Port wird gesetzt. Der FTS-Port liegt im Bereich 29467-29478.
   * 
   * @param value
   *              der Port, auf dem gehorcht wird [29467-29478]
   */
  public void setPort(Integer value) {
    port = value;
    model.setValue(port);
  }



  /**
   * Der Startmodus wird gesetzt, ob der Server per Hand gestart werden soll oder
   * nach jedem Programmstart automatisch.
   * 
   * @param value
   */
  public void setStarttype(Starttype value) {
    for (int index = 0; index < multilingualTypebox.getItemCount(); index++) {
      if (multilingualTypebox.getItemAt(index).toString().equals(value.toString())) {
        multilingualTypebox.setSelectedIndex(index);
        break;
      }
    }
  }



  /**
   * 
   * @param value
   *              true, server started
   */
  public void startStop(boolean value) {
    isGestartet = value;
    if (value) {
      status.setIcon(startImage);
      status.setText(gestartet.toString());
      serviceButton.setDisabledButton1();
      serviceButton.setEnabledButton2();
    }
    else {
      status.setIcon(stopImage);
      status.setKey(KEY.LABEL_ANGEHALTEN);
      serviceButton.setDisabledButton2();
      serviceButton.setEnabledButton1();
    }
  }

}
