package be.msyben.vinylManager.gui;

import be.msyben.vinylManager.controller.Controller;
import be.msyben.vinylManager.entities.Album;
import be.msyben.vinylManager.exceptions.VinylManagerException;
import be.msyben.vinylManager.gui.icon.Icons;
import be.msyben.vinylManager.interfaces.WaitListener;
import be.msyben.vinylManager.properties.Language;
import be.msyben.vinylManager.properties.Preferences;
import be.msyben.vinylManager.tools.Tools;
import be.msyben.vinylManager.tools.WaitThread;
import be.msyben.vinylManager.tools.discogs.DiscogsSearch;
import be.msyben.vinylManager.tools.discogs.DiscogsSearchResult;
import be.msyben.vinylManager.tools.log.VinylManagerLogger;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;

/**
 * Fenêtre de recherche avec Discogs.
 *
 * @author Mathieu Syben
 */
public class DiscogsSearchWindow extends JFrame {

    private static final long serialVersionUID = 348264732824l;
    private Controller controller;
    private DiscogsSearchResult selection;
    private JWindow image;
    private JTextField artiste = new JTextField();
    private JTextField titre = new JTextField();
    private JTextField ref = new JTextField();
    private JTextField barcode = new JTextField();
    private JTextField idDiscogs = new JTextField();
    private MyTableModel model = new MyTableModel();
    private JButton valider = new JButton(Language.getInstance().get("button.valider"));

    private DiscogsSearchWindow() {
    }

    /**
     * Constructeur.
     *
     * @param controller Le controlleur.
     */
    public DiscogsSearchWindow(Controller controller) {
        super(Language.getInstance().get("discogs.window.title"));
        MainWindow.getInstance().setEnabled(false);
        this.controller = controller;
        setIconImage(Icons.getInstance().icon.getImage());

        this.setSize(720, 610); // On donne une taille à notre fenêtre
        this.setLocationRelativeTo(null); // On centre la fenêtre sur l'ecran
        this.setResizable(false); // On interdit la redimensionnement de la fenêtre
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // On dit à l'application de se fermer

        putElements();

        setVisible(true);
        repaint();
    }

    private WaitThread getWaitThread() {
        final WaitThread waitThread = new WaitThread();
        waitThread.addWaitListener(new WaitListener() {
            @Override
            public void onCancel() {
                waitThread.arrete();
            }
        });
        return waitThread;
    }

    private void putElements() {
        Container c = this.getContentPane();
        c.setLayout(null);
        c.setSize(720, 610);

        final JLabel artisteL = new JLabel(Language.getInstance().get("name.artiste"));
        final JLabel titreL = new JLabel(Language.getInstance().get("name.titre"));
        final JLabel refL = new JLabel(Language.getInstance().get("name.reference"));
        final JLabel barcodeL = new JLabel("Barcode");
        final JLabel idDiscogsL = new JLabel(Language.getInstance().get("name.id.discogs"));

        final JLabel imageLabel = new JLabel();

        final JTable results = new JTable(model);
        final JScrollPane jsp = new JScrollPane(results);
        final JButton annuler = new JButton(Language.getInstance().get("button.annuler"));
        valider.setEnabled(false);




        refL.setBounds(5, 10, 100, 20);
        ref.setBounds(105, 5, 200, 25);
        c.add(ref);
        c.add(refL);

        ref.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    buttonSearchCodePressed();
                }
            }
        });
        JButton searchRef = new JButton(Language.getInstance().get("button.rechercher"));
        searchRef.setBounds(330, 5, 150, 25);
        c.add(searchRef);
        searchRef.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                buttonSearchCodePressed();

            }
        });

        barcodeL.setBounds(5, 45, 100, 20);
        barcode.setBounds(105, 40, 200, 25);
        c.add(barcode);
        c.add(barcodeL);

        barcode.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    buttonSearchBarCodePressed();
                }
            }
        });
        JButton searchBarcode = new JButton(Language.getInstance().get("button.rechercher"));
        searchBarcode.setBounds(330, 40, 150, 25);
        c.add(searchBarcode);
        searchBarcode.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                buttonSearchBarCodePressed();

            }
        });
        
        
        
        artisteL.setBounds(5, 80, 100, 20);
        artiste.setBounds(105, 75, 200, 25);
        titreL.setBounds(5, 115, 100, 20);
        titre.setBounds(105, 110, 200, 25);
        c.add(artisteL);
        c.add(artiste);
        c.add(titreL);
        c.add(titre);
        artiste.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    buttonSearchNamePressed();
                }
            }
        });
        titre.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    buttonSearchNamePressed();
                }
            }
        });
        JButton searchArt = new JButton(Language.getInstance().get("button.rechercher"));
        searchArt.setBounds(330, 75, 150, 25);
        c.add(searchArt);
        searchArt.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                buttonSearchNamePressed();
            }
        });

        idDiscogsL.setBounds(5, 150, 100, 20);
        idDiscogs.setBounds(105, 145, 200, 25);
        c.add(idDiscogs);
        c.add(idDiscogsL);

        idDiscogs.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    buttonAddPressed();
                }
            }
        });
        JButton addDiscogs = new JButton(Language.getInstance().get("button.add"));
        addDiscogs.setBounds(330, 145, 150, 25);
        c.add(addDiscogs);
        addDiscogs.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                buttonAddPressed();
            }
        });

        imageLabel.setBorder(new LineBorder(Color.black, 1));
        imageLabel.setBounds(525, 5, 160, 160);
        c.add(imageLabel);

        results.setAutoCreateRowSorter(true);
        for (int i = 0; i < results.getColumnModel().getColumnCount(); i++) {
            String sizeS = Preferences.getInstance().get("discogs.column.size." + i);
            if (sizeS == null || sizeS.isEmpty()) {
                continue;
            }
            try {
                int size = Integer.parseInt(sizeS);
                results.getColumnModel().getColumn(i).setPreferredWidth(size);
                results.getColumnModel().getColumn(i).setWidth(size);
            } catch (NumberFormatException ex) {
                continue;
            }
        }


        //results.getColumnModel().getColumn(1).setWidth(WIDTH);
        results.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
            @Override
            public void columnAdded(TableColumnModelEvent e) {
            }

            @Override
            public void columnRemoved(TableColumnModelEvent e) {
            }

            @Override
            public void columnMoved(TableColumnModelEvent e) {
            }

            @Override
            public void columnMarginChanged(ChangeEvent e) {
                TableColumnModel model = (TableColumnModel) e.getSource();
                for (int i = 0; i < model.getColumnCount(); i++) {
                    Preferences.getInstance().set("discogs.column.size." + i, "" + model.getColumn(i).getWidth());
                }
            }

            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {
            }
        });

        MouseAdapter mouseAdapter = new MouseAdapter() {
            //private int lastRow = -1;
            //private Timer timer = new Timer();
            //private TimerTask timerTask;
            @Override
            public void mouseClicked(MouseEvent e) {
                int row = results.convertRowIndexToModel(results.getSelectedRow());
                selection = model.getResult(row);
                valider.setEnabled(true);
                if (e.getClickCount() == 1) {
                    imageLabel.setIcon(null);
                    byte[] thumb = selection.getThumbImage(DiscogsSearchWindow.this);
                    if (thumb != null) {
                        try {
                            VinylManagerLogger.log("Thumbnail : " + thumb.length);
                            imageLabel.setIcon(new ImageIcon(Tools.getResizedImage(thumb, 160, 160)));
                        } catch (VinylManagerException ex) {
                            VinylManagerLogger.log(ex);

                        }
                    }
                }
                if (e.getClickCount() == 2) {
                    add(selection.getDiscogsId());
                }
            }
        };
        results.addMouseListener(mouseAdapter);
        results.addMouseMotionListener(mouseAdapter);

        jsp.setBounds(5, 200, 685, 300);
        c.add(jsp);

        annuler.setBounds(105, 530, 200, 25);
        c.add(annuler);
        annuler.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (image != null) {
                    image.dispose();
                }
                DiscogsSearchWindow.this.dispose();
                MainWindow.getInstance().toFront();
                MainWindow.getInstance().setEnabled(true);
            }
        });
        valider.setBounds(390, 530, 200, 25);
        c.add(valider);
        valider.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                add(selection.getDiscogsId());
            }
        });
    }

    private void buttonSearchBarCodePressed() {
        if (barcode.getText() == null || barcode.getText().isEmpty()) {
            new ErrorWindow(DiscogsSearchWindow.this, Language.getInstance().get("discogs.search.empty.barcode"));
            return;
        }
        final WaitThread waitThread = getWaitThread();
        waitThread.start();
        new Thread() {
            @Override
            public void run() {
                try {
                    List<DiscogsSearchResult> res = DiscogsSearch.searchBarcode(barcode.getText(), DiscogsSearchWindow.this);
                    if (waitThread.isRunning()) {
                        model.setResults(res);
                        selection = null;
                        valider.setEnabled(false);
                        waitThread.arrete();
                    }
                } catch (VinylManagerException ex) {
                    waitThread.arrete();
                    VinylManagerLogger.log(ex);
                    new ErrorWindow(DiscogsSearchWindow.this, ex.getMessage(), ex);
                }
            }
        }.start();
    }
    
    private void buttonSearchCodePressed() {
        if (ref.getText() == null || ref.getText().isEmpty()) {
            new ErrorWindow(DiscogsSearchWindow.this, Language.getInstance().get("discogs.search.empty.ref"));
            return;
        }
        final WaitThread waitThread = getWaitThread();
        waitThread.start();
        new Thread() {
            @Override
            public void run() {
                try {
                    List<DiscogsSearchResult> res = DiscogsSearch.searchRef(ref.getText(), DiscogsSearchWindow.this);
                    if (waitThread.isRunning()) {
                        model.setResults(res);
                        selection = null;
                        valider.setEnabled(false);
                        waitThread.arrete();
                    }
                } catch (VinylManagerException ex) {
                    waitThread.arrete();
                    VinylManagerLogger.log(ex);
                    new ErrorWindow(DiscogsSearchWindow.this, ex.getMessage(), ex);
                }
            }
        }.start();
    }

    private void buttonSearchNamePressed() {
        if (artiste.getText() == null || artiste.getText().isEmpty()) {
            new ErrorWindow(DiscogsSearchWindow.this, Language.getInstance().get("discogs.search.empty.artiste"));
            return;
        }
        if (titre.getText() == null || titre.getText().isEmpty()) {
            new ErrorWindow(DiscogsSearchWindow.this, Language.getInstance().get("discogs.search.empty.titre"));
            return;
        }
        final WaitThread waitThread = getWaitThread();
        waitThread.start();
        new Thread() {
            @Override
            public void run() {
                try {
                    List<DiscogsSearchResult> res = DiscogsSearch.searchArtist(artiste.getText(), titre.getText(), DiscogsSearchWindow.this);
                    if (waitThread.isRunning()) {
                        model.setResults(res);
                        selection = null;
                        valider.setEnabled(false);
                        waitThread.arrete();
                    }
                } catch (VinylManagerException ex) {
                    waitThread.arrete();
                    VinylManagerLogger.log(ex);
                    new ErrorWindow(DiscogsSearchWindow.this, ex.getMessage(), ex);
                }
            }
        }.start();
    }

    private void buttonAddPressed() {
        if (idDiscogs.getText() == null || idDiscogs.getText().isEmpty()) {
            new ErrorWindow(DiscogsSearchWindow.this, Language.getInstance().get("discogs.search.empty.id"));
            return;
        }
        try {
            long discogsId = Long.parseLong(idDiscogs.getText());        
            add(discogsId);
        } catch(NumberFormatException e) {
            new ErrorWindow(DiscogsSearchWindow.this, Language.getInstance().get("discogs.search.empty.id"));
            return;
        }
    }

    /**
     * Ajout d'un album sélectionné à la collection.
     */
    private void add(final long discogsId) {
        final WaitThread waitThread = getWaitThread();
        waitThread.start();
        new Thread() {
            @Override
            public void run() {
                try {
                    Album a = DiscogsSearch.getAlbum(discogsId, DiscogsSearchWindow.this);
                    if (a == null) {
                        waitThread.arrete();
                        new ErrorWindow(DiscogsSearchWindow.this, Language.getInstance().get("discogs.download.error"));
                    }
                    if (waitThread.isRunning()) {
                        controller.addAlbum(a);
                        if (image != null) {
                            image.dispose();
                        }
                        DiscogsSearchWindow.this.dispose();
                        MainWindow.getInstance().toFront();
                        MainWindow.getInstance().setEnabled(true);
                        waitThread.arrete();
                    }
                } catch (VinylManagerException ex) {
                    waitThread.arrete();
                    VinylManagerLogger.log(ex);
                    new ErrorWindow(DiscogsSearchWindow.this, ex.getMessage(), ex);
                }
            }
        }.start();
    }

    /**
     * Modèle pour la représentation des résultats.
     */
    private static class MyTableModel extends AbstractTableModel {

        private List<DiscogsSearchResult> results;
        private String[] titres = new String[]{
            Language.getInstance().get("name.titre"),
            Language.getInstance().get("name.editeur"),
            Language.getInstance().get("name.reference"),
            Language.getInstance().get("name.annee"),
            Language.getInstance().get("name.genre"),
            Language.getInstance().get("name.support"),
            Language.getInstance().get("name.pays")};

        public MyTableModel() {
            results = new ArrayList<DiscogsSearchResult>();
        }

        @Override
        public int getRowCount() {
            return results.size();
        }

        @Override
        public int getColumnCount() {
            return titres.length;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            DiscogsSearchResult r = results.get(rowIndex);
            switch (columnIndex) {
                case 0:
                    return r.getTitre();
                case 1:
                    return r.getLabel();
                case 2:
                    return r.getReference();
                case 3:
                    return r.getAnnee();
                case 4:
                    return r.getGenre();
                case 5:
                    return r.getFormat();
                case 6:
                    return r.getPays();
                default:
                    return "ERREUR";
            }
        }

        @Override
        public String getColumnName(int col) {
            return titres[col];
        }

        /**
         * Mise à jour du résultat.
         *
         * @param results les résultats.
         */
        public void setResults(List<DiscogsSearchResult> results) {
            this.results = results;
            fireTableDataChanged();
        }

        /**
         * Récupération du résultat.
         *
         * @param idx L'index dans le liste.
         * @return Le résultat à l'index demandé.
         */
        public DiscogsSearchResult getResult(int idx) {
            return results.get(idx);
        }
    }

    /**
     * Affichage du popup avec la miniature de l'image.
     */
    class PopupThumb extends JWindow {

        private ImageIcon image;

        private PopupThumb() {
        }

        /**
         * Constructeur.
         *
         * @param imageData Le contenu de l'image.
         */
        public PopupThumb(byte[] imageData) {
            super();
            this.image = new ImageIcon(imageData);
            this.setLayout(null);
            this.setSize(image.getIconWidth(), image.getIconHeight());
            JLabel label = new JLabel();
            label.setIcon(image);
            label.setBounds(0, 0, image.getIconWidth(), image.getIconHeight());
            label.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    PopupThumb.this.dispose();
                }
            });
            this.getContentPane().add(label);
            setVisible(true);
        }
    }
}
