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

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
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.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.JToolTip;
import javax.swing.ToolTipManager;
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.ArrowTooltip;
import org.nexuswob.gui.InputDocument;
import org.nexuswob.gui.JToolTipBorder;
import org.nexuswob.gui.swing.NimbusCellRenderer;
import net.javacomm.client.environment.GUI;
import net.javacomm.client.gui.JUserlist;
import net.javacomm.client.gui.MultilingualServiceButton;
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.ChatUser;
import net.javacomm.protocol.Room;
import net.javacomm.window.manager.Control;
import net.javacomm.window.manager.Frames;
import net.javacomm.window.manager.WM;
import net.javacomm.window.manager.WindowManagerInternalFrame;



public class JBesprechungsraum extends WindowManagerInternalFrame {

  private final static Logger log = LogManager.getLogger(JBesprechungsraum.class);
  private static final long serialVersionUID = -8849895820719653247L;
  public final static int WIDTH = 600;
  public final static int HEIGHT = 530;
  private room access;
  private InternalAction internalAction = new InternalAction();
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private JPanel mainPane = new JPanel();
  private GridBagLayout gridbag = new GridBagLayout();
  private GridBagConstraints con = new GridBagConstraints();
  private JSeparator separator = new JSeparator();
  private JComboBox<String> rooms = new JComboBox<String>();
  private ButtonPanel buttonPanel = new ButtonPanel();
  private JUserlist myFriends = new JUserlist();
  private ArrowPanel arrowpanel = new ArrowPanel();
  private JUserlist userlist = new JUserlist();
  private JPanel outerpanel = new JPanel(true);
  private MultilingualServiceButton serviceButton = new MultilingualServiceButton(
      KEY.BUTTON_CONFIRM, KEY.BUTTON_SCHLIESSEN
  );
  private MultilingualLabel labelMeineBesprechungsräume = new MultilingualLabel(
      KEY.LABEL_MEINE_BESPRECHUNGSRAEUME
  );
  private MultilingualLabel labelHelp = new MultilingualLabel(KEY.LABEL_WER_EINEN);
  private Collection<String> referenceList = new ArrayList<>();

  public JBesprechungsraum() {
    init();
    setMinimumSize(new Dimension(480, 510));
  }



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



  /**
   * Der Eintrag in der Combobox.
   *
   * @param room
   *             der Raum wird eingefügt und angezeigt
   */
  public void addAndSelect(String room) {
    if (room == null) return;
    rooms.addItem(room);
  }



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



  public synchronized void removeAllListener() {
    for (PropertyChangeListener listener : changes.getPropertyChangeListeners()) {
      removeCreateroomListener(listener);
    }
    removeInternalFrameListener(internalAction);
  }



  public void focusTo() {
    buttonPanel.buttonRaumerstellen.requestFocusInWindow();
  }



  public room getAccess() {
    return access;
  }



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



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



  public final String getPassword() {
    return new String();
  }



  public final String getRoom() {
    ComboBoxEditor editor = rooms.getEditor();
    JTextField comp = (JTextField) editor.getEditorComponent();
    return comp.getText();
  }



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



  void init() {
    setContentPane(mainPane);
    mainPane.setLayout(gridbag);

    final int leftMargin = 12;
    final int rightMargin = 12;
    final int marginTop = 12;
    final int marginBottom = 12;

    con.gridx = 0;
    con.gridy = 0;
    con.gridwidth = 3;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 1.0;
    con.weighty = 0.0;
    con.insets = new Insets(marginTop, leftMargin, 24, rightMargin);
    con.anchor = GridBagConstraints.CENTER;
    gridbag.setConstraints(labelHelp, con);
    mainPane.add(labelHelp);
    labelHelp.setIcon(new ImageIcon(getClass().getResource(Resource.BESPRECUNGSRAUM_71x52)));

    con.gridx = 0;
    con.gridy = 1;
    con.gridwidth = 2;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, leftMargin, 0, 0);
    con.anchor = GridBagConstraints.WEST;
    gridbag.setConstraints(labelMeineBesprechungsräume, con);
    mainPane.add(labelMeineBesprechungsräume);

    con.gridx = 0;
    con.gridy = 2;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, leftMargin, 0, 0);
    con.anchor = GridBagConstraints.WEST;

    gridbag.setConstraints(rooms, con);
    mainPane.add(rooms);
    rooms.setEditable(true);
    rooms.setRenderer(new NimbusCellRenderer<String>());
    ComboBoxEditor editor = rooms.getEditor();
    final JTextField comp = (JTextField) editor.getEditorComponent();
    comp.setDocument(new InputDocument(Resource.FELD_LEN_ROOM));
    comp.addKeyListener(new KeyAdapter() {
      @Override
      public void keyReleased(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.VK_ENTER) {
          buttonPanel.buttonRaumerstellen.doClick();
        }
        // TODO rot einfärben, wenn der Raum nicht existiert
        // Raumliste holen
        ComboBoxModel<String> model = rooms.getModel();
        boolean foundRaumlöschen = false;
        boolean found = false;
        for (int index = 0; index < model.getSize(); index++) {
          found = comp.getText().equals(model.getElementAt(index));
          if (found) break;
        }

        foundRaumlöschen = found;
        boolean foundRaumerstellen = !found && comp.getText().length() > 0;

        log.info("foundRaumerstellen=" + foundRaumerstellen);

        buttonPanel.buttonRaumerstellen
            .setBackground(foundRaumerstellen ? Resource.JQUERY_GREEN : Resource.JQUERY_RED);
        buttonPanel.buttonRaumloeschen
            .setBackground(foundRaumlöschen ? Resource.JQUERY_GREEN : Resource.JQUERY_RED);
      }
    });
    rooms.addItemListener(new ItemListener() {

      @Override
      public void itemStateChanged(ItemEvent event) {
        if (event.getStateChange() == ItemEvent.SELECTED) {
          ComboBoxModel<String> model = rooms.getModel();
          String value = event.getItem().toString();
          int count = model.getSize();
          boolean found = false;
          for (int index = 0; index < count; index++) {
            found = found || model.getElementAt(index).equals(value);
          }
          if (found) {
            ComboBoxEditor editor = rooms.getEditor();
            final JTextField comp = (JTextField) editor.getEditorComponent();
            comp.setText(value);
            changes.firePropertyChange(value, myFriends.getMembers(), Control.TOPICMEMBER);
          }
          else {
            // wird erkannt! bei Tastatur/ENTER
            // könnte genutzt werden für CREATE wird aber auch von DELETE/ButtonKlick
            // erkannt ist nicht eindeutige
            // schwierig
            // log.info("neu=" + value);
          }
        }
      }
    });

    con.gridx = 1;
    con.gridy = 2;
    con.gridwidth = 2;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, 6, 0, rightMargin);
    con.anchor = GridBagConstraints.WEST;

    outerpanel.setLayout(new FlowLayout(FlowLayout.LEFT));
    outerpanel.add(buttonPanel);

    gridbag.setConstraints(outerpanel, con);
    mainPane.add(outerpanel);

    con.gridx = 0;
    con.gridy = 3;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.BOTH;
    con.weightx = 1.0;
    con.weighty = 1.0;
    con.insets = new Insets(0, leftMargin, 0, 0);
    con.anchor = GridBagConstraints.CENTER;

    gridbag.setConstraints(myFriends, con);
    mainPane.add(myFriends);

    con.gridx = 1;
    con.gridy = 3;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, 12, 0, 12);
    con.anchor = GridBagConstraints.CENTER;

    gridbag.setConstraints(arrowpanel, con);
    mainPane.add(arrowpanel);

    con.gridx = 2;
    con.gridy = 3;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.BOTH;
    con.weightx = 1.0;
    con.weighty = 1.0;
    con.insets = new Insets(0, 0, 0, rightMargin);
    con.anchor = GridBagConstraints.CENTER;

    gridbag.setConstraints(userlist, con);
    mainPane.add(userlist);

    con.gridx = 0;
    con.gridy = 4;
    con.gridwidth = 3;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 1.0;
    con.weighty = 0.0;
    con.insets = new Insets(24, leftMargin, 0, rightMargin);
    con.anchor = GridBagConstraints.CENTER;

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

    con.gridx = 1;
    con.gridy = 5;
    con.gridwidth = 2;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(12, leftMargin, marginBottom, rightMargin);
    con.anchor = GridBagConstraints.EAST;

    gridbag.setConstraints(serviceButton, con);
    add(serviceButton);
    serviceButton.addButtonListener(event -> {
      Control value = (Control) event.getNewValue();
      switch(value) {
        case BUTTON_1:
          JTextField field = (JTextField) rooms.getEditor().getEditorComponent();
          String room = field.getText();
          if (room.length() == 0) return;
          changes.firePropertyChange(room, Control.NULL, Control.UPDATE_CHATUSER);
          break;
        case BUTTON_2:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        default:
          break;
      }
    });
    serviceButton.setEnabledButton2();
    serviceButton.setDisabledButton1();
    addInternalFrameListener(internalAction);
  }



  /**
   * Gib alle Nicknames meiner Freunde zurück.
   *
   * @return die Nicknames aus meiner Freundesliste
   */
  public List<String> getNicknames() {
    return Collections.list(myFriends.getMembers());
  }



  public boolean isCreateButtonRed() {
    return false;
  }



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



  /**
   * Der Anwender versuchte einen Raum zu löschen, den es nicht gibt.
   *
   */
  public void removeEditableElement() {
    buttonPanel.buttonRaumloeschen.setBackground(Resource.JQUERY_RED);
    buttonPanel.buttonRaumerstellen.setBackground(Resource.JQUERY_GREEN);
  }



  /**
   * Diese Methode wird nur aufgerufen, wenn ein Raum tatsächlich gelöscht wurde.
   *
   * @param room
   *             dieser Raum wird entfernt
   */
  public void removeRoom(String room) {
    if (room == null) return;
    rooms.removeItem(room);
    myFriends.clear();
    userlist.clear();
    ComboBoxModel<String> model = rooms.getModel();
    int count = model.getSize();
    if (count == 0) {
      buttonPanel.buttonRaumloeschen.setBackground(Resource.JQUERY_RED);
      buttonPanel.buttonRaumerstellen.setBackground(Resource.JQUERY_RED);
      return;
    }
    else {
      rooms.setSelectedIndex(0);
      buttonPanel.buttonRaumloeschen.setBackground(Resource.JQUERY_GREEN);
      buttonPanel.buttonRaumerstellen.setBackground(Resource.JQUERY_RED);
    }
  }



  @Override
  public void removeWM(WM frame) {}



  public void setCandidatemembers(ChatUser[] user) {
    if (user == null) return;
    int count = user.length;
    String[] member = new String[count];
    for (int index = 0; index < count; index++) {
      member[index] = user[index].getNickname();
    }
    userlist.clear();
    userlist.setMember(member);
  }



  void resetReferenceList(String member[]) {
    referenceList.clear();
    Collections.addAll(referenceList, member);
    serviceButton.setDisabledButton1();
  }



  public void setTopicmembers(ChatUser[] user) {
    if (user == null) return;
    int count = user.length;
    String[] member = new String[count];
    for (int index = 0; index < count; index++) {
      member[index] = user[index].getNickname();
    }
    myFriends.clear();
    myFriends.setMember(member);
    resetReferenceList(member);
  }



  /**
   * Alle Stammtische werden übergeben.
   *
   * @param value
   *              eine Stammtischliste
   */
  public void setTopicrooms(List<Room[]> value) {
    if (value == null) return;
    setTopicrooms(value.toArray(new Room[value.size()]));
  }



  public void setTopicrooms(Room[] value) {
    if (value == null) return;
    // TODO den aktuellen Raum ermitteln und auswählen

    String aktuellerRaum = (String) rooms.getSelectedItem();

    rooms.removeAllItems();
    int count = value.length;
    if (count == 0) {
      buttonPanel.buttonRaumloeschen.setBackground(Resource.JQUERY_RED);
      buttonPanel.buttonRaumerstellen.setBackground(Resource.JQUERY_RED);
      return;
    }
    for (int index = 0; index < count; index++) {
      rooms.addItem(value[index].getChatid());
      if (value[index].getChatid().equals(aktuellerRaum)) {
        rooms.setSelectedItem(aktuellerRaum);
      }
    }
    buttonPanel.buttonRaumloeschen.setBackground(Resource.JQUERY_GREEN);
    buttonPanel.buttonRaumerstellen.setBackground(Resource.JQUERY_RED);
  }



  @Override
  public void setType(Frames value) {
    // TODO Auto-generated method stub

  }

  /**
   *
   *
   *
   * @author llange
   *
   */
  private class ArrowPanel extends JPanel {

    private static final long serialVersionUID = 779758453353282377L;
    private MultilingualString teilnehmerEinladen = new MultilingualString(
        KEY.STRING_BENUTZER_IN_DIE_TEILNEHMERLISTE
    );
    private MultilingualString teilnehmerVerabschieden = new MultilingualString(
        KEY.STRING_BENUTZER_AUS_DER_TEILNEHMERLISTE
    );
    @SuppressWarnings("serial")
    private JButton buttonLeft = new JButton() {
      @Override
      public JToolTip createToolTip() {
        ArrowTooltip arrow = new ArrowTooltip(Resource.JQUERY_ORANGE);
        arrow.setComponent(buttonLeft);
        arrow.setTextAttributes(GUI.regularFont13, Color.BLACK, Resource.JQUERY_ORANGE);
        arrow.setBorder(new JToolTipBorder(7, Resource.JQUERY_GREEN, Resource.JQUERY_ORANGE));
        return arrow;
      }
    };
    @SuppressWarnings("serial")
    private JButton buttonRight = new JButton() {
      @Override
      public JToolTip createToolTip() {
        ToolTipManager.sharedInstance().setInitialDelay(200);
        ToolTipManager.sharedInstance().setDismissDelay(4000);
        ArrowTooltip arrow = new ArrowTooltip(Resource.JQUERY_ORANGE);
        arrow.setComponent(buttonRight);
        arrow.setTextAttributes(GUI.regularFont13, Color.BLACK, Resource.JQUERY_ORANGE);
        arrow.setBorder(new JToolTipBorder(7, Resource.JQUERY_RED, Resource.JQUERY_ORANGE));
        return arrow;
      }
    };

    private Class<? extends ArrowPanel> clazz;

    private ArrowPanel() {
      super(true);
      setLayout(new GridLayout(2, 1));
      init();
    }



    /**
     * Hat sich die Freundesliste geändert?
     *
     */
    private void changedBuddies() {
      ArrayList<String> collection = Collections.list(myFriends.getMembers());
      boolean found = collection.size() == referenceList.size();
      for (String tmp : collection) {
        found = found && referenceList.contains(tmp);
      }
      if (found) {
        serviceButton.setDisabledButton1();
      }
      else {
        serviceButton.setEnabledButton1();
      }
    }



    private void init() {
      clazz = getClass();
      buttonLeft.setIcon(new ImageIcon(clazz.getResource(Resource.LEFTARROW_25x26)));
      buttonLeft.setToolTipText(teilnehmerEinladen.toString());
      buttonLeft.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent event) {
          List<String> selectedMembers = userlist.getSelectedMembers();
          userlist.removeMember(selectedMembers);
          myFriends.setMember(selectedMembers);
          changedBuddies();
        }
      });
      buttonRight.setIcon(new ImageIcon(clazz.getResource(Resource.RIGHTARROW_25x26)));
      buttonRight.setToolTipText(teilnehmerVerabschieden.toString());
      buttonRight.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent eevnt) {
          List<String> selectedMembers = myFriends.getSelectedMembers();
          myFriends.removeMember(selectedMembers);
          userlist.setMember(selectedMembers);
          changedBuddies();
        }
      });

      add(buttonLeft);
      add(buttonRight);
    }

  }

  private class ButtonPanel extends JPanel {

    private static final long serialVersionUID = 5384115606373922543L;
    private MultilingualButton buttonRaumerstellen = new MultilingualButton(KEY.BUTTON_RAUM_ERSTELLEN);
    private MultilingualButton buttonRaumloeschen = new MultilingualButton(KEY.BUTTON_RAUM_LOESCHEN);

    private ButtonPanel() {
      super(true);
      setLayout(new GridLayout(1, 2, 6, 0));
      init();
    }



    private void init() {
      add(buttonRaumerstellen);
      buttonRaumerstellen.setForeground(Color.WHITE);
      buttonRaumerstellen.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
          JTextField field = (JTextField) rooms.getEditor().getEditorComponent();
          String room = field.getText();
          if (room.length() == 0) return;
          changes.firePropertyChange(room, Control.NULL, Control.CREATE);
        }

      });

      add(buttonRaumloeschen);

      // TODO Gibt es Räume?
      buttonRaumloeschen.setForeground(Color.WHITE);
      buttonRaumloeschen.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
          JTextField field = (JTextField) rooms.getEditor().getEditorComponent();
          String room = field.getText();
          if (room.length() == 0) return;
          changes.firePropertyChange(room, Control.NULL, Control.DELETE);
        }

      });

    }

  }

  private class InternalAction extends InternalFrameAdapter {

    @Override
    public void internalFrameClosed(InternalFrameEvent event) {
      changes.firePropertyChange(JBesprechungsraum.class.getName(), Control.NULL, Control.CLOSE);
    }
  }

  public enum room {
    publicroom,
    protectedroom
  }

  @Override
  public void setLanguage(ISO639 code) {
    serviceButton.setLanguage(KEY.BUTTON_CONFIRM, KEY.BUTTON_SCHLIESSEN, code);
    buttonPanel.buttonRaumerstellen.setLanguage(code);
    buttonPanel.buttonRaumloeschen.setLanguage(code);
    userlist.setHeader(KEY.LABEL_BENUTZER, code);
    myFriends.setHeader(KEY.LABEL_MITGLIEDER, code);
    labelMeineBesprechungsräume.setLanguage(code);
    setLanguage(KEY.FRAME_BESPRECHUNGSRAEUME, code);
    labelHelp.setLanguage(code);
    labelHelp.setText("<html>" + labelHelp.getText() + "</html>");
    arrowpanel.teilnehmerEinladen.setLanguage(code);
    arrowpanel.buttonLeft.setToolTipText(arrowpanel.teilnehmerEinladen.toString());
    arrowpanel.teilnehmerVerabschieden.setLanguage(code);
    arrowpanel.buttonRight.setToolTipText(arrowpanel.teilnehmerVerabschieden.toString());
  }



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

}
