/**
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
 *
 * AdfPanelCustomizableDropTarget define drop target for PC.
 *
 * @author Kannan Parthasarathy
 */
function AdfPanelCustomizableDropTarget()
{
  this.Init(null, AdfDnDContext.ACTION_COPY_OR_MOVE, [AdfDataFlavor.STRING_FLAVOR, AdfDataFlavor.getRowKeyDataFlavor("resourceModel"), AdfShowDetailFrameDragSource._SDFCOMPONENT_FLAVOR]);
}

// make AdfPanelCustomizableDropTarget a subclass of AdfDropTarget
AdfObject.createSubclass(AdfPanelCustomizableDropTarget, AdfDropTarget);

/**
 * @override
 */
AdfPanelCustomizableDropTarget.prototype.Init = function(
  dropHandler, allowedActions, allowedFlavors)
{
  AdfPanelCustomizableDropTarget.superclass.Init.call(this);

  this._dropHandler = dropHandler;
  this._allowedActions = allowedActions;
  this._allowedFlavors = allowedFlavors;
}

/**
 * @override
 */
AdfPanelCustomizableDropTarget.prototype.drop = function(dndContext, proposedAction, pageX, pageY)
{
  // call the drop handler if any to determine the userAction
  var dropHandler = this._dropHandler;
  var userAction;

  if (dropHandler != null)
    userAction = dropHandler.call(this, dndContext, proposedAction, pageX, pageY);
  else
    userAction = proposedAction;

  AdfAssert.assertNumber(userAction);

  // allow the dropHandler to reject the drop
  if (userAction == AdfDnDContext.ACTION_NONE)
    return userAction;

  // only allowed actions can be input
  AdfAssert.assert((userAction & ~AdfDnDContext.ACTIONS_ALL) == 0,
                "Invalid userAction:" + userAction);

  // Get the panelCustomizable object and associated DIV
  var pc = this.getComponent();
  var pcDiv = AdfDhtmlPanelCustomizablePeer.getContentDiv(pc);

  // Get the children of the panelCustomizable (TDs or DIVs).
  // For horizontal layouts, the children are TDs, not DIVs.
  var pcDivChildren = null;
  var layout = pc.getLayout();
  if (layout == "horizontal")
  {
    pcDivChildren = pcDiv.rows[0].cells;
  }
  else
  {
    pcDivChildren = pcDiv.childNodes;
  }

  // Determine where the proxy is being dropped (calculate dropIndex)
  var dropIndex = 0;
  var halign = pc.getHalign();
  var isRTL = AdfPage.PAGE.getLocaleContext().isRightToLeft();
  var ignoreFirstTD = (layout == "horizontal" && (halign == "end" ||  
                       isRTL && halign == "left" || 
                       !isRTL && halign == "right"));
  for (i=0; i<pcDivChildren.length; i++)
  {
    // When halign is end or if RTL and halign is LEFT, RTL and halign is RIGHT
    // then the first TD would be empty TD with width 100%. Ignore this TD
    // See PC renderer where TD is rendered.
    if (i == 0 && ignoreFirstTD)
      continue;
      
    // Is it either the H or V AdfDhtmlPanelCustomizablePeer proxy?
    if (pcDivChildren[i].id == "custcomps.dropProxy")
    {
      beforeDiv = pcDivChildren[i+1];
      break;
    }

    // skip over invisible children, e.g. the one being moved.
    // we look at the child of the div, i.e. the sdf inside it.

    // ### if this is the ShowDetailFrameDropProxy, then we need to skip this div
    // ### while calculating dropIndex
    if (pcDivChildren[i].firstChild.style.display != "none" &&
        pcDivChildren[i].firstChild.className != "ShowDetailFrameDropProxy")
    {
      dropIndex++;
    }
  }

 // replace child for streched pc if child exists
  if ((dropIndex >= 1) && (pc.getLayout() == "stretch"))
  {
    this.replaceChild();
    return AdfDnDContext.ACTION_NONE;
  }

  // Do the actual Move
  var dropComponent = dndContext.getDragSource().getComponent();
  if (dropComponent.getComponentType() == "oracle.adf.ShowDetailFrame" ||
      dropComponent.getComponentType() == "oracle.adf.rich.portlet")
  {
    // Get the div of the component being moved
    var dropComponentDiv = document.getElementById(dropComponent.getClientId());

    // Remove the SDF Placeholder
    if ((AdfDhtmlShowDetailFramePeer.dropProxy != null) &&
        (AdfDhtmlShowDetailFramePeer.dropProxy.parentNode != null)) 
      AdfDhtmlShowDetailFramePeer.dropProxy.parentNode.removeChild(AdfDhtmlShowDetailFramePeer.dropProxy);

    // Do the move on the client side
    // pcDiv.insertBefore(dropComponentDiv.parentNode, pcDivChildren[dropIndex+1]);
    // beforeDiv.parentNode.insertBefore...
    if (pc.getLayout() == "horizontal")
      this.insertHorizontalLayoutNode(pcDiv, dropComponentDiv, beforeDiv);
    else
      this.insertDefaultLayoutNode( pcDiv, dropComponentDiv, beforeDiv);

    // do the move on the server side
    AdfDhtmlShowDetailFramePeer.dropFrame(dropIndex, dropComponent, pc.getClientId());
    return AdfDnDContext.ACTION_NONE;
  }
  else
  {
      var dropEvent = new AdfDropEvent(this.getComponent(),
                                   dndContext.getDragSource(),
                                   dndContext.getTransferable(),
                                   userAction,
                                   pageX,
                                   pageY,
                                   null,
                                   "dummy",
                                   dropIndex);

      var params = dropEvent.GetParams();
      params.dragCompId = dndContext.getDragSource().getComponent().getClientId();
      dropEvent.queue();

      // remove resource catalog proxy node after drop is completed
      AdfDhtmlPanelCustomizablePeer.removeDefaultLayoutProxy();
      AdfDhtmlPanelCustomizablePeer.removeHorizontalLayoutProxy();

      return AdfDnDContext.ACTION_NONE;
  }
}

/**
 * @override
 */
AdfPanelCustomizableDropTarget.prototype.dragExit = function(dndContext)
{
  // remove resource catalog proxy node after exit
  AdfDhtmlPanelCustomizablePeer.removeDefaultLayoutProxy();
  AdfDhtmlPanelCustomizablePeer.removeHorizontalLayoutProxy();
}

// insert drop node for Horizontal layout
AdfPanelCustomizableDropTarget.prototype.insertHorizontalLayoutNode = function(
   pcDiv, dropComponentDiv, beforeDiv)
{
  var insertHNode = dropComponentDiv.parentNode;

  // create "td" element if drag source is default layout type
  // and drop source is horizontal layout type
  if (dropComponentDiv.parentNode.tagName == "DIV")
  {
    // remove wrapping.div element
    var rmDiv = dropComponentDiv.parentNode;
    rmDiv.parentNode.removeChild(rmDiv);

    // wrapping with td tag
    var tdtag = document.createElement("td");
    tdtag.vAlign = "top";
    tdtag.id = "wrapping.td." + dropComponentDiv.id;
    tdtag.appendChild(dropComponentDiv);

    insertHNode = tdtag;
  }
  // insert node
  if (beforeDiv == null)
    pcDiv.rows[0].appendChild(insertHNode);
  else  
    pcDiv.rows[0].insertBefore(insertHNode, beforeDiv);

}

// insert drop node for default layout
AdfPanelCustomizableDropTarget.prototype.insertDefaultLayoutNode = function (
  pcDiv, dropComponentDiv, beforeDiv)
{
  var insertDNode = dropComponentDiv.parentNode;

  // create "div" element if drag source is horizontal layout type
  // and drop source is default layout type
  if (dropComponentDiv.parentNode.tagName == "TD")
  {
    // remove extra wrapping TD element
    var rmTd = dropComponentDiv.parentNode;
    rmTd.parentNode.removeChild(rmTd);

    var divtag = document.createElement("div");
    divtag.id = "wrapping.div." + dropComponentDiv.id;
    divtag.appendChild(dropComponentDiv);

    insertDNode = divtag;
  }

  // insert node
  if (beforeDiv == null)
    pcDiv.appendChild(insertDNode);
  else  
    pcDiv.insertBefore(insertDNode, beforeDiv);
}

/**
 * TODO: replace Stretched child
 */
AdfPanelCustomizableDropTarget.prototype.replaceChild = function ()
{
  // now, we just alert the user
  var component = this.getComponent();
  var mesg = component.getProperty("cannotDropMessage");
  alert(mesg);
}


/**
 * @override
 */
AdfPanelCustomizableDropTarget.prototype.toDebugString = function()
{
  var debugString = AdfPanelCustomizableDropTarget.superclass.toDebugString.call(this);

  var allowedActons = this._allowedActions;

  if (allowedActons)
    debugString += " allowedActions:" +  allowedActons.toString(2);

  debugString += " allowedFlavors:" +  this._allowedFlavors;

  return debugString;
}

/**
 * Return our allowed AdfDataFlavors
 */
AdfPanelCustomizableDropTarget.prototype.GetAllowedFlavors = function(dndContext)
{
  return this._allowedFlavors;
}

/**
 * Override to use the actions
 */
AdfPanelCustomizableDropTarget.prototype.GetAllowedActions = function(dndContext)
{
  return this._allowedActions;
}


AdfPanelCustomizableDropTarget.prototype.AcceptDrag = function(
  dndContext, possibleActions, proposedAction, pageX, pageY)
{

  var component = this.getComponent();
  var allowAction = component.getAllowAction();

  if ( allowAction == "none" )
  {
    return AdfDnDContext.ACTION_NONE;
  }
  
  // don't allow DnD across naming container
  if (this.isContainerAllowsDropSource(dndContext) == false)
  {
    return AdfDnDContext.ACTION_NONE;
  }

  // only calculate flavors once and then stash on DndContext
  var flavorAcceptance = dndContext.getDropTargetProperty("DropTarget:flavorAcceptance");

  if (flavorAcceptance == null)
  {
    // not in the cache, so calculate
    flavorAcceptance = this.CalculateFlavorAcceptance(dndContext);

    dndContext.setDropTargetProperty("DropTarget:flavorAcceptance", flavorAcceptance);
  }

  AdfAssert.assertBoolean(flavorAcceptance);

  if (!flavorAcceptance)
    return AdfDnDContext.ACTION_NONE;
  else
  {
    // Show the drag feedback (gray insertion bar)
    AdfDhtmlPanelCustomizablePeer.showDragFeedback(
      dndContext, possibleActions, proposedAction, pageX, pageY, component);

    // the proposed action is allowed, so return it
    if (proposedAction & possibleActions)
    {
      return proposedAction;
    }
    else
    {
      // =-= bts TODO Allow preference order to be passed in
      if (possibleActions & AdfDnDContext.ACTION_MOVE)
        return AdfDnDContext.ACTION_MOVE;
      else if (possibleActions & AdfDnDContext.ACTION_COPY)
        return AdfDnDContext.ACTION_COPY;
      else if (possibleActions & AdfDnDContext.ACTION_LINK)
        return AdfDnDContext.ACTION_COPY;
      else
        return AdfDnDContext.ACTION_NONE;
    }
  }
}

/**
 * Check PC and SDF are in same naming container
 * don't allow DnD across naming container
 */
AdfPanelCustomizableDropTarget.prototype.isContainerAllowsDropSource = function(dndContext)
{
  var dragsource = dndContext.getDragSource();
  if (dragsource == null)
  {
    return false;
  }

  if (dragsource.getComponent().getComponentType() == "oracle.adf.ShowDetailFrame")
  {
    // Get SDF's id  
    var dragCompId = dragsource.getComponent().getClientId();
    // Get PC's id
    var component = this.getComponent();
    var dropContainerId = component.getClientId();

    var dragSourceNC  = dragCompId.substring(0, dragCompId.lastIndexOf(':'));
    var dropSourceNC  = dropContainerId.substring(0, dropContainerId.lastIndexOf(':'));

    // check both PC and SDF are in same naming container
    if ( dragSourceNC != dropSourceNC )
    {
      return false;
    }
  }

  return true;
}


