package be.msyben.vinylManager.tools.swing;

import be.msyben.vinylManager.entities.Album;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.util.Vector;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.border.LineBorder;
import be.msyben.vinylManager.entities.Titre;
import be.msyben.vinylManager.gui.icon.Icons;
import be.msyben.vinylManager.properties.Preferences;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.Border;

/**
 * Ma classe pour les JList.
 *
 * @author Mathieu Syben
 */
public class MyJList<E> extends JList<E> {

    private static final long serialVersionUID = 5345478L;

    public MyJList() {
        super();
        setCommons();
    }

    public MyJList(Vector<E> listData) {
        super(listData);
        setCommons();
    }

    public MyJList(E[] listData) {
        super(listData);
        setCommons();
    }

    public MyJList(ListModel<E> dataModel) {
        super(dataModel);
        setCommons();
    }

    private void setCommons() {
        ListCellRenderer<E> listTitreCellRenderer = new ListCellRenderer<>() {
            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {

                JLabel jla;

                if (value instanceof Titre) {
                    Titre t = (Titre) value;
                    jla = getComponent(t);
                } else if (value instanceof Album) {
                    Album a = (Album) value;
                    String duree = a.getDureeTotale();
                    boolean showDuration = Preferences.getInstance().get(Preferences.DISPLAY_DURATION_ALBUM, "N").equalsIgnoreCase("Y");
        
                    String annee = a.getAnnee();
                    if (a.getAnneeParution() != null && !a.getAnneeParution().isEmpty()) {
                        annee += " ("+a.getAnneeParution()+")";
                    }
                    
                    if (showDuration && duree != null)   {
                        jla = new JLabel(annee + " - " + a.getTitre() + " (" + duree + ")");
                    } else {
                        jla = new JLabel(annee + " - " + a.getTitre());
                    }
                    if (!a.getPossede()) {
                        jla.setForeground(Color.RED);
                    }
                } else {
                    jla = new JLabel(value.toString());
                }
                Font f = new Font(jla.getFont().getName(), Font.PLAIN, jla.getFont().getSize());
                jla.setFont(f);
                Border paddingBorder = BorderFactory.createEmptyBorder(1, 2, 1, 0);
                if (isSelected) {
                    jla.setBackground(new Color(184, 207, 229));
                    jla.setOpaque(true);
                    if (cellHasFocus) {
                        Border b = BorderFactory.createCompoundBorder(new LineBorder(new Color(99, 130, 191), 1), paddingBorder);
                        jla.setBorder(b);
                    } else {
                        jla.setBorder(paddingBorder);
                    }
                } else {
                    jla.setBorder(paddingBorder);
                }
                return jla;
            }
        };

        setCellRenderer(listTitreCellRenderer);
    }

    private JLabel getComponent(Titre t) {
        ImageIcon lyrics, link;

        if (t.getLyrics() != null && !t.getLyrics().isEmpty()) {
            lyrics = Icons.getInstance().pen;
        } else {
            lyrics = Icons.getInstance().penVide;
        }
        if (t.getLinkedFilePath() != null && !t.getLinkedFilePath().isEmpty()) {
            link = Icons.getInstance().link;
        } else {
            link = Icons.getInstance().linkVide;
        }




        JLabel ret = new JLabel(t.toString(), new CachedCompositeIcon(lyrics, link).getIcon(), JLabel.CENTER);
        ret.setVerticalTextPosition(JLabel.CENTER);
        ret.setHorizontalTextPosition(JLabel.LEFT);
        ret.setHorizontalAlignment(JLabel.LEFT);

        return ret;
    }

    /**
     * This is a convenience class to handle creating a single composite icon
     * from several icons, and caching the created icons to eliminate duplicate
     * work. This class is basically used as a key into a map, allowing us to
     * define both a hashCode and equals in a single place.
     */
    private static class CachedCompositeIcon {

        private static final byte ICON_PADDING = 2;
        private static final Map<CachedCompositeIcon, ImageIcon> CACHED_ICONS =
                new HashMap<CachedCompositeIcon, ImageIcon>();
        private final ImageIcon[] m_icons;

        public CachedCompositeIcon(final ImageIcon... icons) {
            m_icons = icons;
        }

        public ImageIcon getIcon() {
            if (!CACHED_ICONS.containsKey(this)) {
                CACHED_ICONS.put(this, lcl_combineIcons());
            }

            return CACHED_ICONS.get(this);
        }

        /**
         * Generates an icon that is a composition of several icons by appending
         * each icon together with some padding between them.
         *
         * @return An icon that is the concatenation of all the icons this was
         *         constructed with.
         */
        private ImageIcon lcl_combineIcons() {
            // First determine how big our composite icon will be; we need to know how wide & tall to make it.
            int totalWidth = (m_icons.length - 1) * ICON_PADDING; // Take into account the padding between icons
            int minHeight = 0;
            for (int i = 0; i < m_icons.length; ++i) {
                totalWidth += m_icons[i].getIconWidth();
                if (m_icons[i].getIconHeight() > minHeight) {
                    minHeight = m_icons[i].getIconHeight();
                }
            }

            // Create an image big enough and acquire the image canvas to draw on
            final BufferedImage compositeImage = new BufferedImage(totalWidth, minHeight, BufferedImage.TYPE_INT_ARGB);
            final Graphics graphics = compositeImage.createGraphics();

            // Iterate over the icons, painting each icon and adding some padding space between them
            int x = 0;
            for (int i = 0; i < m_icons.length; ++i) {
                final ImageIcon icon = m_icons[ i];
                graphics.drawImage(icon.getImage(), x, 0, null);
                x += icon.getIconWidth() + ICON_PADDING;
            }

            return new ImageIcon(compositeImage);
        }

        /**
         * Generates a hash that takes into account the number of icons this
         * composition includes and the hash & order of those icons.
         *
         * @return A hash code.
         */
        @Override
        public int hashCode() {
            int weakHash = m_icons.length;
            for (int i = 0; i < m_icons.length; ++i) {
                weakHash += m_icons[i].hashCode() * (i + 1);
            }
            return weakHash;
        }

        /**
         * Two instances are equal if and only if they include the same icons
         * and they're in the same order.
         *
         * @param obj An object to check for equality with this.
         *
         * @return true if the two objects are equal, false otherwise.
         */
        @Override
        public boolean equals(final Object obj) {
            if (!(obj instanceof CachedCompositeIcon)) {
                return false;
            }

            final CachedCompositeIcon other = (CachedCompositeIcon) obj;
            if (m_icons.length != other.m_icons.length) {
                return false;
            }

            for (int i = 0; i < m_icons.length; ++i) {
                if (m_icons[i].hashCode() != other.m_icons[i].hashCode()) {
                    return false;
                }
            }

            return true;
        }
    }
}
