package adf.sample.view;

import java.util.Iterator;
import java.util.List;

import oracle.adf.model.binding.DCIteratorBinding;
import oracle.adf.view.rich.component.rich.data.RichTable;
import oracle.adf.view.rich.context.AdfFacesContext;
import oracle.adf.view.rich.datatransfer.DataFlavor;
import oracle.adf.view.rich.datatransfer.Transferable;
import oracle.adf.view.rich.dnd.DnDAction;
import oracle.adf.view.rich.event.DropEvent;

import oracle.jbo.Row;
import oracle.jbo.RowSetIterator;
import oracle.jbo.uicli.binding.JUCtrlHierBinding;
import oracle.jbo.uicli.binding.JUCtrlHierNodeBinding;

import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.RowKeySet;


public class DepartmentsDropBean {
    public DepartmentsDropBean() {
    }

    /**
     * The dragged row takes the position of the row it is droped on. Note that 
     * drag and drop is on the table component and to synchronize the underlying 
     * ADF model I needed to accept a "flicker" of teh table after the drop
     * 
     * @param dropEvent Event passed in from ADF Faces at the end of the drag and 
     *        drop operation
     *        
     * @return Copy.MOVE
     */
    public DnDAction onDepartmentsRowDrop(DropEvent dropEvent) {
        
        //get the table instance. This information is later used
        //to determine the tree binding and the iterator binding
        RichTable table = (RichTable)dropEvent.getDragComponent();
        List dropRowKey = (List)dropEvent.getDropSite();
        //if no dropsite then drop area was not a data area
        if (dropRowKey == null) {
            return DnDAction.NONE;
        }
        
        //The transferable is the payload that contains the dragged row's
        //row key that we use to access the dragged row handle in the ADF
        //iterator binding
        Transferable t = dropEvent.getTransferable();

        //get the row key set of the dragged row. The "rowmove" string is the 
        //discriminant defined on the drag source and the collectionDrop target.        
        DataFlavor<RowKeySet> df = DataFlavor.getDataFlavor(RowKeySet.class, "rowmove");
        RowKeySet rks = t.getData(df);
        Iterator iter = rks.iterator();
        
        //for this use case the re-order of rows is one-by-one, which means that the rowKeySet 
        //should only contain a single entry. If it contains more then still we only look at a
        //singe (first) row key entry
        List draggedRowKey = (List) iter.next();
        
        //get access to the oracle.jbo.Row instance represneting this table row
        JUCtrlHierNodeBinding draggeRowNode = (JUCtrlHierNodeBinding) table.getRowData(draggedRowKey);        
        Row dragRow = draggeRowNode.getRow();        
        
        JUCtrlHierNodeBinding dropRowObject = (JUCtrlHierNodeBinding) table.getRowData(dropRowKey);        
        Row dropRow = dropRowObject.getRow();
               
               
        //get the table's ADF JUCtrlHierBinding
        CollectionModel collectionModel = (CollectionModel) table.getValue();        
        JUCtrlHierBinding treeBinding = (JUCtrlHierBinding) collectionModel.getWrappedData();
        
        //get access to the ADF iterator binding used by the table and the underlying RowSetIterator.
        //The RowSetIterator allows us to remove and re-instert the dragged row
        DCIteratorBinding departmentsIterator = treeBinding.getDCIteratorBinding();               
        RowSetIterator rsi = departmentsIterator.getRowSetIterator(); 
               
        int indexOfDropRow= rsi.getRangeIndexOf(dropRow);        
        //remove dragged row from collection so it can be added back
        dragRow.removeAndRetain();
                
        rsi.insertRowAtRangeIndex(indexOfDropRow, dragRow);        
        //make row current in ADF iterator.         
        departmentsIterator.setCurrentRowIndexInRange(indexOfDropRow);
        
        //ppr the table
        AdfFacesContext adfctx = AdfFacesContext.getCurrentInstance();
        //note that the refresh of the table didn't work when refreshing the table
        //so I needed to refresh the container component (af:panelStretchLayout). 
        adfctx.addPartialTarget(table.getParent());
        
        return DnDAction.MOVE;
    }
}
