/**
 *  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.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.javacomm.client.config.schema.Config;
import net.javacomm.client.config.schema.FileTransferService;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;
import net.javacomm.protocol.Searchfile;
import net.javacomm.window.manager.Control;
import net.javacomm.window.manager.Frames;
import net.javacomm.window.manager.WM;
import net.javacomm.window.manager.WindowAnrufenEvent;
import net.javacomm.window.manager.WindowAnrufenListener;
import net.javacomm.window.manager.WindowManager;
import net.javacomm.window.manager.WindowManagerInternalFrame;



/**
 * Der Hauptframe für den Dateiübertragungsdienst.
 *
 * @author lromero
 *
 */
public class JFTServiceFrame extends WindowManagerInternalFrame implements WindowAnrufenListener {

  class FrameAction extends InternalFrameAdapter {

    @Override
    public void internalFrameClosing(InternalFrameEvent event) {
      hauptfenster.removeAllListener();
      removeAllListener();
      hauptfenster.relase();
      changes.firePropertyChange("JFTServiceFrame", Control.NULL, Control.EXIT_ON_CLOSE);
    }

  }

  private static final long serialVersionUID = 1281899504863867586L;

  private final static Logger log = LogManager.getLogger(JFTServiceFrame.class);
  public final static int SLOTS = 2;
  public final static int SCREEN_WIDTH = 900;
  public final static int SCREEN_HEIGHT = 672;
  public final static int NULL = 0;
  private JPanel main = new JPanel(true);
  private FrameAction frameAction = new FrameAction();
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private JHauptfenster hauptfenster;
  private MouseAdapter hauptfensterMouseAdapter;
  private JScrollPane scrollHauptfenster = new JScrollPane();
  private String record = "";
  private JSplitPane splitpane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
  private JScrollBar verticalScrollbar;
  private ComponentAdapter componentAdapter = new ComponentAdapter() {

    @Override
    public void componentResized(ComponentEvent event) {
      if (JFTServiceFrame.this.isMaximum()) {
        setHorizontalDivider(1.0);
      }
      else {}
    }

  };

  private JLabel corner;

  public JFTServiceFrame(Config root) {
    FileTransferService fts = root.getFileTransferService();
    if (fts == null) {
      // RuntimeException werden, weil der FileTransferService fehlt
      log.warn("Der FileTransferService ist in der config.xml nicht hinterlegt.");
      return;
    }

    setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    main.setLayout(new BorderLayout());
    setMaximizable(true);
    setResizable(true);
    setIconifiable(true);
    setClosable(true);
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

    addInternalFrameListener(frameAction);
    windowManager.addWMListener(event -> {
      if (event.getNewValue() == Control.MOUSE_EXITED) {
        return;
      }
      changes.firePropertyChange(event);
    });
    hauptfenster = new JHauptfenster(this, root);
    hauptfenster.setMinimumSize(new Dimension(0, 0));
    hauptfensterMouseAdapter = new MouseAdapter() {

      @Override
      public void mouseEntered(MouseEvent event) {
        if (event.getSource().equals(hauptfenster)) {
          if (hauptfenster.getParent().getWidth() == hauptfenster.getWidth()) return;
          setHorizontalDivider(1.0);
        }
      }



      @Override
      public void mouseExited(MouseEvent event) {
        if (event.getSource().equals(hauptfenster)) {
          // verlässt das Hauptfenster
          if (
            (hauptfenster.getWidth() == scrollHauptfenster.getWidth())
                && (event.getX() == hauptfenster.getWidth())
          ) {
            setHorizontalDivider(JFTServiceFrame.this.getWidth() - WindowManagerInternalFrame.SPLITWIDTH);
            return;
          }
          setHorizontalDivider(1.0);
        }
        else {
          setHorizontalDivider(1.0);
          return;
        }
      }

    };
//    hauptfenster.addMouseListener(hauptfensterMouseAdapter);
    scrollHauptfenster.setViewportView(hauptfenster);
    hauptfenster.addHauptfensterListener(propertyEvent -> {
      Control control = (Control) propertyEvent.getNewValue();
      switch(control) {
        case EXIT_ON_CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case DELETEUPLOAD:
          changes.firePropertyChange(propertyEvent);
          break;
        case UPLOADFILE:
          changes.firePropertyChange(propertyEvent);
          break;
        case STOP:
          changes.firePropertyChange(propertyEvent);
          break;
        case DISCONNECT:
          changes.firePropertyChange(propertyEvent);
          break;
        case TRANSMIT:
          changes.firePropertyChange(propertyEvent);
          break;
        case SEARCH:
          changes.firePropertyChange(propertyEvent);
          break;
        default:
          break;
      }
    });

    splitpane.setLeftComponent(scrollHauptfenster);
    verticalScrollbar = scrollHauptfenster.getVerticalScrollBar();
    verticalScrollbar.setUnitIncrement(12);
    scrollHauptfenster.getHorizontalScrollBar().setUnitIncrement(12);
    scrollHauptfenster.setBorder(null);

    corner = new JLabel();
    // die richtige Farbe einblenden
    corner.setBackground(UIManager.getColor("nimbusSelectionBackground"));
    corner.setOpaque(true);
    scrollHauptfenster.setCorner(ScrollPaneConstants.LOWER_RIGHT_CORNER, corner); // ok!

    splitpane.setRightComponent(windowManager);
    windowManager.setMinimumSize(new Dimension(0, 0));
    splitpane.setDividerLocation(SCREEN_WIDTH);
    splitpane.setOneTouchExpandable(true);
    main.add(BorderLayout.CENTER, splitpane);
    setContentPane(main);
  }



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



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



  /**
   *
   * @param files
   * @param hasStarted
   *                   true, neue Anfrage, die bisherige Dateiliste löschen
   */
  public void addFoundFiles(Searchfile[] files, boolean hasStarted) {
    hauptfenster.addFoundFiles(files, hasStarted);
  }



  public void clearSlot(int slot) {
    hauptfenster.setDownloadFile(slot, new String());
  }



  /**
   * Eine Hilfsmehode, welche die rechte untere Ecke in der Videoansicht einfärbt.
   * Nach einem L&F-Wechsel wudre die Farbe nicht geändert.
   *
   * @param color
   *              eine Farbe
   */
  public void corner(Color color) {
    corner.setBackground(color);
  }



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



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



  @Override
  public Dimension getMinimumSize() {
    return new Dimension(720, 540);
  }



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



  WindowManager getWM() {
    return windowManager;
  }



  @Override
  public void insertWM(WM value) {
    windowManager.addWindow(value);
  }



  /**
   * Ist der Server inaktiv?
   *
   * @return {@code true}, der Server ist down und der Publishknopf ist rot
   */
  public boolean isPublished() {
    return hauptfenster.isDown();
  }



  public void removeAllListener() {
    removeComponentListener(componentAdapter);
    hauptfenster.removeMouseListener(hauptfensterMouseAdapter);
    windowManager.removeAllListener();
    removeInternalFrameListener(frameAction);
  }



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



  @Override
  public void removeWM(WM record) {
    windowManager.removeWM(record);
  }



  @Override
  public void ringRing(WindowAnrufenEvent event) {
    extText = event.getNickname();
    getMultiAbnehmen().setLanguage(KEY.FRAME_ABNEHMEN, event.getCode(), extText);
    getMultiAnrufen().setLanguage(KEY.TELEFON_ANRUFEN, event.getCode(), extText);
  }



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



  // Titel
  @Override
  public void setFrameTitleId(String str) {
    record = str;
    setTitle(record);
  }



  /**
   * Die Trennleiste wird in horizontaler Richtung positioniert. Die Angabe
   * erfolgt in Prozent. 0-Prozent ist ganz links und 100-Prozent ist ganz rechts.
   *
   * @param prozent
   *                liegt im Intervall [0..1]
   */
  public void setHorizontalDivider(double prozent) {
    if (0 > prozent || prozent > 1) {
      log.warn(prozent + " - die Prozentangabe liegt nicht im Intervall [0..1]");
    }
    splitpane.setDividerLocation(prozent);
  }



  /**
   * Die Trennleiste wird in horizontaler Richtung positioniert. Die Angabe
   * erfolgt in Pixel. 0 ist ganz links und {@code SCREEN_WIDTH} ist ganz rechts.
   *
   *
   * @param pixel
   *              die X-Position
   */
  public void setHorizontalDivider(int pixel) {
    splitpane.setDividerLocation(pixel);
  }



  @Override
  public void setLanguage(ISO639 code) {
    hauptfenster.setLanguage(code);
    setLanguage(KEY.FRAME_FILESHARING, code);
    treeView(code);
  }



  /**
   * Eine Channelbeschreibung aus JChat. Der Anwender wollte einen Download auf
   * einem belegten Channel starten.
   *
   *
   * @param value
   *              ein Channel, der belegt ist
   */
  public void setOccupied(Channel value) {
    hauptfenster.setDownloadFile(value.getSlot().getSlotnumber(), value.getSlot().getFilename());
  }



  /**
   *
   * @param slot
   * @param value
   *              Prozentpunkte
   */
  public void setProgressDownload(int slot, int value) {
    hauptfenster.setProgressDownload(slot, value);
  }



  @Override
  public void setType(Frames value) {

  }

}
