package net.seesharpsoft.intellij.plugins.csv.editor.table.swing;

import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.util.UserDataHolder;
import net.seesharpsoft.intellij.plugins.csv.editor.CsvEditorSettingsExternalizable;
import net.seesharpsoft.intellij.plugins.csv.settings.CsvColorSettings;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.util.Collections;
import java.util.EventObject;
import java.util.HashSet;
import java.util.Set;

public class MultiLineCellRenderer extends JTextArea implements TableCellRenderer, TableCellEditor {

    private Set<CellEditorListener> cellEditorListenerSet = new HashSet<>();
    private final UserDataHolder userDataHolder;

    public MultiLineCellRenderer(CsvTableEditorKeyListener keyListener, UserDataHolder userDataHolderParam) {
        setLineWrap(true);
        setWrapStyleWord(true);
        setOpaque(true);
        addKeyListener(keyListener);
        this.userDataHolder = userDataHolderParam;
    }

    private TextAttributes getColumnTextAttributes(int column) {
        if (CsvEditorSettingsExternalizable.getInstance().isTableColumnHighlightingEnabled()) {
            return CsvColorSettings.getTextAttributesOfColumn(column, userDataHolder);
        }
        return null;
    }

    private Color getColumnForegroundColor(int column, Color fallback) {
        TextAttributes textAttributes = getColumnTextAttributes(column);
        return textAttributes == null || textAttributes.getForegroundColor() == null ? fallback : textAttributes.getForegroundColor();
    }

    private Color getColumnBackgroundColor(int column, Color fallback) {
        TextAttributes textAttributes = getColumnTextAttributes(column);
        return textAttributes == null || textAttributes.getBackgroundColor() == null ? fallback : textAttributes.getBackgroundColor();
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        if (isSelected) {
            setForeground(table.getSelectionForeground());
            setBackground(table.getSelectionBackground());
        } else {
            setForeground(getColumnForegroundColor(column, table.getForeground()));
            setBackground(getColumnBackgroundColor(column, table.getBackground()));
        }
        setFont(table.getFont());
        if (hasFocus) {
            setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
            if (table.isCellEditable(row, column)) {
                setForeground(UIManager.getColor("Table.focusCellForeground"));
                setBackground(UIManager.getColor("Table.focusCellBackground"));
            }
        } else {
            setBorder(new EmptyBorder(1, 2, 1, 2));
        }
        setText((value == null) ? "" : value.toString());

        final int columnWidth = table.getColumnModel().getColumn(column).getWidth();
        final int rowHeight = table.getRowHeight(row);
        this.setSize(columnWidth, rowHeight);
        this.validate();

        return this;
    }

    @Override
    public Dimension getPreferredSize() {
        try {
            final Rectangle rectangle = this.modelToView(getDocument().getLength());
            if (rectangle != null) {
                return new Dimension(this.getWidth(),
                        this.getInsets().top + rectangle.y + rectangle.height +
                                this.getInsets().bottom);
            }
        } catch (BadLocationException e) {
            e.printStackTrace();
        }

        return super.getPreferredSize();
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        return getTableCellRendererComponent(table, value, isSelected, true, row, column);
    }

    @Override
    public Object getCellEditorValue() {
        return this.getText();
    }

    @Override
    public boolean isCellEditable(EventObject anEvent) {
        return true;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        return true;
    }

    @Override
    public boolean stopCellEditing() {
        fireStopCellEditing();
        return true;
    }

    @Override
    public void cancelCellEditing() {
        fireCancelCellEditing();
    }

    protected void fireStopCellEditing() {
        ChangeEvent changeEvent = new ChangeEvent(this);
        Collections.synchronizedSet(cellEditorListenerSet).forEach(cellEditorListener -> cellEditorListener.editingStopped(changeEvent));
    }

    protected void fireCancelCellEditing() {
        ChangeEvent changeEvent = new ChangeEvent(this);
        Collections.synchronizedSet(cellEditorListenerSet).forEach(cellEditorListener -> cellEditorListener.editingCanceled(changeEvent));
    }

    @Override
    public void addCellEditorListener(CellEditorListener cellEditorListener) {
        cellEditorListenerSet.add(cellEditorListener);
    }

    @Override
    public void removeCellEditorListener(CellEditorListener cellEditorListener) {
        cellEditorListenerSet.remove(cellEditorListener);
    }
}
@@ -641,97 +641,9 @@
 til.
-Collections;%0Aimport java.util.EventObject;%0Aimport java.util.HashSet;%0Aimport java.util.Set
+*
 ;%0A%0Ap
@@ -799,24 +799,52 @@
 stenerSet = 
+Collections.synchronizedSet(
 new HashSet%3C
@@ -846,16 +846,17 @@
 hSet%3C%3E()
+)
 ;%0A    pr
@@ -4636,36 +4636,24 @@
 s);%0A        
-Collections.
 synchronized
@@ -4644,35 +4644,33 @@
     synchronized
-Set
+ 
 (cellEditorListe
@@ -4672,34 +4672,48 @@
 ListenerSet)
-.forEach(c
+ %7B%0A           Iterator%3CC
 ellEditorLis
@@ -4709,35 +4709,38 @@
 llEditorListener
- -%3E
+%3E it =
  cellEditorListe
@@ -4734,32 +4734,106 @@
 llEditorListener
+Set.iterator();%0A           while (it.hasNext()) %7B%0A               it.next()
 .editingStopped(
@@ -4836,34 +4836,55 @@
 ped(changeEvent)
-)
 ;
+%0A           %7D%0A       %7D
 %0A    %7D%0A%0A    prot
@@ -4985,28 +4985,16 @@
         
-Collections.
 synchron
@@ -4997,19 +4997,17 @@
 hronized
-Set
+ 
 (cellEdi
@@ -5025,18 +5025,33 @@
 Set)
-.forEach(c
+ %7B%0A            Iterator%3CC
 ellE
@@ -5067,11 +5067,14 @@
 ener
- -%3E
+%3E it =
  cel
@@ -5088,16 +5088,92 @@
 Listener
+Set.iterator();%0A            while (it.hasNext()) %7B%0A                it.next()
 .editing
@@ -5193,18 +5193,41 @@
 geEvent)
-)
 ;
+%0A            %7D%0A        %7D
 %0A    %7D%0A%0A
@@ -5542,8 +5542,9 @@
 %0A    %7D%0A%7D
+%0A

synchronize iteration