/*! Add a single layout object shape into the quadTree. 
It first checks whether or not another layout object is already placed into this
quadTree. If not it simply links the shape and exits. If another object is already
here, then the new overlap area is calculated. \n In case the new area is the same as 
the existing one, then the object might be (possibly) fited into one of the childrens 
quadTree. To check this fitintree() method is called. If this is unsuccessfull, just 
then the layout object is linked to this quadTree. \n If the new overlapping area is 
bigger that the existing one, then the layout object is linked to the current quadTree 
after what the current quadTree as well as its successors has to be rebuild using 
resort().\n The method might be called recursively via fitintree() method.
*/
void laydata::quadTree::add(tdtdata* shape) {
   DBbox shovl = shape->overlap();shovl.normalize();
   if (empty()) {
   // first shape in the container
      _overlap = shovl;
      _first = shape;shape->nextis(NULL);
   }
   else {
      // save the old overlap
      DBbox oldovl = _overlap;
      // calculate the new container overlap
      _overlap.overlap(shovl);
      float areaold = oldovl.area();
      float areanew = _overlap.area();
// The equation below produce problems with severe consequences.
// It seems to be because of the type of the conversion
//      if (oldovl.area() == _overlap->area()) {
      if (areaold == areanew) {
         // if the overlapping box hasn't changed,
         // try to fit the shape into subtree
         if ((areanew <= 4 * shovl.area()) || !fitintree(shape)) {
            // shape doesn't fit into the subtree, so place it here
            shape->nextis(_first); _first = shape;
         }
      }
      else { // the overlapping box has had blown-up
         shape->nextis(_first); _first = shape;
         resort(); // re-sort the entire tree
      }   
   }
}
/*! Checks whether a single layout object shape will fit into one of the 
childrens quadTree. It calls add() and returns success if the new layout object 
fits entirely into one of the possible subtrees or if it blows up its 
overlaping area not more than 10%. Returns false if the shape does not fit
anywhere - means it should be placed higher into the quadTree structure.\n
The method might be called recursively via the add() method.
*/
bool laydata::quadTree::fitintree(tdtdata* shape) {
   DBbox shovl = shape->overlap();
   float clipedarea[4];
   // check the clipping to see in witch region to place the shape
   for (byte i = 0; i < 4 ; i++) {
      DBbox subbox = _overlap.getcorner(i);
      clipedarea[i] = subbox.cliparea(shovl,true);
      if (-1 == clipedarea[i]) {//entirely inside the area
         if (!_quads[i]) _quads[i] = DEBUG_NEW quadTree();
         _quads[i]->add(shape);
         return true;
      }
   }
   // if we got to this point - means that the shape does not fit
   // entirely inside neither of the four sub-areas. 
   // It is a decision time then
   byte candidate = biggest(clipedarea);
   // now calculate the eventual new overlaping box
   DBbox newovl = _overlap.getcorner(candidate);
   newovl.overlap(shovl);
   // if the max area of the candidate does not blow more than 10% - 
   // then seems to be OK to get it
   if (newovl.area() < 1.1 * (_overlap.area() / 4)) {
      if (!_quads[candidate]) _quads[candidate] = DEBUG_NEW quadTree();
      _quads[candidate]->add(shape);
      return true;
   }
   return false; // shape can not be fit into any subtree
}
/*! Build a new quadTree structure for the tdtdata in the inlist. The method is
using the existing _overlap variable. For every layout shape fitinsubtree()
method is called in a try to put the data in the child quadTree. At the end
the method is called for every of the child structures.
*/
void laydata::quadTree::sort(dataList& inlist)
{
   // if the input list is empty - nothing to do!
   if (0 == inlist.size()) return;
   dataList::iterator DI = inlist.begin();
   // if the list contains only one component - link it and run away
   if (1 == inlist.size())
   {
      DI->first->nextis(NULL); _first = DI->first;
      return;
   }
   byte i;
   // the overlapping box of the currnet shape 
//   DBbox shovl(TP(0,0));
   DBbox shovl = DEFAULT_OVL_BOX;
   // the maximum possible overlapping boxes of the 4 children
   DBbox maxsubbox[4] = {DEFAULT_OVL_BOX, DEFAULT_OVL_BOX, 
                         DEFAULT_OVL_BOX, DEFAULT_OVL_BOX};
   for (i = 0; i < 4; i++) maxsubbox[i] = _overlap.getcorner(i);
   // the sub-lists data will be sorted in
   dataList sublist[4];
   // which is the child where current shape fits 
   int fitinsubbox;
   // initialize the iterator
   float sharea, totalarea = _overlap.area();
   while (inlist.end() != DI)
   {
      // get the overlap of the current shape
      shovl = DI->first->overlap();shovl.normalize();
      sharea = shovl.area();
      // Check it fits in some of the children
      if (totalarea <= 4 * sharea || 
                        (-1 == (fitinsubbox = fitsubtree(shovl, maxsubbox))))
      {
         // no fit. The shape is sorted in the current tree
         DI->first->nextis(_first); _first = DI->first;
      }
      else
      {
         // fits in sub-tree fitinsubbox
         sublist[fitinsubbox].push_back(*DI);
         // check this child already exists
         if (_quads[fitinsubbox])  // yes ?
            _quads[fitinsubbox]->_overlap.overlap(shovl);
         else
         {
            // create the child, initialize the overlapping box
            _quads[fitinsubbox] = DEBUG_NEW quadTree();
            _quads[fitinsubbox]->_overlap = shovl;
         }
      }
      // in all cases get rid of the current shape pointer. It is already sorted
      DI = inlist.erase(DI);
   }
   // at this point inlist MUST be empty - split over max 4+this quadTrees
   // now go and sort the children - if any
   for(i = 0; i < 4; i++)
      if (_quads[i]) _quads[i]->sort(sublist[i]);

}
/*! Removes marked shapes from the quadtree without deleting them. The removed
    shapes are still listed in the _shapesel container of the current cell.
    The new overlapping box is calculated during this process and the method
    returns true to notify its parent that the overlapping box has changed and
    resort has to be initiated on the upper levels of the tree. The tree is 
    processed bottom-up, i.e. the method is recursively called first for child 
    quadTree structures.\n
    On the top level the method is called by two tdtcell methods:
    delete_selected and move selected. The difference is that for delete, 
    partially selected shapes are ignored and not processed.\n
    Fully selected shapes are always marked as sh_deleted. When move operation is
    going on they will be re-marked afterwards to sh_selected by the move(copy) 
    virtual methods of tdtdata.
 */
bool laydata::quadTree::delete_marked(SH_STATUS stat, bool partselect) {
   assert(!((stat != sh_selected) && (partselect == true)));
   // Create and initialize a variable "to be sorted"
   bool _2B_sorted = false;
   // save the old overlap, and initialize the new one
   DBbox oldovl = _overlap;
   _overlap = DEFAULT_OVL_BOX;
   // deleteing sequence is bottom-up, so start from the children
   for (byte i = 0; i < 4; i++) 
      if (_quads[i]) {
         _2B_sorted |= _quads[i]->delete_marked(stat, partselect);
         // check that there is still something left in the child quadTree
         if (_quads[i]->empty()) {
            delete _quads[i]; _quads[i] = NULL;
         }   
         else update_overlap(_quads[i]->overlap());
      }
   // prepare a pair of pointers to tdtdata
   tdtdata* wds = _first;
   tdtdata* wdsP = NULL;
   // loop all tdtdata in the current tree and check they are selected
   while (wds)
      // if selected ...
      if ((stat == wds->status()) || 
                                (partselect && (sh_partsel == wds->status()))) {
         // mark the fully selected shapes as deleted
         if (stat == wds->status()) wds->set_status(sh_deleted);
         // Unlink the marked shape from the list
         if (wdsP) { // if this is not the first shape
            wdsP->nextis(wds->next()); wds->nextis(NULL);
            wds = wdsP->next();
         }
         else { // Special attention when this is the first shape
            _first = wds->next(); wds->nextis(NULL);
            wds = _first;
         }
      }
      // If not selected, or partially selected but partselect == false,
      // update the overlapping box, and move further
      else {
         update_overlap(wds->overlap());
         wdsP = wds; wds = wds->next();
      }
   // If _overlap is still NULL here -> means the placeholder is empty. Will
   // be deleted by the parent
   if (empty()) _invalid = true;
   else {
      //Now if the overlapping rectangles differ, then invalidate 
      //the current quadTree
      float areaold = oldovl.area();
      float areanew = _overlap.area();
      if (areaold != areanew) _invalid = true;
   }
   return _2B_sorted |= _invalid;
}
/*! A temporary Draw (during move/copy operations) of the container contents
 on the screen using the virtual quadTree::tmp_draw() method of the 
 parent object. */
void laydata::tdtlayer::tmp_draw(const layprop::DrawProperties& drawprop,
                                                 ctmqueue& transtack) const {
   // check the entire layer for clipping...
   DBbox clip = drawprop.clipRegion();
   if (empty()) return;
   DBbox areal = overlap() * transtack.front();
   areal.normalize();
   if (clip.cliparea(areal) == 0) return;
   else {
      areal = areal * drawprop.ScrCTM();
      if (areal.area() < MIN_VISUAL_AREA) return;
   }   
   quadTree::tmp_draw(drawprop, transtack);
}
/*! Temporary draw of the container contents on the screen using the virtual 
tmp_draw methods of the tdtddata objects. This happens only if 
the current quadTree object is visible. Current clip region data is
obtained from LayoutCanvas. In a sence this method is the same as openGL_draw
without fill and not handling selected shapes*/
void laydata::quadTree::tmp_draw(const layprop::DrawProperties& drawprop,
                                                   ctmqueue& transtack) const {
   if (empty()) return;
   // check the entire holder for clipping...
   DBbox clip = drawprop.clipRegion();   
   DBbox areal = _overlap * transtack.front(); 
   areal.normalize();
   if (clip.cliparea(areal) == 0) return;
   else {
      areal = areal * drawprop.ScrCTM();
      if (areal.area() < MIN_VISUAL_AREA) return;
   }   
   tdtdata* wdt = _first;
   while(wdt) {
      wdt->tmp_draw(drawprop, transtack);
      wdt = wdt->next();
   }
   for(byte i = 0; i < 4; i++) 
      if (_quads[i]) _quads[i]->tmp_draw(drawprop, transtack);
}
/*! Draw the contents of the container on the screen using the virtual 
openGL_draw methods of the tdtddata objects. This happens only if 
the current quadTree object is visible. Current clip region data is
obtained from LayoutCanvas. Draws also the select marks in case shape is
selected. \n This is the cherry of the quadTree algorithm cake*/
void laydata::quadTree::openGL_draw(ctmstack& transtack, const layprop::DrawProperties& drawprop,
                                                   const dataList* slst) const {
   if (empty()) return;
   // check the entire holder for clipping...
   DBbox clip = drawprop.clipRegion();
   DBbox areal = _overlap * transtack.top(); 
   areal.normalize();
   if (clip.cliparea(areal) == 0) return;
   else {
      areal = areal * drawprop.ScrCTM();
      if (areal.area() < MIN_VISUAL_AREA) return;
//      std::cout << "  ... with area " << areal.area() << "\n";
   }
   tdtdata* wdt = _first;
   // The drawing will be faster like this for the cells without selected shapes
   // that will be the wast majority of the cases. A bit bigger code though.
   // Seems the bargain is worth it.
   if (slst)
      while(wdt) {
         wdt->openGL_draw(transtack,drawprop);
         // in case the shape is somehow selected...
         if       (sh_selected == wdt->status()) wdt->draw_select(transtack.top());
         else if  (sh_partsel == wdt->status()) {
            dataList::const_iterator SI;
            for (SI = slst->begin(); SI != slst->end(); SI++)
               if (SI->first == wdt) break;
            assert(SI != slst->end());
            wdt->draw_select(transtack.top(), SI->second);
         }   
         wdt = wdt->next();
      }
   else
      // if there are no selected shapes
      while(wdt) {
         wdt->openGL_draw(transtack,drawprop);
         wdt = wdt->next();
      }
   for(byte i = 0; i < 4; i++) 
      if (_quads[i]) _quads[i]->openGL_draw(transtack, drawprop, slst);
}
/*! Checks whether a single layout object shape will fit into one of the 
childrens quadTree. Returns the index of the child quadTree which fits 
the shape or -1 otherwise.
*/
int laydata::quadTree::fitsubtree(DBbox shovl, DBbox* maxsubbox ) {
   float clipedarea[4];
   // check the clipping to see in witch region to place the shape
   for (byte i = 0; i < 4 ; i++) {
      clipedarea[i] = maxsubbox[i].cliparea(shovl,true);
      if (-1 == clipedarea[i]) {//entirely inside the area
         return i;
      }
   }
   // if we got to this point - means that the shape does not fit
   // entirely inside neither of the four sub-areas. 
   // It is a decision time then
   byte candidate = biggest(clipedarea);
   // now calculate the eventual new overlaping box
   DBbox newovl = maxsubbox[candidate];
   newovl.overlap(shovl);
   // if the max area of the candidate does not blow more than 10% - 
   // then seems to be OK to get it
   if (newovl.area() < 1.1 * (_overlap.area() / 4)) {
      return candidate;
   }
   return -1; // shape can not be fit into any subtree
}
/*! Draw the contents of the container on the screen using the virtual 
openGL_draw methods of the tdtddata objects. This happens only if 
the current quadTree object is visible. Current clip region data is
obtained from LayoutCanvas. Draws also the select marks in case shape is
selected. \n This is the cherry of the quadTree algorithm cake*/
void laydata::quadTree::openGL_draw(layprop::DrawProperties& drawprop,
                                                   const dataList* slst, bool fill, bool bound) const {
   if (empty()) return;
   // check the entire holder for clipping...
   DBbox clip = drawprop.clipRegion();
   DBbox areal = _overlap * drawprop.topCTM(); 
   areal.normalize();
   if (clip.cliparea(areal) == 0) return;
   else {
      areal = areal * drawprop.ScrCTM();
      if (areal.area() < MIN_VISUAL_AREA) return;
//      std::cout << "  ... with area " << areal.area() << "\n";
   }
   tdtdata* wdt = _first;
//   bool fill = drawprop.getCurrentFill();
   // The drawing will be faster like this for the cells without selected shapes
   // that will be the wast majority of the cases. A bit bigger code though.
   // Seems the bargain is worth it.
   if (slst)
   {
      while(wdt)
      {
         pointlist points;
         // precalculate drawing data
         wdt->openGL_precalc(drawprop, points);
         if (0 != points.size())
         {
            // draw the shape fill (contents of refs, arefs and texts)
            if (fill)  wdt->openGL_drawfill(drawprop, points);
            // draw the outline of the shapes and overlapping boxes 
            if (bound) wdt->openGL_drawline(drawprop, points);
            if ((sh_selected == wdt->status()) || (sh_partsel == wdt->status()))
            {
               drawprop.setLineProps(true);
               if       (sh_selected == wdt->status())
                  wdt->openGL_drawsel(points, NULL);
               else if  (sh_partsel  == wdt->status())
               {
                  dataList::const_iterator SI;
                  for (SI = slst->begin(); SI != slst->end(); SI++)
                     if (SI->first == wdt) break;
                  assert(SI != slst->end());
                  wdt->openGL_drawsel(points, SI->second);
               }
               drawprop.setLineProps(false);
            }
            wdt->openGL_postclean(drawprop, points);
         }
         wdt = wdt->next();
      }
   }
   else
   {
      // if there are no selected shapes
      while(wdt)
      {
         pointlist points;
         // precalculate drawing data
         wdt->openGL_precalc(drawprop, points);
         // draw the shape fill (contents of refs, arefs and texts)
         if (fill)  wdt->openGL_drawfill(drawprop, points);
         // draw the outline of the shapes and overlapping boxes
         if (bound) wdt->openGL_drawline(drawprop, points);
         // clean-up
         wdt->openGL_postclean(drawprop, points);
         wdt = wdt->next();
      }
   }
   
/*   // The drawing will be faster like this for the cells without selected shapes
   // that will be the wast majority of the cases. A bit bigger code though.
   // Seems the bargain is worth it.
   if (slst)
      while(wdt) {
         wdt->openGL_draw(drawprop);
         // in case the shape is somehow selected...
         if       (sh_selected == wdt->status()) wdt->draw_select(drawprop.topCTM());
         else if  (sh_partsel == wdt->status()) {
            dataList::const_iterator SI;
            for (SI = slst->begin(); SI != slst->end(); SI++)
               if (SI->first == wdt) break;
            assert(SI != slst->end());
            wdt->draw_select(drawprop.topCTM(), SI->second);
         }   
         wdt = wdt->next();
      }
   else
      // if there are no selected shapes
      while(wdt) {
         wdt->openGL_draw(drawprop);
         wdt = wdt->next();
      }*/
   for(byte i = 0; i < 4; i++) 
      if (_quads[i]) _quads[i]->openGL_draw(drawprop, slst, fill, bound);
}