/**
 *  Copyright © 2022-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.telko;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nexuswob.gui.InputDocument;
import net.javacomm.client.gui.JSliderVolumePanel;
import net.javacomm.client.resource.Resource;
import net.javacomm.multilingual.MultilingualButton;
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.protocol.KonferenzraumUser;
import net.javacomm.share.Constants;
import net.javacomm.transfer.TransferKonferenzraum;
import net.javacomm.window.manager.Control;
import net.javacomm.window.manager.Frames;
import net.javacomm.window.manager.WM;
import net.javacomm.window.manager.WMResource;
import net.javacomm.window.manager.WindowManagerInternalFrame;



public class JTelefonkonferenzTeilnehmenFrame extends WindowManagerInternalFrame {

  private final static Logger log = LogManager.getLogger(JTelefonkonferenzTeilnehmenFrame.class);

  private static final long serialVersionUID = 5617163885860305413L;

  public final static Dimension MIN_NORMAL = new Dimension(320, 180);
  public final static Dimension PREFERRED_NORMAL = new Dimension(1260, 540);

  public final static int BREITE = Constants.LEN_KONFERENZ_BESCHREIBUNG;
  private GridBagLayout gridbag = new GridBagLayout();
  private GridBagConstraints con = new GridBagConstraints();
  private BorderLayout borderLayout = new BorderLayout(0, 0);
  private JPanel mainpanel = new JPanel();
  private JOnlineOfflinePanel online = new JOnlineOfflinePanel();
  private JOnlineOfflinePanel offline = new JOnlineOfflinePanel();
  private JScrollPane scrollleftpane = new JScrollPane();
  private JLabel labelNickname = new JLabel();
  private PropertyChangeListener abnehmenListener;
  private boolean isMuted = false;

  private JSliderVolumePanel volumepanel = new JSliderVolumePanel();
  private Knopfleiste knopfleiste = new Knopfleiste();
  private ActionListener buttonHoererAuflegenListener = new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
      // Teilen deaktivieren
      if (isShared) {
        isShared = false;
        knopfleiste.buttonTeilen.setIcon(iconVideoanruf);
        changes.firePropertyChange(
            JTelefonkonferenzTeilnehmenFrame.class.getName(), Control.NULL, Control.SHARING
        );
      }
      changes.firePropertyChange(
          JTelefonkonferenzTeilnehmenFrame.class.getName(), Control.NULL, Control.TELEFON_AUFLEGEN
      );

    }

  };
  private ActionListener buttonHoererAbnehmenListener = new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent event) {
      changes.firePropertyChange(
          JTelefonkonferenzTeilnehmenFrame.class.getName(), Control.NULL, Control.TELEFON_ABNEHMEN
      );
    }

  };

  private ActionListener buttonAufzeichnenListener;
  private ActionListener buttonVideoListener;
  private JSeparator separator = new JSeparator();
  private MultilingualButton buttonSchliessen = new MultilingualButton(KEY.BUTTON_SCHLIESSEN);
  private ActionListener buttonCloseListener;
  private MultilingualLabel labelOrganisator = new MultilingualLabel(KEY.LABEL_ORGANISATOR);
  private JComboBox<String> comboKonferenzname = new JComboBox<>();
  private MultilingualLabel multilingualKonferenzname = new MultilingualLabel(KEY.LABEL_KONFERENZNAME);
  private MultilingualLabel labelBeschreibung = new MultilingualLabel(KEY.STRING_BESCHREIBUNG);
  private MultilingualString einzigerTeilnehmer = new MultilingualString(
      KEY.STRING_EINZIGE_KONFERENZTEILNEHMER
  );
  private MultilingualString nichtAnwesendInKonferenz = new MultilingualString(
      KEY.STRING_NICHT_ANWESEND_IN_KONFERENZ
  );
  private JTextArea textareaBeschreibung = new JTextArea();
  private JScrollPane scrollpane = new JScrollPane(textareaBeschreibung);
  private JSplitPane splitpane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
  private JPanel centerpanel = new JPanel();
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private InternalAction internalAction = new InternalAction();
  private HashMap<Integer, TransferKonferenzraum> dataKonferenzraum = new HashMap<>();
  private ArrayList<String> sessionlist = new ArrayList<>();
  private ItemListener comboboxAction;
  private String konferenzname;
  private String conferenceKey;
  private ImageIcon micConference;
  private ImageIcon micConferenceOff;
  private ImageIcon iconVideoanrufAnimated;
  private ImageIcon iconVideoanruf;
  private boolean isShared = false;
  private String userid;
  private String currentNickname;

  public JTelefonkonferenzTeilnehmenFrame() {
    setMinimumSize(MIN_NORMAL);
    setSize(PREFERRED_NORMAL);
    init();
  }

  private class InternalAction extends InternalFrameAdapter {
    @Override
    public void internalFrameClosing(InternalFrameEvent event) {
      dataKonferenzraum.clear();
      sessionlist.clear();
      changes.firePropertyChange(
          JTelefonkonferenzTeilnehmenFrame.this.getClass().getName(), Control.NULL, Control.CLOSE
      );
    }

  }

  /**
   * Die Leiste Knopf Auflegen und Knopf Ablegen
   * 
   * 
   * @author llange
   *
   */
  private class Knopfleiste extends JPanel {

    private static final long serialVersionUID = 7506748079964000121L;
    private GridLayout grid = new GridLayout(1, 4, 24, 24);
    private MultilingualButton buttonHoererAbnehmen = new MultilingualButton(KEY.BUTTON_HOERER_ABNEHMEN);
    private MultilingualButton buttonHoererAuflegen = new MultilingualButton(KEY.BUTTON_HOERER_AUFLEGEN);
    private MultilingualButton buttonAufzeichnen = new MultilingualButton(KEY.BUTTON_AUFZEICHNEN);
    private MultilingualButton buttonTeilen = new MultilingualButton(KEY.BUTTON_SHARE);
    private Class<? extends Knopfleiste> resourceKnopfleiste;

    private Knopfleiste() {
      resourceKnopfleiste = Knopfleiste.class;
      micConference = new ImageIcon(resourceKnopfleiste.getResource(Resource.MICROPHONE_CONFERENCE));
      micConferenceOff = new ImageIcon(resourceKnopfleiste.getResource(Resource.FORBIDDEN_MICROPHONE));
      iconVideoanrufAnimated = new ImageIcon(
          resourceKnopfleiste.getResource(Resource.DESKTOP_ANIMATED_25x25)
      );
      iconVideoanruf = new ImageIcon(resourceKnopfleiste.getResource(Resource.DESKTOP_25x25));

      setLayout(grid);

      add(buttonHoererAbnehmen);
      buttonHoererAbnehmen.setIcon(new ImageIcon(resourceKnopfleiste.getResource(Resource.ABNEHMEN)));

      add(buttonHoererAuflegen);
      buttonHoererAuflegen.setIcon(new ImageIcon(resourceKnopfleiste.getResource(Resource.AUFLEGEN)));

      add(buttonAufzeichnen);
      buttonAufzeichnen.setIcon(micConference);
      buttonAufzeichnenListener = new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent event) {
          isMuted = !isMuted;
          knopfleiste.buttonAufzeichnen.setIcon(isMuted ? micConferenceOff : micConference);
          changes.firePropertyChange(
              JTelefonkonferenzTeilnehmenFrame.class.getName(), Control.NULL, Control.MIKRO_AUFZEICHNEN
          );
        }

      };

      buttonAufzeichnen.addActionListener(buttonAufzeichnenListener);

      buttonVideoListener = new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {

          // TODO von Userid nach Nickname umstellen

          if (
            online.getKonferenzraumTeilnehmer().stream()
                .noneMatch(user -> user.getNickname().equals(currentNickname))
          ) {
            JOptionPane.showMessageDialog(
                JTelefonkonferenzTeilnehmenFrame.this, nichtAnwesendInKonferenz.toString()
            );
            return;
          }

          // nur starten, wenn es receiverSessions gibt
          if (getSessions().length < 1) {
            JOptionPane
                .showMessageDialog(JTelefonkonferenzTeilnehmenFrame.this, einzigerTeilnehmer.toString());
            return;
          }
          stopAnimation();
          changes.firePropertyChange(
              JTelefonkonferenzTeilnehmenFrame.class.getName(), Control.NULL, Control.SHARING
          );
        }
      };
      add(buttonTeilen);
      buttonTeilen.setIcon(iconVideoanruf);
      buttonTeilen.addActionListener(buttonVideoListener);

      buttonDisabled(buttonHoererAuflegen, buttonHoererAuflegenListener);
      buttonDisabled(buttonHoererAbnehmen, buttonHoererAbnehmenListener);
    }



    /**
     * Ein Knopf wird rot eingefärbt.
     * 
     * @param button
     *               dieser Knopf wird deaktiviert
     * @param al
     *               dieser ActionListener gehört zum übergebenen Knopf
     */
    private void buttonDisabled(JButton button, ActionListener al) {
      button.removeActionListener(al);
      button.setForeground(WMResource.DISABLED_BUTTON_FOREGROUND);
      button.setBackground(WMResource.DISABLED_BUTTON_BACKGROUND);
    }



    /**
     * Der Knopf wird grün.
     * 
     * @param button
     *               dieser Knopf wird aktiviert
     * @param al
     *               dieser ActionListener gehört zum übergebenen Knopf
     */
    private void buttonEnabled(JButton button, ActionListener al) {
      button.setForeground(WMResource.ENABLED_BUTTON_FOREGROUND);
      button.setBackground(WMResource.ENABLED_BUTTON_BACKGROUND);
      if (button.getActionListeners().length == 0) button.addActionListener(al);
    }

  }

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



  public void addKonferenzListener(PropertyChangeListener listener) {
    changes.addPropertyChangeListener(listener);
  }



  @Override
  public String getBaumansicht() {
    return multiTelefonkonferenzBeitreten.toString();
  }



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



  public String getKonferenzname() {
    return konferenzname;
  }



  public String getConferenceKey() {
    return conferenceKey;
  }



  /**
   * An diese Konferenzteilnehmer wird gesendet. Die eigene Session ist nicht
   * darunter.
   * 
   */
  public String[] getSessions() {
    return sessionlist.toArray(new String[sessionlist.size()]);
  }



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



  /**
   * Welcher Anwender öffnete diesen Frame?
   * 
   * @return dieser Anwender
   */
  public String getUserid() {
    return userid;
  }



  /**
   * Die Lautsprecherstärke wird vom Slider gelesen.
   * 
   * 
   * @return die Lautstärke
   */
  public int getVolume() {
    return volumepanel.getLoudness();
  }



  private void init() {

    setLayout(borderLayout);
    this.add(splitpane, BorderLayout.CENTER);

    mainpanel.setLayout(new BorderLayout(12, 0));

    online.setTopBackground(Resource.JQUERY_GREEN);
    online.setTopForeground(Color.WHITE);
    online.installMouseListener();
    online.addChatInfoListener(event -> {
      changes.firePropertyChange(event);
    });
    offline.setTopBackground(Resource.JQUERY_RED);
    offline.setTopForeground(Color.WHITE);
    offline.installMouseListener();
    offline.addChatInfoListener(event -> {
      changes.firePropertyChange(event);
    });

    mainpanel.add(online, BorderLayout.WEST);
    mainpanel.add(offline, BorderLayout.EAST);
    mainpanel.add(centerpanel, BorderLayout.CENTER);

    scrollleftpane.setMinimumSize(new Dimension(0, 0));
    scrollleftpane.setViewportView(mainpanel);
    scrollleftpane.getHorizontalScrollBar().setUnitIncrement(12);
    scrollleftpane.getVerticalScrollBar().setUnitIncrement(12);

    splitpane.setLeftComponent(scrollleftpane);
    splitpane.setRightComponent(windowManager);
    splitpane.setDividerLocation(PREFERRED_NORMAL.width - WindowManagerInternalFrame.SPLITWIDTH);
    splitpane.setOneTouchExpandable(true);
    windowManager.setMinimumSize(new Dimension(0, 0));
    windowManager.addWMListener(propertyEvent -> {
      changes.firePropertyChange(propertyEvent);

    });

    centerpanel.setLayout(gridbag);

    // 1. Reihe
    con.gridx = 0;
    con.gridy = 0;
    con.gridwidth = 1;
    con.insets = new Insets(12, 0, 0, 0);
    con.fill = GridBagConstraints.NONE;
    con.anchor = GridBagConstraints.CENTER;
    con.weightx = 0.0;
    con.weighty = 0.0;
    gridbag.setConstraints(labelOrganisator, con);
    centerpanel.add(labelOrganisator);

    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.insets = new Insets(0, 0, 0, 0);
    con.fill = GridBagConstraints.NONE;
    con.anchor = GridBagConstraints.CENTER;
    con.weightx = 0.0;
    con.weighty = 0.0;
    gridbag.setConstraints(labelNickname, con);
    centerpanel.add(labelNickname);
    labelNickname.setText("anaconda");

    // 2. Reihe
    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.insets = new Insets(18, 0, 0, 0);
    con.fill = GridBagConstraints.NONE;
    con.anchor = GridBagConstraints.CENTER;
    con.weightx = 0.0;
    con.weighty = 0.0;
    gridbag.setConstraints(multilingualKonferenzname, con);
    centerpanel.add(multilingualKonferenzname);

    // 3. Reihe
    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.insets = new Insets(0, 12, 12, 0);
    con.fill = GridBagConstraints.NONE;
    con.anchor = GridBagConstraints.CENTER;
    con.weightx = 0.0;
    con.weighty = 0.0;
    gridbag.setConstraints(comboKonferenzname, con);
    centerpanel.add(comboKonferenzname);
    comboKonferenzname.setMaximumRowCount(7);
    comboKonferenzname.setMaximumSize(new Dimension(BREITE, 32));
    comboKonferenzname.setMinimumSize(new Dimension(BREITE, 32));
    comboKonferenzname.setPreferredSize(new Dimension(BREITE, 32));
    comboboxAction = new ItemListener() {

      @Override
      public void itemStateChanged(ItemEvent event) {

        if (event.getStateChange() == ItemEvent.SELECTED) {
          String beschreibung = dataKonferenzraum.get(comboKonferenzname.getSelectedIndex())
              .getBeschreibung();
          textareaBeschreibung.setText(beschreibung);
          String organisator = dataKonferenzraum.get(comboKonferenzname.getSelectedIndex()).getNickname(); // Organisator
          labelNickname.setText(organisator);
          konferenzname = comboKonferenzname.getSelectedItem().toString();
          conferenceKey = dataKonferenzraum.get(comboKonferenzname.getSelectedIndex()).getConferencekey();
          requestAnwesenheitsliste();

        }
      }
    };

    // 4. Reihe

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

    // 5. Reihe
    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.insets = new Insets(0, 12, 12, 0);
    con.fill = GridBagConstraints.NONE;
    con.anchor = GridBagConstraints.NORTH;
    con.weightx = 0.0;
    con.weighty = 0.0;
    gridbag.setConstraints(scrollpane, con);
    centerpanel.add(scrollpane);
    scrollpane.setMaximumSize(new Dimension(330, 90));
    scrollpane.setMinimumSize(new Dimension(330, 90));
    scrollpane.setPreferredSize(new Dimension(330, 90));

    textareaBeschreibung.setDocument(new InputDocument(Constants.LEN_KONFERENZ_BESCHREIBUNG));
    textareaBeschreibung.setLineWrap(true);
    textareaBeschreibung.setWrapStyleWord(true);
    textareaBeschreibung.getInputMap(JComponent.WHEN_FOCUSED)
        .put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "TAB");
    textareaBeschreibung.getActionMap().put("TAB", new AbstractAction() {

      private static final long serialVersionUID = 1167795538247195434L;

      @Override
      public void actionPerformed(ActionEvent event) {
        textareaBeschreibung.transferFocus();
      }

    });

    // 6. Reihe
    final int margin_left = 6;
    final int margin_right = 6;

    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(18, 0, 24, 0);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(volumepanel, con);
    centerpanel.add(volumepanel);
    abnehmenListener = new PropertyChangeListener() {

      @Override
      public void propertyChange(PropertyChangeEvent event) {
        changes.firePropertyChange(
            JTelefonkonferenzTeilnehmenFrame.class.getName(), Control.NULL, Control.TELEFON_VOLUME
        );
      }

    };
    volumepanel.addVolumeListener(abnehmenListener);

    // 7. Reihe
    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(12, margin_left, 18, margin_right);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(knopfleiste, con);
    centerpanel.add(knopfleiste);

    // 8. Reihe
    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.anchor = GridBagConstraints.CENTER;
    con.insets = new Insets(12, margin_left, 0, margin_right);
    gridbag.setConstraints(separator, con);
    centerpanel.add(separator);

    // 9. Reihe

    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 1.0;
    con.anchor = GridBagConstraints.NORTHEAST;
    con.insets = new Insets(18, margin_left, 18, margin_right);
    gridbag.setConstraints(buttonSchliessen, con);
    centerpanel.add(buttonSchliessen);
    buttonCloseListener = event -> {
      try {
        setClosed(true);
      }
      catch (PropertyVetoException e1) {}
    };
    buttonSchliessen.addActionListener(buttonCloseListener);

    addInternalFrameListener(internalAction);
  }



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



  /**
   * Ist das Mikro auf stumm geschaltet?
   * 
   * @return {@code true}, wenn das Mikro auf stumm geschaltet ist
   */
  public boolean isMuted() {
    return isMuted;
  }



  /**
   * Ein Anwender möchte seinen Bildschirm an andere Konferenzteilnehmer
   * übertragen.
   * 
   * @return {@code true}, Bildschirm teilen mit allen Konferenzteilnehmern oder
   *         {@code false}, Bildschirm teilen zurückziehen
   */
  public boolean isShared() {
    return isShared;
  }



  /**
   * Die Konferenzdaten werden neu angezeigt.
   */
  public void refreshData() {
    comboKonferenzname.removeItemListener(comboboxAction);
    comboKonferenzname.removeAllItems();
    textareaBeschreibung.setText("");
    labelNickname.setText("");

    dataKonferenzraum.forEach((key, value) -> {
      comboKonferenzname.addItem(value.getKonferenzraum());
    });

    int index = comboKonferenzname.getSelectedIndex();
    if (index == -1) return;
    textareaBeschreibung.setText(dataKonferenzraum.get(index).getBeschreibung());
    textareaBeschreibung.setCaretPosition(0);
    labelNickname.setText(dataKonferenzraum.get(index).getNickname()); // Organisator
    comboKonferenzname.addItemListener(comboboxAction);
    konferenzname = comboKonferenzname.getSelectedItem().toString();
    conferenceKey = dataKonferenzraum.get(comboKonferenzname.getSelectedIndex()).getConferencekey();

    // eine Anwesenheitsliste anfordern
    requestAnwesenheitsliste();
  }



  public void removeAllListener() {
    for (PropertyChangeListener pl : changes.getPropertyChangeListeners()) {
      removeKonferenzListener(pl);
    }
    removeInternalFrameListener(internalAction);
    comboKonferenzname.removeActionListener(comboKonferenzname);
    knopfleiste.buttonHoererAbnehmen.removeActionListener(buttonHoererAbnehmenListener);
    knopfleiste.buttonHoererAuflegen.removeActionListener(buttonHoererAuflegenListener);
    knopfleiste.buttonAufzeichnen.removeActionListener(buttonAufzeichnenListener);
    knopfleiste.buttonTeilen.removeActionListener(buttonVideoListener);

    buttonSchliessen.removeActionListener(buttonCloseListener);
    volumepanel.removeVolumeListener(abnehmenListener);
    online.deinstallMouseListener();
    offline.deinstallMouseListener();
    Arrays.stream(changes.getPropertyChangeListeners())
        .forEach(listener -> changes.removePropertyChangeListener(listener));
  }



  public void removeKonferenzListener(PropertyChangeListener listener) {
    changes.removePropertyChangeListener(listener);
  }



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



  /**
   * Eine Anwesenheitsliste anfordern.
   * 
   */
  public void requestAnwesenheitsliste() {
    changes
        .firePropertyChange(JTelefonkonferenzTeilnehmenFrame.class.getName(), Control.NULL, Control.REQUEST);
  }



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



  /**
   * Die Maske "Telefonkonferenz>Beitreten" wird befüllt. Organisator,
   * Konferenzname, KOnferenzschlüssel, Beschreibungstext.
   * 
   * 
   * @param data
   *             alle Konferenzräume mit Organisator, Konferenzname,
   *             Beschreibungstext
   */
  public void setData(List<TransferKonferenzraum> data) {
    dataKonferenzraum.clear();
    int index = 0;
    for (TransferKonferenzraum tmp : data) {
      dataKonferenzraum.put(index++, tmp);
    }
  }



  /**
   * 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);
  }



  /**
   * Die Knopfeinstellungen auf der Leiste werden aktiviert oder deaktiviert. Wenn
   * der Anwender offline ist, dann wird der Knopf aktiviert. Ist der Anwender
   * online, dann wird der Knopf deaktiviert. Dasselbe gilt für den KnopfListener.
   * 
   * @param session
   *                          der Anwender muss nicht der Organisator sein
   * @param konferenzraumuser
   *                          alle Konferenzteilnehmer
   */
  public void setKnopfleiste(String session, KonferenzraumUser[] konferenzraumuser) {

    boolean found = false;
    for (KonferenzraumUser tmp : konferenzraumuser) {
      if (session.equals(tmp.getSession())) {
        found = tmp.isAnwesend();
        break;
      }
    }

    if (found) {
      // online
      comboKonferenzname.setEnabled(false);

      knopfleiste.buttonDisabled(buttonSchliessen, buttonCloseListener);
      knopfleiste.buttonDisabled(knopfleiste.buttonHoererAbnehmen, buttonHoererAbnehmenListener);
      knopfleiste.buttonEnabled(knopfleiste.buttonHoererAuflegen, buttonHoererAuflegenListener);
    }
    else {
      // offline
      if (konferenzraumuser.length >= 2) {
        knopfleiste.buttonEnabled(knopfleiste.buttonHoererAbnehmen, buttonHoererAbnehmenListener);
        knopfleiste.buttonDisabled(knopfleiste.buttonHoererAuflegen, buttonHoererAuflegenListener);
      }
      else {
        knopfleiste.buttonDisabled(knopfleiste.buttonHoererAbnehmen, buttonHoererAbnehmenListener);
        // schliessen button muss auf jeden Fall aktiv sein
      }
      knopfleiste.buttonEnabled(buttonSchliessen, buttonCloseListener);
      comboKonferenzname.setEnabled(true);
    }

  }



  /**
   * Der Onlinestatus der Konferenzteilnehmer wird gesetzt. Die eigene Session aus
   * {@code KonferenzraumUser[]} wird nicht in die Empfängersessionliste
   * übernommen.
   * 
   * @param konferenzraumuser
   *                          alle Konferenzteilnehmer
   * @param session
   *                          der Konferenzteilnehmer
   */
  public void setKonferenzraumuser(KonferenzraumUser[] konferenzraumuser, String session) {
    sessionlist.clear();
    online.clear();
    offline.clear();
    for (KonferenzraumUser tmp : konferenzraumuser) {
      if (tmp.isAnwesend()) {
        // Onlinepanel
        online.addUser(tmp);
        // sessionuserlist erneuern
        if (session.equals(tmp.getSession())) {
          online.setNickname(tmp.getNickname());
          continue;
        }
        sessionlist.add(tmp.getSession());
      }
      else {
        // Offlinepanel
        offline.addUser(tmp);
      }
    }
  }



  @Override
  public void setLanguage(ISO639 code) {
    setLanguage(KEY.STRING_TEILNEHMEN, code);
    online.setLanguage(KEY.LABEL_ANWESEND, code);
    offline.setLanguage(KEY.LABEL_ABWESEND, code);
    volumepanel.setLanguage(code);
    multilingualKonferenzname.setLanguage(code);
    labelBeschreibung.setLanguage(code);
    labelOrganisator.setLanguage(code);
    knopfleiste.buttonHoererAbnehmen.setLanguage(code);
    knopfleiste.buttonHoererAuflegen.setLanguage(code);
    knopfleiste.buttonAufzeichnen.setLanguage(code);
    knopfleiste.buttonTeilen.setLanguage(code);
    buttonSchliessen.setLanguage(code);
    einzigerTeilnehmer.setLanguage(code);
    nichtAnwesendInKonferenz.setLanguage(code);

    treeView(code);
  }



  /**
   * Dieser Anwender öffnet das Fenster.
   * 
   * @param userid
   *                 User ID
   * @param nickname
   *                 Nickname
   */
  public void setUserid(String userid, String nickname) {
    this.userid = userid;
    currentNickname = nickname;
  }



  /**
   * Die Lautsprecherstärke wird in der GUI eingestellt und nicht am realen
   * Lautsprecher.
   * 
   * @param volume
   */
  public void setVolume(int volume) {
    volumepanel.setLoudness(volume);
  }



  /**
   * 
   * Die Bildschirmübertragung wird angehalten.
   * 
   */
  public void stopAnimation() {
    knopfleiste.buttonTeilen.setIcon(isShared ? iconVideoanruf : iconVideoanrufAnimated);
    isShared = !isShared;
  }



  public void setNickname(String nickname) {
    currentNickname = nickname;
  }

}
