/**
 *  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.gui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Hashtable;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import net.javacomm.client.resource.Resource;
import net.javacomm.multilingual.Babelfish;
import net.javacomm.multilingual.MultilingualLabel;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;



public class JSliderVolumePanel extends JPanel implements Babelfish {

  private static final long serialVersionUID = 5482442378039214012L;
  final static int TICKSPACING = 34;
  public final static int NORMAL = TICKSPACING * 2;
  public final static int max = TICKSPACING * 3;
  private Videoslider volumeSlider = new Videoslider(0, max);
  private Hashtable<Integer, JLabel> sliderlabels = new Hashtable<>();

  private JLabel imageSpeakerPlus = new JLabel();
  private JLabel imageSpeakerMinus = new JLabel();
  private GridBagLayout gridbag = new GridBagLayout();
  private GridBagConstraints con = new GridBagConstraints();
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private MouseAction mouseAction = new MouseAction();
  private AbstractAction leftAction;
  private AbstractAction rightAction;
  final static String RECHTS = "rechts";
  final static String LINKS = "links";
  private boolean mouseDragged = false;
  private MultilingualLabel labelLaut = new MultilingualLabel(KEY.LABEL_LAUT);
  private MultilingualLabel labelminimum = new MultilingualLabel(KEY.LABEL_LAUTLOS);
  private MultilingualLabel labelNormal = new MultilingualLabel(KEY.LABEL_NORMAL);
  private MultilingualLabel labelLeise = new MultilingualLabel(KEY.LABEL_LEISE);
  private Class<? extends JSliderVolumePanel> resource;

  public JSliderVolumePanel() {
    this(JSliderVolumePanel.NORMAL);
  }



  /**
   *
   *
   * @param loudness
   *                 die Lautstärke zwischen 0 und 100
   */
  @SuppressWarnings("serial")
  public JSliderVolumePanel(int loudness) {
    super(true);
    if (
        (0 > loudness) || (loudness > max)
        ) throw new IllegalArgumentException(
            "Die Lautstärke liegt nicht im Bereich zwischen [0 bis " + max + "]. - " + loudness
            );
    // value = loudness;
    resource = getClass();
    setLayout(gridbag);

    volumeSlider.setOrientation(SwingConstants.HORIZONTAL);
    volumeSlider.setPaintTicks(true);
    volumeSlider.setPaintLabels(true);
    volumeSlider.setMajorTickSpacing(TICKSPACING);
    volumeSlider.setSnapToTicks(false);
    volumeSlider.addMouseListener(mouseAction);
    volumeSlider.addMouseMotionListener(mouseAction);

    volumeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "none");
    volumeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "none");

    leftAction = new AbstractAction() {

      @Override
      public void actionPerformed(ActionEvent e) {
        int position = volumeSlider.getValue();
        if (position <= 0) return;
        volumeSlider.setValue(--position);
        changes.firePropertyChange(JSliderVolumePanel.class.getName(), Integer.MIN_VALUE, position);
      }
    };
    volumeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LINKS);
    volumeSlider.getActionMap().put(LINKS, leftAction);

    rightAction = new AbstractAction() {

      @Override
      public void actionPerformed(ActionEvent e) {
        int position = volumeSlider.getValue();
        if (position >= max) return;
        volumeSlider.setValue(++position);
        changes.firePropertyChange(JSliderVolumePanel.class.getName(), Integer.MIN_VALUE, position);
      }
    };
    volumeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RECHTS);
    volumeSlider.getActionMap().put(RECHTS, rightAction);

    sliderlabels.put(0, labelminimum);
    sliderlabels.put(max, labelLaut);
    sliderlabels.put((max * 2) / 3, labelNormal);
    sliderlabels.put(max / 3, labelLeise);

    imageSpeakerMinus.setIcon(new ImageIcon(resource.getResource(Resource.ICON_VOLUME_MINUS)));
    imageSpeakerMinus.setHorizontalAlignment(SwingConstants.CENTER);
    con.gridy = 0;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(imageSpeakerMinus, con);
    add(imageSpeakerMinus, con);

    volumeSlider.setLabelTable(sliderlabels);
    volumeSlider.setValue(loudness);
    con.anchor = GridBagConstraints.CENTER;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weighty = 0.0;
    con.weightx = 1.0;
    con.gridy = 0;
    gridbag.setConstraints(volumeSlider, con);
    add(volumeSlider, con);

    con.gridy = 0;
    con.weighty = 0.0;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    gridbag.setConstraints(imageSpeakerPlus, con);
    con.anchor = GridBagConstraints.CENTER;
    imageSpeakerPlus.setIcon(new ImageIcon(resource.getResource(Resource.ICON_VOLUME_PLUS)));
    imageSpeakerPlus.setHorizontalAlignment(SwingConstants.CENTER);
    add(imageSpeakerPlus, con);
  }



  /**
   *
   * Die Lautstärkeregelung wird überwacht.
   *
   * @param l
   */
  public synchronized void addVolumeListener(PropertyChangeListener l) {
    changes.addPropertyChangeListener(l);
  }



  /**
   * Die Lautstärke
   *
   * @return ein Wert zwischen 0 und 100
   */
  public int getLoudness() {
    return volumeSlider.getValue();
  }



  /**
   * Die Lautstärkeregelung wird nicht mehr überwacht.
   *
   * @param l
   */
  public synchronized void removeVolumeListener(PropertyChangeListener l) {
    changes.removePropertyChangeListener(l);
  }



  /**
   * Die Lautstärke wird auf dem Schieberegler eingestellt.
   *
   *
   * @param value
   *              die Lautstärke zwischen 0 und {@link #max}
   */
  public void setLoudness(int value) {
    volumeSlider.setValue(Math.max(0, Math.min(value, JSliderVolumePanel.max)));
  }

  /**************************************************************
   * * * MouseAction * * *
   *************************************************************/
  class MouseAction extends MouseAdapter {

    @Override
    public void mouseDragged(MouseEvent event) {
      mouseDragged = true;
    }



    @Override
    public void mousePressed(MouseEvent event) {
      if (!mouseDragged) {
        int currentValue = volumeSlider.getTimerposition();
        // umrechnen von Timer nach value
        // Die Audioausgabe darf 100 nicht übersteigen, vlc4j Einschränkung
        int result = Math.min(100, volumeSlider.getMaximum() * currentValue / volumeSlider.getMaxTimevalue());
        volumeSlider.setValue(result);
        changes.firePropertyChange(JSliderVolumePanel.class.getName(), 0, result);
      }
    }



    @Override
    public void mouseReleased(MouseEvent event) {
      if (mouseDragged) {
        // bei dragging muss videoslider.getValue verwendet werden
        int position = volumeSlider.getValue();
        if (position >= 100) position = 100;
        changes.firePropertyChange(JSliderVolumePanel.class.getName(), 0, position);
        mouseDragged = false;
      }
    }

  }

  @Override
  public void setLanguage(ISO639 code) {
    volumeSlider.requestFocusInWindow();
    labelLaut.setLanguage(code);
    labelminimum.setLanguage(code);
    labelLeise.setLanguage(code);
    labelNormal.setLanguage(code);
  }

}