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

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToolTip;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.ToolTipManager;
import javax.swing.border.EmptyBorder;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nexuswob.gui.ArrowTooltip;
import org.nexuswob.gui.JToolTipBorder;
import org.nexuswob.gui.TableModel3;
import org.nexuswob.util.Cell;
import org.nexuswob.util.Util;
import net.javacomm.client.environment.GUI;
import net.javacomm.client.resource.Resource;
import net.javacomm.multilingual.Babelfish;
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.window.manager.Control;



/**
 * Ein grafischer Überblick über alle Anwender, die in einem Konferenzraum sind.
 * 
 * 
 * @author llange
 *
 */
public class JOnlineOfflinePanel extends JPanel implements Babelfish {

  /***************************************************************************/
  /*                                                                         */
  /* Innerclass ColorRenderer */
  /*                                                                         */
  /***************************************************************************/

  class ColorRenderer extends JLabel implements TableCellRenderer {

    private static final long serialVersionUID = 1483352116438614471L;
    private Class<? extends ColorRenderer> resource;
    private ImageIcon onlineIcon;
    private ImageIcon offlineIcon;

    public ColorRenderer() {
      setOpaque(true);
      resource = ColorRenderer.class;
      onlineIcon = new ImageIcon(resource.getResource(Resource.ONLINE_26x26));
      offlineIcon = new ImageIcon(resource.getResource(Resource.OFFLINE_26x26));
    }



    @Override
    public Component getTableCellRendererComponent(JTable table, Object str, boolean isSelected,
        boolean hasFocus, int row, int column) {

      // Wenn der chatuser anwesend ist, dann zeichne Mikro
      KonferenzraumUser user = konferenzraumUser.get(row);

      setBackground(new Color(user.getBackgroundColor()));
      setForeground(new Color(user.getForegroundColor()));
      setText((String) str);

      if (user.isAnwesend()) {
        if (user.isMute()) {
          try {
            BufferedImage image = JOnlineOfflinePanel.modifyRGBA(Resource.MUTE_26x26, getForeground());
            setIcon(new ImageIcon(image));
            setHorizontalAlignment(SwingConstants.LEFT);
            setIconTextGap(12);
          }
          catch (IOException e) {
            log.info(e.getMessage(), e);
          }
        }
        else {
          try {
            BufferedImage image = JOnlineOfflinePanel.modifyRGBA(Resource.UNMUTE_26x26, getForeground());
            setIcon(new ImageIcon(image));
            setHorizontalAlignment(SwingConstants.LEFT);
            setIconTextGap(12);
          }
          catch (IOException e) {
            log.info(e.getMessage(), e);
          }
        }
      }
      else {
        // nicht in der Videokonferenz
        if (user.getWebsocketSession() == null) {
          setIcon(offlineIcon);
          setHorizontalAlignment(SwingConstants.LEFT);
          setIconTextGap(12);
          setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0));
        }
        else {
          setIcon(onlineIcon);
          setHorizontalAlignment(SwingConstants.LEFT);
          setIconTextGap(12);
          setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0));
        }

      }
      return this;
    }

  }

  /**
   * In diesem Panel werden die User gezählt.
   */
  static class CountUserPanel extends JPanel {

    private static final long serialVersionUID = 8123825495408532218L;
    private JLabel labelNumber = new JLabel();
    private GridBagLayout gridbag = new GridBagLayout();
    private GridBagConstraints con = new GridBagConstraints();
    private MultilingualLabel labelAnwesend = new MultilingualLabel(KEY.LABEL_ANWESEND);

    public CountUserPanel() {
      setLayout(gridbag);
      setBackground(Resource.JQUERY_ORANGE);

      con.insets = new Insets(2, 2, 0, 2);
      con.gridwidth = GridBagConstraints.REMAINDER;
      gridbag.setConstraints(labelAnwesend, con);
      add(labelAnwesend);
      labelAnwesend.setForeground(Resource.JQUERY_TEXTBRAUN);

      con.insets = new Insets(1, 2, 2, 2);
      gridbag.setConstraints(labelNumber, con);
      labelNumber.setForeground(Resource.JQUERY_TEXTBRAUN);
      add(labelNumber);
      setBorder(null);
    }



    public void setCount(int c) {
      labelNumber.setText(String.valueOf(c));
    }



    public void setTextBackground(Color color) {
      super.setBackground(color);
    }



    public void setTextForeground(Color color) {
      labelAnwesend.setForeground(color);
      labelNumber.setForeground(color);
    }

  }

  /**
   * 
   */
  private class HeaderRenderer extends JLabel implements TableCellRenderer {
    private static final long serialVersionUID = 1483352116438614471L;

    public HeaderRenderer() {
      setOpaque(true);
    }



    @Override
    public Component getTableCellRendererComponent(JTable table, Object str, boolean isSelected,
        boolean hasFocus, int row, int column) {

      if (column == 0) {
        setBorder(new EmptyBorder(0, 0, 0, 0));
      }

      setBackground(Resource.JQUERY_ORANGE);

      setText((String) str);
      return this;
    }
  }

  class MouseAction extends MouseAdapter {

    int old = -1;
    boolean flag = true;

    @Override
    public void mouseMoved(MouseEvent event) {
      int row = table.rowAtPoint(event.getPoint());

      if (old == row) {
        if (flag) {
          flag = false;
          table.setToolTipText(doubleclick.toString()); // ok
        }
      }
      else {
        flag = true;
        table.setToolTipText(null); // ok
      }
      old = row;
    }



    @Override
    public void mouseReleased(MouseEvent event) {
      Object obj;
      // String nickname; //Vorsicht Nickname ist nicht eindeutig, weil der
      // nickname sich ändern kann
      obj = event.getSource();
      if ((obj.equals(table) && event.getClickCount() >= 2) && (event.getButton() == MouseEvent.BUTTON1)) {
        int selectedRow = table.getSelectedRow();
        String nickname = model.getValueAt(selectedRow, 0).toString();
        changes.firePropertyChange(nickname, Control.NULL, Control.PRIVATECHAT);
      }
    }

  }

  private static final long serialVersionUID = -1258669005473361153L;
  private final static Logger log = LogManager.getLogger(JOnlineOfflinePanel.class);
  // private final static String names [] = {"", /*"First Name",
  // "Last Name", "UID"*/};
  private TableModel3 model = new TableModel3();
  private JTable table = new JTable() {
    @Override
    public JToolTip createToolTip() {
      ToolTipManager.sharedInstance().setInitialDelay(100);
      ToolTipManager.sharedInstance().setDismissDelay(2000);
      ArrowTooltip arrow = new ArrowTooltip(cRenderer.getBackground());
      arrow.setComponent(table);
      arrow.setTextAttributes(GUI.regularFont13, cRenderer.getForeground(), cRenderer.getBackground());
      arrow.setBorder(new JToolTipBorder(7, cRenderer.getForeground(), cRenderer.getBackground(), 2));
      return arrow;
    }
  };
  private JScrollPane scrollTable = new JScrollPane();
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private JTableHeader header;
  private ColorRenderer cRenderer = new ColorRenderer();
  private CountUserPanel countUserPanel = new CountUserPanel();
  private ArrayList<KonferenzraumUser> konferenzraumUser = new ArrayList<>();
  private HeaderRenderer headerrenderer = new HeaderRenderer();
  private MouseAction mouseAction = new MouseAction();
  private MultilingualString doubleclick = new MultilingualString(KEY.STRING_DOPPELKLICKEN);
  private String nickname;

  public JOnlineOfflinePanel() {
    super(true);
    model.setHeader("");
    setLayout(new BorderLayout());
    table.setModel(model);
    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    // table.setAutoResizeMode (JTable.AUTO_RESIZE_OFF);
    header = table.getTableHeader();
    header.setReorderingAllowed(false);
    header.setDefaultRenderer(headerrenderer);
    headerrenderer.setHorizontalAlignment(SwingConstants.CENTER);

    table.setDefaultRenderer(String.class, cRenderer);
    cRenderer.setHorizontalAlignment(SwingConstants.CENTER);
    table.setRowHeight(28);

    scrollTable.setViewportView(table);
    scrollTable.getHorizontalScrollBar().setUnitIncrement(12);
    scrollTable.getVerticalScrollBar().setUnitIncrement(14);

    countUserPanel.setBorder(null);
    add(BorderLayout.NORTH, countUserPanel);
    add(BorderLayout.CENTER, scrollTable);

    scrollTable.setMinimumSize(new Dimension(84, getSize().height));
    scrollTable.setPreferredSize(new Dimension(84, getSize().height));
    scrollTable.setMaximumSize(new Dimension(84, getSize().height));

    scrollTable.setBorder(null);
    scrollTable.getViewport().setBackground(Resource.JQUERY_TEXTBRAUN);

  }



  /**
   * Ändere die Vordergrundfarbe und erhalte die Transparenz. Die übergebene
   * Resource ist ein monochromes PNG, JPEG oder GIF Bild. Der Resourcenstring ist
   * ein Pfad auf das Bild. Beachte, dass ein Resourcenstring mit einem Slash
   * {@code /} beginnt.
   * 
   * @param resource
   *                 dieser Resourcenstring
   * @param color
   *                 diese neue Vordergrundfarbe
   * @return aus einer Resource neu erstelltes BufferedImage
   * @throws IOException
   *                     die Resource konnte nicht verarbeitet und erstellt werden
   */
  public static BufferedImage modifyRGBA(String resource, Color color) throws IOException {

    BufferedImage bufferedimage;
    try(InputStream is = JOnlineOfflinePanel.class.getResourceAsStream(resource)) {
      bufferedimage = ImageIO.read(is);
      Util.modifyRGBA(bufferedimage, color);
    }
    return bufferedimage;
  }



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



  /**
   * Ein Konferenzteilnehmer wird mit seinem Nickname angezeigt.
   * 
   * 
   * @param user
   *             dieser Anwender
   */
  public void addUser(KonferenzraumUser user) {
    Util.Record record = new Util.Record();
    Cell<String> cellNickname = new Cell<>();
    cellNickname.setValue(user.getNickname());
    record.add(cellNickname);
    model.addRow(record);
    konferenzraumUser.add(user);
    countUserPanel.setCount(konferenzraumUser.size());
  }



  /**
   * Die Teilnehmerliste wird gelöscht.
   */
  public void clear() {
    model.removeAll();
    konferenzraumUser.clear();
    countUserPanel.setCount(konferenzraumUser.size());
  }



  public void deinstallMouseListener() {
    table.removeMouseListener(mouseAction);
  }



  /**
   * Gib alle Konferenzteilnehmer zurück.
   * 
   * @return diese Teilnehmer
   */
  public List<KonferenzraumUser> getKonferenzraumTeilnehmer() {
    return konferenzraumUser;
  }



  public String getNickname() {
    return nickname;
  }



  @Override
  public Dimension getPreferredSize() {
    return new Dimension(150, super.getHeight());
  }



  /**
   * Die Maus wird aktiviert.
   */
  public void installMouseListener() {
    table.addMouseListener(mouseAction);
    table.addMouseMotionListener(mouseAction);
    table.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

  }



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



  @Override
  public void setLanguage(ISO639 code) {
    setLanguage(KEY.LABEL_ANWESEND, code);
  }



  public void setLanguage(KEY key, ISO639 code) {
    countUserPanel.labelAnwesend.setLanguage(key, code);
    doubleclick.setLanguage(code);
    table.setToolTipText(doubleclick.toString()); // ok
  }



  // TODO der Nickname kann sich ändern
  /**
   * Der Nickname vom Konferenzteilnehmer(User).
   * 
   * @param nickname
   *                 dieser Nickname
   */
  public void setNickname(String nickname) {
    this.nickname = nickname;
  }



  public void setTopBackground(Color color) {
    countUserPanel.setTextBackground(color);
  }



  public void setTopForeground(Color color) {
    countUserPanel.setTextForeground(color);
  }



  /**
   * Die Hintergrundfarbe wird gewechselt.
   * 
   * @param userid
   *               dieser Anwender
   * @param color
   *               diese neue Hintergrundfarbe
   */
  public void updateBackground(String userid, Color color) {
    // TODO
    // wird relevant, wenn sich der Nickname ändert
    for (int row = 0; row < model.getRowCount(); row++) {
      String value = model.getValueAt(row, 0).toString();
      if (value.equals(userid)) {
//      chatuser[row].setForegroundColor(color.getRGB());
        repaint();
        break;
      }
    }

  }



  /**
   * Der User hat seine Vordergrundfarbe gewechselt.
   * 
   * @param userid
   *               dieser Anwender
   * @param color
   *               diese neue Hintergrundfarbe
   */
  public void updateForeground(String userid, Color color) {
    // TODO
    // wird relevant, wenn sich der Nickname ändert
    for (int row = 0; row < model.getRowCount(); row++) {
      String value = model.getValueAt(row, 0).toString();
      if (value.equals(userid)) {
//        chatuser[row].setForegroundColor(color.getRGB());
        repaint();
        break;
      }
    }

  }

}
