/**
 *  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.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.JToolTip;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nexuswob.gui.ArrowTooltip;
import org.nexuswob.gui.InputDocument;
import org.nexuswob.gui.JToolTipBorder;
import net.javacomm.client.config.schema.Config;
import net.javacomm.client.config.schema.FileTransferService;
import net.javacomm.client.environment.Environment;
import net.javacomm.client.environment.GUI;
import net.javacomm.client.resource.Resource;
import net.javacomm.multilingual.Babelfish;
import net.javacomm.multilingual.MultilingualButton;
import net.javacomm.multilingual.MultilingualString;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;
import net.javacomm.protocol.Searchfile;
import net.javacomm.window.manager.Control;



/**
 * Das Hauptfenster für den Dateiübertragungsdienst. Das Hauptfenster ist der
 * linke Bereich vom Navigationsfenster innerhalb des gesamten InternalFrames.
 * 
 * @author lromero
 *
 */
public class JHauptfenster extends JPanel implements Babelfish {

  private final static Logger log = LogManager.getLogger(JHauptfenster.class);
//  public final static Dimension FILE_CHOOSER_SIZE = new Dimension(680, 450);
  private static final long serialVersionUID = 5280689170668508786L;
  private final static int columns = 45;
  private GridBagLayout gridbag = new GridBagLayout();
  private GridBagConstraints con = new GridBagConstraints();
  private JFTServiceSuchmuster suchmuster = new JFTServiceSuchmuster();
  private MultilingualString channel = new MultilingualString(KEY.STRING_CHANNEL);
  private PropertyChangeSupport changesHauptfenster = new PropertyChangeSupport(this);
  // neue Komponenten
  private Class<? extends JHauptfenster> resource;

  private MultilingualString uploadText = new MultilingualString(KEY.STRING_UPLOAD_DIRECTORY);
  private MultilingualString downloadText = new MultilingualString(KEY.STRING_DOWNLOAD_DIRECTORY);
  private MultilingualString downloadTextfield = new MultilingualString(KEY.STRING_DOWNLOAD_VERZEICHNIS);
  private MultilingualString uploadTextfield = new MultilingualString(KEY.STRING_UPLOAD_VERZEICHNIS);
  private MultilingualString multilingualMarkieren = new MultilingualString(KEY.STRING_MARKIEREN);
  private MultilingualString multilingualConfirm = new MultilingualString(KEY.BUTTON_CONFIRM);
  private MultilingualString clickFileOrDirectory = new MultilingualString(
      KEY.STRING_CLICK_FILE_OR_DIRECTORY
  );
  private MultilingualString confirmDirectory = new MultilingualString(KEY.STRING_CONFIRM_DIRECTORY);


  @SuppressWarnings("serial")
  private JButton uploadButton = new JButton("...") {
    @Override
    public JToolTip createToolTip() {
      ToolTipManager.sharedInstance().setInitialDelay(200);
      ToolTipManager.sharedInstance().setDismissDelay(5000);
      ArrowTooltip arrow = new ArrowTooltip(Resource.JQUERY_TEXTBRAUN);
      arrow.setComponent(uploadButton);
      arrow.setTextAttributes(GUI.regularFont13, Color.WHITE, Resource.JQUERY_TEXTBRAUN);
      arrow.setBorder(new JToolTipBorder(7, Resource.JQUERY_ORANGE, Resource.JQUERY_TEXTBRAUN));
      return arrow;
    }

  };
  private JButton downloadButton = new JButton("...") {
    private static final long serialVersionUID = -5733324930253227534L;
    @Override
    public JToolTip createToolTip() {
      ToolTipManager.sharedInstance().setInitialDelay(200);
      ToolTipManager.sharedInstance().setDismissDelay(5000);
      ArrowTooltip arrow = new ArrowTooltip(Resource.JQUERY_TEXTBRAUN);
      arrow.setComponent(downloadButton);
      arrow.setTextAttributes(GUI.regularFont13, Color.WHITE, Resource.JQUERY_TEXTBRAUN);
      arrow.setBorder(new JToolTipBorder(7, Resource.JQUERY_ORANGE, Resource.JQUERY_TEXTBRAUN));
      return arrow;
    }
  };
  @SuppressWarnings("serial")
  private JTextField uploadVerzeichnis = new JTextField(columns) {

    @Override
    public JToolTip createToolTip() {
      ToolTipManager.sharedInstance().setInitialDelay(200);
      ToolTipManager.sharedInstance().setDismissDelay(5000);
      ArrowTooltip arrow = new ArrowTooltip(Resource.JQUERY_TEXTBRAUN);
      arrow.setComponent(uploadVerzeichnis);
      arrow.setTextAttributes(GUI.regularFont13, Color.WHITE, Resource.JQUERY_TEXTBRAUN);
      arrow.setBorder(new JToolTipBorder(7, Resource.JQUERY_ORANGE, Resource.JQUERY_TEXTBRAUN));
      return arrow;
    }

  };
  @SuppressWarnings("serial")
  private JTextField downloadVerzeichnis = new JTextField(columns) {
    @Override
    public JToolTip createToolTip() {
      ToolTipManager.sharedInstance().setInitialDelay(200);
      ToolTipManager.sharedInstance().setDismissDelay(5000);
      ArrowTooltip arrow = new ArrowTooltip(Resource.JQUERY_TEXTBRAUN);
      arrow.setComponent(downloadVerzeichnis);
      arrow.setTextAttributes(GUI.regularFont13, Color.WHITE, Resource.JQUERY_TEXTBRAUN);
      arrow.setBorder(new JToolTipBorder(7, Resource.JQUERY_ORANGE, Resource.JQUERY_TEXTBRAUN));
      return arrow;
    }
  };
  private JButtonChecker publishButton = new JButtonChecker();
  private JTrefferliste trefferliste = new JTrefferliste();
  private MultilingualButton trefferlisteButton = new MultilingualButton(KEY.BUTTON_TREFFERLISTE);
  private JPanel slotpanel = new JPanel(new GridLayout(1, 2, 18, 0));
  private JSlot slot[] = new JSlot[2];
  private JSeparator separator = new JSeparator();
  private MultilingualButton buttonSchliessen = new MultilingualButton(KEY.BUTTON_SCHLIESSEN);
  private FileTransferService fts;


  public JHauptfenster(Component service, Config root) {
    setLayout(gridbag);

    resource = getClass();

    final int top = 12;
    final int left = 12;
    final int right = 12;
    final int trefferlisteRight = 12;
    final int trefferlisteLeft = 12;
    final int trefferlisteTop = 12;

    // 1. Reihe

    uploadButton.setIcon(new ImageIcon(resource.getResource(Resource.EXPORT)));
    uploadButton.setToolTipText(uploadText.toString());
    uploadButton.addActionListener((event) -> {
      String upload = fts.getUpload();
      if (upload == null) upload = System.getProperty("user.home");
      JFileChooser fileChooser = new JFileChooser(upload);
      fileChooser.setDialogTitle(publishButton.getText());
      fileChooser.setApproveButtonText(multilingualMarkieren.toString());
      fileChooser.setApproveButtonToolTipText(clickFileOrDirectory.toString());
      fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
      fileChooser.setPreferredSize(GUI.FILE_CHOOSER_SIZE);

      UIManager.put("FileChooser.cancelButtonText", multilingualConfirm.toString());
      UIManager.put("FileChooser.cancelButtonToolTipText", confirmDirectory.toString());
      SwingUtilities.updateComponentTreeUI(fileChooser);
      fileChooser.showOpenDialog(service);
      String uploadpath = fileChooser.getCurrentDirectory().getAbsolutePath(); // ist ein String
      if ((fileChooser.getSelectedFile() != null) && (fileChooser.getSelectedFile().isDirectory())) {
        uploadpath = fileChooser.getSelectedFile().getAbsolutePath();
      }
      fts.setUpload(uploadpath);
      uploadVerzeichnis.setText(uploadpath);
      changesHauptfenster
          .firePropertyChange(JHauptfenster.class.getName(), Control.NULL, Control.DELETEUPLOAD);

      // transmit, wenn der Server oben ist
      if (!publishButton.isDown()) {
        changesHauptfenster
            .firePropertyChange(JHauptfenster.class.getName(), Control.NULL, Control.UPLOADFILE);
      }
    });

    con.gridx = 0;
    con.gridy = 0;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(top, left, 0, 0);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(uploadButton, con);
    add(uploadButton);

    con.gridx = 1;
    con.gridy = 0;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(top, trefferlisteLeft, 0, trefferlisteRight);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(uploadVerzeichnis, con);
    add(uploadVerzeichnis);
    uploadVerzeichnis.setDocument(new InputDocument(255));
    uploadVerzeichnis.setToolTipText(uploadTextfield.toString());

    publishButton.addActionListener((event) -> {
      if (publishButton.isDown()) {
        publishButton.setGreen();
        changesHauptfenster
            .firePropertyChange(JHauptfenster.class.getName(), Control.NULL, Control.UPLOADFILE);
      }
      else {
        publishButton.setRed();
        changesHauptfenster.firePropertyChange(JHauptfenster.class.getName(), Control.NULL, Control.STOP);
      }
    });

    con.gridx = 2;
    con.gridy = 0;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(top, 0, 0, right);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(publishButton, con);
    add(publishButton);

    // 2. Reihe
    downloadButton.setIcon(new ImageIcon(resource.getResource(Resource.IMPORT)));
    downloadButton.setToolTipText(downloadText.toString());
    downloadButton.setHorizontalAlignment(JButton.LEFT);
    downloadButton.addActionListener((event) -> {
      String download = fts.getDownload();
      if (download == null) download = System.getProperty("user.home");
      JFileChooser fileChooser = new JFileChooser(download);
      fileChooser.setDialogTitle("Ablageordner");
      fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
      fileChooser.setApproveButtonText("Markieren");
      fileChooser.setApproveButtonToolTipText(clickFileOrDirectory.toString());
      fileChooser.setPreferredSize(GUI.FILE_CHOOSER_SIZE);
      UIManager.put("FileChooser.cancelButtonText", multilingualConfirm.toString());
      UIManager.put("FileChooser.cancelButtonToolTipText", confirmDirectory.toString());
      SwingUtilities.updateComponentTreeUI(fileChooser);
      fileChooser.showOpenDialog(service);

      String mediaformat = fileChooser.getCurrentDirectory().getAbsolutePath(); // ist ein String
      if ((fileChooser.getSelectedFile() != null) && (fileChooser.getSelectedFile().isDirectory())) {
        mediaformat = fileChooser.getSelectedFile().getAbsolutePath();
      }
      fts.setDownload(mediaformat);
      downloadVerzeichnis.setText(mediaformat);
      downloadVerzeichnis.setCaretPosition(0);
    });

    con.gridx = 0;
    con.gridy = 1;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, left, 0, 0);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(downloadButton, con);
    add(downloadButton);

    con.gridx = 1;
    con.gridy = 1;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, trefferlisteLeft, 0, trefferlisteRight);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(downloadVerzeichnis, con);
    add(downloadVerzeichnis);
    downloadVerzeichnis.setDocument(new InputDocument(255));
    downloadVerzeichnis.setToolTipText(downloadTextfield.toString());

    // 3. Reihe

    con.gridx = 0;
    con.gridy = 2;
    con.gridwidth = 2;
    con.gridheight = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 1.0;
    con.weighty = 0.0;
    con.insets = new Insets(trefferlisteTop, left, 0, trefferlisteRight);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(trefferliste, con);
    add(trefferliste);
    trefferliste.getHorizontalScrollBar().setUnitIncrement(10);
    trefferliste.getVerticalScrollBar().setUnitIncrement(10);

    con.gridx = 2;
    con.gridy = 2;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(trefferlisteTop, 0, 0, right);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(suchmuster, con);
    add(suchmuster);
    suchmuster.addLookingForListener((event) -> {
      changesHauptfenster.firePropertyChange(event);
    });

    // 4. Reihe

    trefferlisteButton.setIcon(new ImageIcon(getClass().getResource(Resource.REFRESH)));

    trefferlisteButton.setHorizontalAlignment(JButton.CENTER);
    trefferlisteButton.addActionListener((event) -> {
      changesHauptfenster
          .firePropertyChange(JHauptfenster.class.getName(), suchmuster.getSuchmuster(), Control.SEARCH);
    });
    con.gridx = 0;
    con.gridy = 3;
    con.gridwidth = 2;
    con.gridheight = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, left, 0, trefferlisteRight);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(trefferlisteButton, con);
    add(trefferlisteButton);

    // 5. Reihe

    con.gridx = 0;
    con.gridy = 4;
    con.gridwidth = 3;
    con.gridheight = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, left, 0, 12);
    con.anchor = GridBagConstraints.WEST;
    gridbag.setConstraints(slotpanel, con);
    add(slotpanel);
    slot[0] = new JSlot();
    slot[0].setSlot(0);
    slot[0].addDisconnectListener((event) -> {
      Transport transport = new Transport(slot[0].getKanal(), slot[0].getFilename(), slot[0].getIndex());
      changesHauptfenster.firePropertyChange(event.getPropertyName(), transport, event.getNewValue());
    });
    slot[1] = new JSlot();
    slot[1].setSlot(1);
    slot[1].addDisconnectListener((event) -> {
      Transport transport = new Transport(slot[1].getKanal(), slot[1].getFilename(), slot[1].getIndex());
      changesHauptfenster.firePropertyChange(event.getPropertyName(), transport, event.getNewValue());
    });
    slotpanel.add(slot[0]);
    slotpanel.add(slot[1]);

    // 6. Reihe

    con.gridx = 0;
    con.gridy = 5;
    con.gridwidth = 3;
    con.gridheight = 1;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.anchor = GridBagConstraints.CENTER;
    con.insets = new Insets(24, left, 12, right);

    gridbag.setConstraints(separator, con);
    add(separator);

    // 7. Reihe

    con.gridx = 2;
    con.gridy = 6;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.weightx = 0.0;
    con.weighty = 1.0;
    con.fill = GridBagConstraints.NONE;
    con.anchor = GridBagConstraints.NORTHEAST;
    con.insets = new Insets(0, left, 12, right);

    buttonSchliessen.setIcon(new ImageIcon(resource.getResource(Resource.BROWN_CLOSE_BUTTON)));
    buttonSchliessen.addActionListener((event) -> {
      changesHauptfenster.firePropertyChange("JHauptFenster", Control.NULL, Control.EXIT_ON_CLOSE);
    });
    gridbag.setConstraints(buttonSchliessen, con);
    add(buttonSchliessen);
//    // Initialisierung nach der GUI
    init(root);

  }



  void addFoundFiles(Searchfile[] searchfile, boolean hasStarted) {
    trefferliste.refresh(searchfile, hasStarted);
  }



  public synchronized void addHauptfensterListener(PropertyChangeListener l) {
    changesHauptfenster.addPropertyChangeListener(l);
  }



  /**
   * Die laufende �bertragung wird unterbrochen.
   * 
   * @param kanal
   *              der Slot
   */
  void buttonDisconnect(int kanal) {
    slot[kanal].disconnect();
  }



  int countSlots() {
    return slot.length;
  }



  /**
   * Der File Transfer Server ist down.
   */
  void ftsIsDown() {
    publishButton.setRed();
  }



  /**
   * Das Uplaodverzeichnis und das Downloadverzeichnis dürfen erst nach dem
   * Auslegen der GUI initialisiert werden. Der Grund ist das InputDocument und
   * seine Beschränkung auf 255 Zeichen.
   * 
   * @param root
   *             der Inhalt der Konfigurationsdatei
   */
  private void init(Config root) {
    fts = root.getFileTransferService();
    if (fts.getDownload() == null) {
      fts.setDownload(Environment.getInstance().getDownloadDir().toAbsolutePath().toString());
    }
    downloadVerzeichnis.setText(fts.getDownload());
    downloadVerzeichnis.setCaretPosition(0);
    if (fts.getUpload() == null) {
      fts.setUpload(Environment.getInstance().getUploadDir().toAbsolutePath().toString());
    }
    uploadVerzeichnis.setText(fts.getUpload());
    uploadVerzeichnis.setCaretPosition(0);
  }



  void readyToTransmit(int kanal) {
    slot[kanal].ready();
  }



  /**
   * Das Model der Trefferliste wird frei gegeben. Der Speicher wird frei gegeben.
   * 
   */
  void relase() {
    trefferliste.clearModel();
  }



  void removeAllListener() {
    for (PropertyChangeListener listener : changesHauptfenster.getPropertyChangeListeners()) {
      changesHauptfenster.removePropertyChangeListener(listener);
    }
  }



  public synchronized void removeHauptfensterListener(PropertyChangeListener l) {
    changesHauptfenster.removePropertyChangeListener(l);
  }



  /**
   * Die Datei wird gerade oder soll heruntergeladen werden.
   * 
   * 
   * @param kanal
   *              Slot 1 oder Slot 2
   * @param value
   *              der Dateiname der Slot
   */
  void setDownloadFile(int kanal, String value) {
    slot[kanal].setFilename(value);
  }



  void setProgressDownload(int kanal, int value) {
    slot[kanal].setPercent(value);
  }



  /**
   * Ist der Publishbutton gedrückt? Der Server ist GUImäßig down.
   * 
   * @return {@code true}, er ist inaktiv
   */
  boolean isDown() {
    return publishButton.isDown;
  }

  private static class JButtonChecker extends MultilingualButton {

    private static final long serialVersionUID = -6199591539468484176L;
    private Icon green;
    private Icon red;
    private boolean isDown = true;

    JButtonChecker() {
      super();
      Class<? extends JButtonChecker> resource = getClass();
      green = new ImageIcon(resource.getResource(Resource.SMALL_GREEN_CHECK));
      red = new ImageIcon(resource.getResource(Resource.SMALL_RED_CHECK25x25));
      setRed();

    }



    @SuppressWarnings("unused")
    public JButtonChecker(String value) {
      this();
      super.setText(value);
    }



    public boolean isDown() {
      return isDown;
    }



    public void setGreen() {
      isDown = false;
      setIcon(green);
    }



    public void setRed() {
      isDown = true;
      setIcon(red);
    }

  }

  @Override
  public void setLanguage(ISO639 code) {
    buttonSchliessen.setLanguage(code);
    trefferlisteButton.setLanguage(code);
    publishButton.setLanguage(KEY.BUTTON_PUBLISH, code);
    suchmuster.setLanguage(code);
    trefferliste.setLanguage(code);
    slot[0].setLanguage(code);
    slot[1].setLanguage(code);
    channel.setLanguage(code);
    slot[0].setTitle(" " + channel.toString() + " 1 ");
    slot[1].setTitle(" " + channel.toString() + " 2 ");
    uploadText.setLanguage(code);
    uploadButton.setToolTipText(uploadText.toString());
    downloadText.setLanguage(code);
    downloadButton.setToolTipText(downloadText.toString());
    downloadTextfield.setLanguage(code);
    downloadVerzeichnis.setToolTipText(downloadTextfield.toString());
    uploadTextfield.setLanguage(code);
    uploadVerzeichnis.setToolTipText(uploadTextfield.toString());
    multilingualMarkieren.setLanguage(code);
    multilingualConfirm.setLanguage(code);
    clickFileOrDirectory.setLanguage(code);
    confirmDirectory.setLanguage(code);
  }

}
