/**
 *  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.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
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.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
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 org.nexuswob.util.Util.Record;
import net.javacomm.client.environment.GUI;
import net.javacomm.multilingual.Babelfish;
import net.javacomm.multilingual.MultilingualString;
import net.javacomm.multilingual.MultilingualTitledBorder;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;
import net.javacomm.protocol.Searchfile;



/**
 * Das Panel ist die Trefferliste aller gefundenen Dateien. Das Panel erscheint
 * auf der linken Seite unterhalb der Ablageorte und rechts von den Suchmustern.
 * 
 * @author lromero
 *
 */
public class JTrefferliste extends JScrollPane implements Babelfish {


  private static final long serialVersionUID = -9192395543567166561L;
//  private TitledBorder border = new TitledBorder(new EmptyBorder(0, 0, 0, 0), "Trefferliste");
  private MultilingualTitledBorder border = new MultilingualTitledBorder(KEY.TITLED_BORDER_TREFFERLISTE);
  private String file, index;
  private MultilingualString multiFilename = new MultilingualString(KEY.STRING_DATEI);
  private MultilingualString waehleDatei = new MultilingualString(KEY.STRING_WAEHLE_EINE_DATEI);

  private DragSource dragsource = new DragSource();
  private JTable table = new JTable() {

    /**
     * 
     */
    private static final long serialVersionUID = 9201902229067631932L;

    @Override
    public JToolTip createToolTip() {
      ToolTipManager.sharedInstance().setInitialDelay(1000);
      ToolTipManager.sharedInstance().setDismissDelay(4000);
      ArrowTooltip arrow = new ArrowTooltip(UIManager.getColor("nimbusSelectionBackground"));
      arrow.setComponent(table);
      arrow.setTextAttributes(
          GUI.regularFont13, UIManager.getColor("text"), UIManager.getColor("nimbusSelectionBackground")
      );
      arrow.setBorder(
          new JToolTipBorder(7, UIManager.getColor("text"), UIManager.getColor("nimbusSelectionBackground"))
      );

      return arrow;
    }

  };
  private TableModel3 model3 = new TableModel3();
  private JTableHeader header;
  private TableColumnModel columnmodel;
  private TableColumn columnIndex;

  public JTrefferliste() {

    table.setModel(model3);
    table.setToolTipText("<html>" + waehleDatei.toString() + "</html>");
    model3.setHeader(Column.FILE.toString(), Column.MB.toString(), Column.INDEX.toString());
    columnmodel = table.getColumnModel();

    TableColumn columnFile = columnmodel.getColumn(Column.FILE.columnNumber);
    columnFile.setPreferredWidth(520);

    columnIndex = columnmodel.getColumn(Column.INDEX.columnNumber);
    columnmodel.getColumn(Column.FILE.columnNumber).setCellRenderer(new DecimalFormatRenderer());
    columnmodel.getColumn(Column.MB.columnNumber).setCellRenderer(new DecimalFormatRenderer());

    TableColumn columnMB = columnmodel.getColumn(Column.MB.columnNumber);
    columnMB.setPreferredWidth(120);

    columnmodel.removeColumn(columnIndex);

    header = table.getTableHeader();
    header.setReorderingAllowed(false);
    // header.setBackground(Color.RED); // ok nicht dargestellter Headerbereich
    header.setForeground(Color.BLACK); // ok real
    header.setOpaque(true);

    header.addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent event) {
        int column = header.columnAtPoint(event.getPoint());
        if (Column.FILE.columnNumber == column) {
          // Sortiere Dateinamen
          Util.quicksort(model3, Util.SortType.ALPHA_NUMERIC, column);
          model3.fireTableRowsUpdated(0, 0);
        }
        else if (Column.MB.columnNumber == column) {
          // sortiere MB
          Util.quicksort(model3, Util.SortType.DECIMAL, column);
          model3.fireTableRowsUpdated(0, 0);
        }
      }
    });



    DefaultTableCellRenderer headerRenderer = (DefaultTableCellRenderer) header.getDefaultRenderer();
    headerRenderer.setHorizontalAlignment(SwingConstants.CENTER);

    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    table.setRowHeight(26);
    table.setFillsViewportHeight(true);
//    table.setPreferredScrollableViewportSize(dim);
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    dragsource.createDefaultDragGestureRecognizer(table, DnDConstants.ACTION_COPY, new DragGestureListener() {
      @Override
      public void dragGestureRecognized(DragGestureEvent event) {
        Object value = null;
        try {
          value = model3.getValueAt(table.getSelectedRow(), Column.FILE.columnNumber);
        }
        catch (IndexOutOfBoundsException e) {
          // Der Fehler kann auftreten, wenn die TAbelle leer ist.
          // Die Api ruft immer
          // public Object getValueAt(int rowIndex, int columnIndex) aus dem
          // TabelModel
          // auf
          return;
        }
        if (value == null) return;
        GefundeneDatei filefound;
        try {
          filefound = new GefundeneDatei(
              value.toString(), (Integer) model3.getValueAt(table.getSelectedRow(), Column.INDEX.columnNumber)
          );
        }
        catch (ClassCastException e) {
          return;
        }
        FileFoundSelection selection = new FileFoundSelection(filefound);
        event.startDrag(null, selection, new DragSourceAdapter() {});
      }
    });

    border.setBorder(new EmptyBorder(0, 0, 0, 0));
    border.setTitlePosition(TitledBorder.ABOVE_TOP);
    border.setTitleJustification(TitledBorder.CENTER);
    setBorder(border);
    this.getViewport().setOpaque(true);
    setViewportView(table);
    this.setOpaque(true);
  }



  public void clear() {
    table.clearSelection();
  }



  /**
   * Alle Tabelleneinträge werden gelöscht.
   */
  void clearModel() {
    model3.removeAll();
  }



  public String getFile() {
    return (file);
  }



  public String getIndex() {
    return (index);
  }



  @Override
  public Dimension getMaximumSize() {
    return new Dimension(500, 260);
  }



  @Override
  public Dimension getPreferredSize() {
    return getMaximumSize();
  }



  /**
   * Der Server hat gerade eine Trefferliste geschickt. Die Trefferliste kann in
   * mehrere Teillisten separiert sein. Wenn {@code hasStarted true} ist, wurde
   * die 1-te Teilliste geschickt. Weitere Teillisten können folgen. Der bisherige
   * Trefferlisteninhalt muss gelöscht werden.
   * 
   * @param file
   * @param hasStarted
   *                   {@code true}, der erste Chunk, sonst der letzte
   */
  public void refresh(Searchfile file[], boolean hasStarted) {
    int count;
    // DecimalFormat descimalFormat = new DecimalFormat("###0.0");
    // DecimalFormat descimalFormat = new DecimalFormat();
    final double mb = 1024 * 1024;

    // descimalFormat.setMaximumFractionDigits(1);
    // descimalFormat.setMinimumFractionDigits(1);
    // descimalFormat.setGroupingSize(4);

    if (hasStarted) clearModel();
    for (Searchfile serachfile : file) {
      Record record = new Record();

      Cell<String> cellFile = new Cell<>();
      cellFile.setValue(serachfile.getFilename());
      record.add(cellFile);

      Cell<Double> cellFilesize = new Cell<>();
      cellFilesize.setValue(serachfile.getFilesize() / mb);
      record.add(cellFilesize);

      Cell<Integer> cellIndex = new Cell<>();
      cellIndex.setValue(serachfile.getIndex());
      record.add(cellIndex);

      model3.addRow(record);

      table.setRowHeight(model3.getRowCount() - 1, 26);
    }

    Util.quicksort(model3, Util.SortType.ALPHA_NUMERIC, 0);
  }

  enum Column {
    FILE("Datei", 0),
    MB("MB", 1),
    INDEX("Index", 2);

    private String columnName;
    private int columnNumber;

    private Column(String value, int columnNumber) {
      columnName = value;
      this.columnNumber = columnNumber;
    }



    @Override
    public String toString() {
      return columnName;
    }

  }

  private class DecimalFormatRenderer extends DefaultTableCellRenderer {
    private static final long serialVersionUID = -4939992203031507014L;
    private final DecimalFormat formatter = new DecimalFormat("####0.0");

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

      // First format the cell value as required

      if (column == Column.MB.columnNumber) {
        value = formatter.format(value);
        // And pass it on to parent class
        this.setHorizontalAlignment(SwingConstants.CENTER);
      }


      if (value != null) setText(value.toString());
      if (isSelected) {
        setBackground(UIManager.getColor("nimbusSelectionBackground")); // ok
        setForeground(UIManager.getColor("text"));
      }
      else {
        setBackground(UIManager.getColor("Table.background"));
        setForeground(UIManager.getColor("TextField.textForeground"));
      }
      return this;
    }
  }

  @Override
  public void setLanguage(ISO639 code) {
    // TODO Auto-generated method stub
    border.setLanguage(code);
    multiFilename.setLanguage(code);
    columnmodel.getColumn(Column.FILE.columnNumber).setHeaderValue(multiFilename.toString());
    waehleDatei.setLanguage(code);
    table.setToolTipText("<html>" + waehleDatei.toString() + "</html>");

  }

}
