package yukihane.inqubus.gui;

import static yukihane.inqubus.InqubusConstants.*;

import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.regex.Matcher;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import javax.swing.text.JTextComponent;
import org.apache.commons.io.FilenameUtils;
import yukihane.inqubus.filewatch.FileWatch;
import yukihane.inqubus.filewatch.FileWatchUtil;

final class IdComboBox extends JComboBox<String> {

    private static final long serialVersionUID = 1L;
    private static final Logger logger = LoggerFactory.getLogger(IdComboBox.class);
    private final Set<Path> alternates = new HashSet<>();
    private final FileWatch videoFileWatcher;

    IdComboBox(FileWatch videoFileWather) {
        super();
        this.videoFileWatcher = videoFileWather;
        setEditable(true);
        setSelectedIndex(-1);
        getEditorComponent().setTransferHandler(new IdTransferHander(getEditorComponent().getTransferHandler()));
        getEditorComponent().addKeyListener(new AutoCompleteAdapter());
        getEditorComponent().addFocusListener(new FocusAdapter() {

            @Override
            public void focusGained(FocusEvent e) {
                setAlternates(videoFileWatcher.getFiles());
            }
        });

    }

    JTextField getEditorComponent() {
        return (JTextField) getEditor().getEditorComponent();
    }

    void setAlternates(Collection<Path> alternates) {
        this.alternates.clear();
        this.alternates.addAll(alternates);
    }

    String getText() {
        return getEditorComponent().getText();
    }

    void setText(String str) {
        getEditorComponent().setText(str);
    }

    private class AutoCompleteAdapter extends KeyAdapter {

        @Override
        public void keyTyped(final KeyEvent e) {
            EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    final String text = getText();
                    final SortedSet<String> alt = FileWatchUtil.getVideoIdsStartWith(alternates, text);
                    final String[] altArray = alt.toArray(new String[0]);
                    DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>(altArray);
                    IdComboBox.this.setModel(model);
                    setSelectedIndex(-1);
                    setText(text);
                    IdComboBox.this.showPopup();
                }
            });
        }
    }
}

class IdTransferHander extends TransferHandler {

    private static final long serialVersionUID = 1L;
    private static final Logger logger = LoggerFactory.getLogger(IdTransferHander.class);
    private static final DataFlavor URL_FLAVOR;

    static {
        try {
            URL_FLAVOR = new DataFlavor("application/x-java-url; class=java.net.URL");
        } catch (ClassNotFoundException ex) {
            throw new IllegalStateException(ex);
        }
    }
    private final TransferHandler defaultTransferHandler;

    IdTransferHander(TransferHandler defaultTransferHandler) {
        this.defaultTransferHandler = defaultTransferHandler;
    }

    @Override
    public boolean canImport(TransferHandler.TransferSupport support) {
        if (logger.isTraceEnabled()) {
            for (DataFlavor df : support.getDataFlavors()) {
                logger.trace(df.toString() + ", " + df.getClass().getName());
            }
        }

        if (support.isDataFlavorSupported(DataFlavor.stringFlavor)
                || support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            if (support.isDrop()) {
                support.setDropAction(LINK);
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean importData(TransferHandler.TransferSupport support) {
        try {
            String targetText;
            if (support.isDataFlavorSupported(URL_FLAVOR)) {
                final URL url = (URL) support.getTransferable().getTransferData(URL_FLAVOR);
                targetText = url.getPath();
            } else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                @SuppressWarnings("unchecked")
                final List<File> files = (List<File>) support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
                if (!files.isEmpty()) {
                    final File file = files.get(0);
                    targetText = FilenameUtils.getBaseName(file.getPath());
                } else {
                    return false;
                }
            } else if (support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                targetText = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor);
            } else {
                return false;
            }

            final Matcher matcher = PATTERN_VIDEO_ID.matcher(targetText);
            if (matcher.find()) {
                final String text = matcher.group(1);
                final JTextComponent component = (JTextComponent) support.getComponent();
                component.setText(text);
                return true;
            }
        } catch (UnsupportedFlavorException | IOException ex) {
            logger.error(null, ex);
        }
        return false;
    }
}
