//NonLeafElement.java
//  
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//  
//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
//Lesser General Public License for more details.
package rtree;

/**
   Anybody outside the package need not be concerned with this class.
   Element that will be in a non leaf node
   @author Prachuryya Barua
*/
public class NonLeafElement extends Element
{
  /**will contain file pointer pointing to the child node*/
  long nodePtr;
  public NonLeafElement( Rect nodeRect,long nodePtr)
  {
    super(nodeRect);
    this.nodePtr = nodePtr;
  }
  /**if possible make this function abstract and static in the parent class
     depends upon the size of the pointer
  */
  public static int sizeInBytes()
  {
    return( Rect.sizeInBytes() + Node.LONG_SIZE);
  }
  /**
     This can be the chile node pointer. 
  */
  //  public Object getPtr()//this is an integer object
  //  {
  //    return(new Integer(nodePtr));
  //  }
  @Override
public long getPtr()//this is an integer object
  {
    return nodePtr;
  }
  
  @Override
public int getElementType()
  {
    return Node.NONLEAF_NODE;
  }
  //  void setPtr(Object ptr)
  //    throws IllegalValueException
  //  {
  //    if(!(ptr instanceof Integer))
  //      throw new IllegalValueException("rtree.NonLeafElement.setPtr: pointer shoild be Integer");
  //    nodePtr = ((Integer)ptr).intValue();
  //  }
  @Override
public void setPtr(long ptr)
  {
    nodePtr = ptr;
  }
  @Override
public String toString()
  {
    return (super.toString()+"\n\tnodePointer: "+nodePtr);
  }
  /**
     A merge-sort routine for the Packing algo.
     @param rect the array to sort
     @param on if 0 then sort on X else on Y(i.e for 1)
  */
  public static void sort( Element[] elmts,int on)
  {
    twoWayMerge(elmts,0,elmts.length-1,on);
  }

  static void twoWayMerge(Element[] elmts,int start,int finish,int on)
  {
    try{
      int size = finish - start+1;
      if(size <= 2){//last two elements - simple swap
        if(size < 2)
          return;
        int midValI = getMid(elmts[start],on);
        int midValJ = getMid(elmts[finish],on);
        Element temp;
        if(midValI > midValJ){
          temp = elmts[start];
          elmts[start] = elmts[finish];
          elmts[finish] = temp;
        }
        return;
      }
      Double middle = new Double(start+finish);
      middle = new Double(Math.ceil(middle.doubleValue()/2));
      twoWayMerge(elmts,start,middle.intValue(),on);
      twoWayMerge(elmts,middle.intValue(),finish,on);
      simpleMerge(elmts,start,middle.intValue(),finish,on);
    }
    catch(Exception e){
      System.out.println("rtree.Element.twoWayMerge: probably index out of bound");
      //e.printStackTrace();
    }
  }
  //simple merge
  private static void simpleMerge( Element[] elmts,int first,int second,int third,int on)
    throws Exception
  {
    int i = first;
    int j = second;
    int l = 0;
    int midValI;
    int midValJ;
    Element[] temp = new Element[third-first+1];
    while((i < second) && (j <= third)){//loop till one lasts
      //get the mid values in the given dimension
      midValI = getMid(elmts[i],on);
      midValJ = getMid(elmts[j],on);
      if(midValI <= midValJ)
        temp[l++] = elmts[i++];
      else
        temp[l++] = elmts[j++];
    }
    //copy the rest
    if(i >= second)//give second section
      while(j <= third)
        temp[l++] = elmts[j++];
    else
      while(i < second)//give first section
        temp[l++] = elmts[i++];
    System.arraycopy(temp,0,elmts,first,temp.length);
  }
  /**
     A private class to calculate the mid value in given dimension
  */
  private static int getMid( Element elmt,int on)
  {
    if(on == 0)
      return ((elmt.getRect().getMaxX() 
               + elmt.getRect().getMinX())/2);
    else
      return ((elmt.getRect().getMaxY() 
               + elmt.getRect().getMinY())/2);
  }
  @Override
public Object clone()
  {
    try{
      return new NonLeafElement(new Rect(Rectangle.getMinX(), Rectangle.getMinY(), 
                                         Rectangle.getMaxX(), Rectangle.getMaxY()), nodePtr);
    }
    catch(Exception e){
      e.printStackTrace();
      return null;
    }
  }
}
