package org.openswing.swing.pivottable.client;

import javax.swing.*;
import java.awt.dnd.*;
import java.awt.Toolkit;
import org.openswing.swing.util.client.ClientUtils;
import org.openswing.swing.util.client.ClientSettings;
import java.awt.Point;
import java.awt.Cursor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.util.ArrayList;


/**
 * <p>Title: OpenSwing Framework</p>
 * <p>Description: Draggable button used within pivot table.</p>
 * <p>Copyright: Copyright (C) 2006 Mauro Carniel</p>
 *
 * <p> This file is part of OpenSwing Framework.
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the (LGPL) Lesser General Public
 * License as published by the Free Software Foundation;
 *
 *                GNU LESSER GENERAL PUBLIC LICENSE
 *                 Version 2.1, February 1999
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *       The author may be contacted at:
 *           maurocarniel@tin.it</p>
 *
 * @author Mauro Carniel
 * @version 1.0
 */
public class DraggableButton extends JPanel implements DragSourceListener, DropTargetListener {

  /** drag source */
  private DragSource dragSource = new DragSource();

  /** panel identifier, used for DnD */
  private String panelId = null;

  /** drop gestures */
  private DropTarget dropTarget = null;

  /** cursor to show on dragging */
  private Cursor dragCursor = null;

  /** component position */
  private int pos;

  /** list of DraggableButtonListener elements */
  private ArrayList draggableButtonListeners = new ArrayList();


  public DraggableButton(String panelId,int pos) {
    this.panelId = panelId;
    this.pos = pos;
    try {
      dragSource.createDefaultDragGestureRecognizer(
          this,
          DnDConstants.ACTION_MOVE,
          new DragGestureAdapter(this)
      );
      dropTarget = new DropTarget(this, this);
      dragCursor = Toolkit.getDefaultToolkit().createCustomCursor(
        ClientUtils.getImage("column.gif"),
        new Point(15, 10),
        ClientSettings.getInstance().getResources().getResource("drag")
      );
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }


  public final void addDraggableButtonListener(DraggableButtonListener listener) {
    draggableButtonListeners.add(listener);
  }


  public final void removeDraggableButtonListener(DraggableButtonListener listener) {
    draggableButtonListeners.remove(listener);
  }


  /********************************************************************
   *
   *             DRAG 'N DROP MANAGEMENTS METHODS
   *
   ********************************************************************/



  /************************************************************
   * DRAG MANAGEMENT
   ************************************************************/


  class DragGestureAdapter implements DragGestureListener {

    private DragSourceListener dragListener = null;

    public DragGestureAdapter(DragSourceListener dragListener) {
      this.dragListener = dragListener;
    }


    /**
     * A drag gesture has been initiated.
     */
    public final void dragGestureRecognized( DragGestureEvent event) {
      setCursor(dragCursor);
      try {
        dragSource.startDrag(event, DragSource.DefaultMoveDrop,
                             new StringSelection(panelId + "_" + pos),
                             dragListener);
      }
      catch (InvalidDnDOperationException ex) {
      }
    }

  }


  /**
   * This message goes to DragSourceListener, informing it that the dragging has entered the DropSite
   */
  public final void dragEnter (DragSourceDragEvent event) {
    setCursor(Cursor.getDefaultCursor());
  }


  /**
   * This message goes to DragSourceListener, informing it that the dragging has exited the DropSite.
   */
  public final void dragExit (DragSourceEvent event) {
    setCursor(Cursor.getDefaultCursor());
  }


  /**
   * This message goes to DragSourceListener, informing it that the dragging is currently ocurring over the DropSite.
   */
  public final void dragOver (DragSourceDragEvent event) {
    setCursor(dragCursor);
  }


  /**
   * This method is invoked when the user changes the dropAction.
   */
  public final void dropActionChanged ( DragSourceDragEvent event) { }


  /**
   * This message goes to DragSourceListener, informing it that the dragging has ended.
   */
  public final void dragDropEnd (DragSourceDropEvent event) {
  }



  /************************************************************
   * DROP MANAGEMENT
   ************************************************************/

  /**
   * This method is invoked when you are dragging over the DropSite.
   */
  public final void dragEnter (DropTargetDragEvent event) {
    event.acceptDrag (DnDConstants.ACTION_MOVE);
  }


  /**
   * This method is invoked when you are exit the DropSite without dropping.
   */
  public final void dragExit (DropTargetEvent event) {
  }

  /**
   * This method is invoked when a drag operation is going on.
   */
  public final void dragOver (DropTargetDragEvent event) {
  }


  /**
   * This method is invoked when a drop event has occurred.
   */
  public final void drop(DropTargetDropEvent event) {
    try {
      setCursor(Cursor.getDefaultCursor());
      Transferable transferable = event.getTransferable();
      if (transferable.isDataFlavorSupported (DataFlavor.stringFlavor)){

        String id = (String)transferable.getTransferData ( DataFlavor.stringFlavor);
        if (id!=null && id.startsWith(panelId)) {
          event.acceptDrop(DnDConstants.ACTION_MOVE);
          event.getDropTargetContext().dropComplete(true);
          String[] tokens = id.split("_");
          int draggedCompPos = Integer.parseInt(tokens[tokens.length-1]);
//          System.out.println("draggedCompPos:"+draggedCompPos+" pos:"+pos);
          if (draggedCompPos!=pos) {
            DraggableButtonEvent e = new DraggableButtonEvent(
              panelId,
              draggedCompPos,
              pos
            );
            for(int i=0;i<draggableButtonListeners.size();i++)
              ((DraggableButtonListener)draggableButtonListeners.get(i)).dragEventFired(e);
          }
        }
        else
          event.rejectDrop();

      } else{
        event.rejectDrop();
      }
    }
    catch (Exception ex) {
      ex.printStackTrace();
      event.rejectDrop();
    } finally {
      try {
        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
      }
      catch (Exception ex) {
      }

    }
  }

  /**
   * This method is invoked if the use modifies the current drop gesture.
   */
  public final void dropActionChanged ( DropTargetDragEvent event ) {
  }




}
