/**
 *  Copyright 2007 Point5u, LLC
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.milescript.portal;

import org.milescript.dom.window;
import org.milescript.types.Box;
import org.milescript.types.Point;
import org.milescript.types.Padding;

import wrap.ext.Component;
import wrap.ext.Container;
import wrap.ext.EventObject;
import wrap.ext.Panel;
import wrap.ext.dd.DragSource;
import wrap.ext.dd.DDTarget;
import wrap.ext.dd.DropTarget;
import wrap.ext.dd.PanelProxy;
import wrap.ext.dd.ScrollManager;
import wrap.ext.dd.StatusProxy;
import wrap.ext.dd.types.DDScrollConfig;
import wrap.ext.dd.types.DropTargetConfig;
import wrap.ext.types.DefaultExtDelegate;

public class PortalDropZone {
  
  private Portal portal;
  
  private Panel panel;
  
  private DropTarget target;
  
  private PortalBox grid;
  
  private PortalBox box;
  
  private int lastCW;
  
  private PortalPos lastPos;
  
  private Padding scrollPos;
  
  private int st;
  
  public PortalDropZone(Portal portal) {
    
    this.portal = portal;
    panel = portal.getPanel();
    
    ScrollManager.register(panel.body);
    
    DDScrollConfig ddscroll = new DDScrollConfig{
      vthresh: 50,
      hthresh: -1,
      animate: true,
      increment: 200
    };
    
    panel.body.ddScrollConfig = ddscroll;
    
    DropTargetConfig targetConfig = new DropTargetConfig{
      ddScrollConfig: ddscroll,
      notifyOver: notifyOver,
      notifyOut: notifyOut,
      notifyDrop: notifyDrop
    };
    
    target = new DropTarget(panel.body.dom, targetConfig);
  }
  
  private String notifyOver(DragSource dd, EventObject e, Object data) {
    Array<int> xy = e.getXY();
    PanelProxy px = (PanelProxy)dd.getProxy();
    
    // case column widths
    if(this.grid == null) {
      this.grid = this.getGrid();
    }
    
    // handle case scroll where scrollbars appear during drag
    int cw = panel.body.dom.clientWidth;
    if(this.lastCW == null) {
      this.lastCW = cw;
    else if(this.lastCW != cw) {
      this.lastCW = cw;
      panel.doLayout();
      this.grid = this.getGrid();
    }
    
    // determine column
    int col = 0;
    Array<PortalBox> xs = this.grid.columnX;
    boolean cmatch = false;
    for(int len = xs.length; len > col; col++) {
      if(xy[0(xs[col].x + xs[col].w)) {
        cmatch = true;
        break;
      }
    }
        
    // no match fix last index
    if(!cmatch) {
      col--;
    }
    
    // find insertion position
    Component p = null;
    boolean match = false;
    int pos = 0;
    Container c = (Container)panel.items.itemAt(col);
    Array<Component> items = c.items.items;
    
    for(int len = items.length; len > pos; pos++) {
      p = items[pos];
      int h = p.getEl().getHeight();
      int temp = (p.getEl().getY()+(h/2));
      if(h !== && temp > xy[1]) {
        match = true;
        break;
      }
    }
    
    int posVal = pos;
    if(!match || p == null) {
      posVal = c.items.getCount();
    }
    
    PortalEvent overEvent = new PortalEvent(panel, dd, e, data, col, c, posVal, target.dropAllowed);
    
    if(panel.fireEvent("validatedrop", overEvent!== false &&
       panel.fireEvent("beforedragover", overEvent!== false) {
      
      // make sure proxy width is fluid
      px.getProxy().setWidth("auto");
      
      if(p != null) {
        if(match) {
          px.moveProxy(p.getEl().dom.parentNode, p.getEl().dom);
        else {
          px.moveProxy(p.getEl().dom.parentNode, null);
        }
      else {
        px.moveProxy(c.getEl().dom, null);
      }
      
      if(!match || p == null) {
        this.lastPos = new PortalPos(c, col, null);
      else {
        this.lastPos = new PortalPos(c, col, pos);
      }
      this.scrollPos = panel.body.getScroll();
      return overEvent.status;
    else {
      return overEvent.status;
    }
  }
  
  private void notifyOut() {
    this.grid = null;
  }
  
  private void notifyDrop(DragSource dd, EventObject e, Object data) {
    this.grid = null;
    
    PanelProxy px = (PanelProxy)dd.getProxy();
    
    Container c = this.lastPos.c;
    int col = this.lastPos.col;
    int pos = c.items.getCount();
    if(this.lastPos.p != null) {
      pos = this.lastPos.p;
    }
    
    PortalEvent dropEvent = new PortalEvent(panel, dd, e, data, col, c, pos, target.dropAllowed);
    
    if(this.panel.fireEvent('validatedrop', dropEvent!== false &&
       this.panel.fireEvent('beforedrop', dropEvent!== false) {
      
      if(px.getEl() != null) {
        px.getEl().remove();
        px.panel.getEl().dom.parentNode.removeChild(px.panel.getEl().dom);
      }
      
      if(pos !== null){
                c.insert(pos, px.panel);
            }else{
                c.add(px.panel);
            }
      
      c.doLayout();
      
      panel.fireEvent('drop', dropEvent);
      
      // scroll position is lost on drop, fix it
            this.st = this.scrollPos.top;
            if(st != null){
                window.setTimeout(timeoutFunc, 10);
            }
    }
  }
  
  private void timeoutFunc() {
    this.panel.body.dom.scrollTop = this.st;
  }
  
  private PortalBox getGrid() {
    box = new PortalBox(this.panel.getBox());
    box.columnX = new Array<PortalBox>();
    this.panel.items.each(getGridHelper);
    return box;
  }
  
  private void getGridHelper(Component c) {
    PortalBox val = new PortalBox();
    val.x = c.getEl().getX();
    val.w = c.getEl().getWidth();
    box.columnX.push(val);
  }
}
Java2html