/*
 * jNPad v0.3 - jNPad's an Simple Text Editor written in Java
 *
 * Copyright (C) 2014-2017  rgs
 *
 * Require JDK 1.6 (or later)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 *
 * Info, Questions, Suggestions & Bugs Report to rgsevero@gmail.com
 */

package jnpad.text;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;

import javax.swing.JComponent;
import javax.swing.TransferHandler;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;

import jnpad.JNPadFrame;

/**
 * The Class JNPadTransferHandler.
 *
 * @version 0.3
 * @since   jNPad v0.1
 */
public class JNPadTransferHandler extends TransferHandler {
  private JTextComponent      exportComp;
  private boolean             shouldRemove;

  // Start and end position in the source text.
  // We need this information when performing a MOVE
  // in order to remove the dragged text from the source.
  private Position            p0               = null;
  private Position            p1               = null;

  private JNPadFrame          jNPad;

  /** Logger */
  private static final Logger LOGGER           = Logger.getLogger(JNPadTransferHandler.class.getName());

  /** UID */
  private static final long   serialVersionUID = 1231193598766229947L;

  /**
   * Instantiates a new jN pad transfer handler.
   *
   * @param jNPad JNPadFrame
   */
  public JNPadTransferHandler(JNPadFrame jNPad) {
    this.jNPad = jNPad;
  }

  /**
   * Gets the source actions.
   *
   * @param c the c
   * @return the source actions
   * @see javax.swing.TransferHandler#getSourceActions(javax.swing.JComponent)
   */
  @Override
  public int getSourceActions(JComponent c) {
    if ( ( (JTextComponent) c).isEditable()) {
      return COPY_OR_MOVE;
    }
    return COPY;
  }

  /**
   * Creates the transferable.
   *
   * @param c the c
   * @return the transferable
   * @see javax.swing.TransferHandler#createTransferable(javax.swing.JComponent)
   */
  @Override
  protected Transferable createTransferable(JComponent c) {
    exportComp = (JTextComponent) c;
    int start = exportComp.getSelectionStart();
    int end = exportComp.getSelectionEnd();
    Document doc = exportComp.getDocument();
    if (start == end) {
      return null;
    }
    try {
      p0 = doc.createPosition(start);
      p1 = doc.createPosition(end);
    }
    catch (BadLocationException ex) {
      LOGGER.warning("Can't create position - unable to remove text from source."); //$NON-NLS-1$
    }
    shouldRemove = true;
    String data = exportComp.getSelectedText();
    return new StringSelection(data);
  }

  /**
   * Export done.
   *
   * @param source the source
   * @param data the data
   * @param action the action
   * @see javax.swing.TransferHandler#exportDone(javax.swing.JComponent, java.awt.datatransfer.Transferable, int)
   */
  @Override
  protected void exportDone(JComponent source, Transferable data, int action) {
    // only remove the text if shouldRemove has not been set to
    // false by importData and only if the action is a move
    if (shouldRemove && action == MOVE) {
      if (p0 != null && p1 != null && p0.getOffset() != p1.getOffset()) {
        try {
          JTextComponent tc = (JTextComponent) source;
          tc.getDocument().remove(p0.getOffset(), p1.getOffset() - p0.getOffset());
        }
        catch (BadLocationException e) {
          LOGGER.warning("Can't remove text from source."); //$NON-NLS-1$
        }
      }

    }
    exportComp = null;
  }

  /**
   * Can import.
   *
   * @param comp the comp
   * @param flavors the flavors
   * @return true, if successful
   * @see javax.swing.TransferHandler#canImport(javax.swing.JComponent, java.awt.datatransfer.DataFlavor[])
   */
  @Override
  public boolean canImport(JComponent comp, DataFlavor[] flavors) {
    JTextComponent tc = (JTextComponent) comp;
    return tc.isEditable() && tc.isEnabled() && (hasFileFlavor(flavors) || hasStringFlavor(flavors));
  }

  /**
   * Checks for file flavor.
   *
   * @param flavors the flavors
   * @return true, if successful
   */
  private boolean hasFileFlavor(DataFlavor[] flavors) {
    for (DataFlavor flavor : flavors) {
      if (DataFlavor.javaFileListFlavor.equals(flavor)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Checks for string flavor.
   *
   * @param flavors the flavors
   * @return true, if successful
   */
  private boolean hasStringFlavor(DataFlavor[] flavors) {
    for (DataFlavor flavor : flavors) {
      if (DataFlavor.stringFlavor.equals(flavor)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Import data.
   *
   * @param comp the comp
   * @param t the t
   * @return true, if successful
   * @see javax.swing.TransferHandler#importData(javax.swing.JComponent, java.awt.datatransfer.Transferable)
   */
  @Override
  public boolean importData(JComponent comp, Transferable t) {
    if (!canImport(comp, t.getTransferDataFlavors())) {
      return false;
    }

    try {
      DataFlavor[] flavors = t.getTransferDataFlavors();

      if (hasFileFlavor(flavors)) {
        List<?> files = (List<?>) t.getTransferData(DataFlavor.javaFileListFlavor);
        for (Object file1 : files) {
          File file = (File) file1;
          jNPad.openFile(file.getAbsolutePath());
        }
        return true;
      }
      else if (hasStringFlavor(flavors)) {
        JTextComponent tc = (JTextComponent) comp;
        if (tc.equals(exportComp)
            && (tc.getCaretPosition() >= p0.getOffset())
            && (tc.getCaretPosition() <= p1.getOffset())) {
          shouldRemove = false;
          return true;
        }
        String str = (String) t.getTransferData(DataFlavor.stringFlavor);
        tc.replaceSelection(str);

        jNPad.getActiveEditPane().repaintGutter(); // selección del gutter

        return true;
      }
    }
    catch (UnsupportedFlavorException ufex) {
      LOGGER.warning("importData: unsupported data flavor"); //$NON-NLS-1$
    }
    catch (IOException ieox) {
      LOGGER.warning("importData: I/O exception"); //$NON-NLS-1$
    }

    return false;
  }

}
