// @(#)root/eve:$Id: TEveSelection.cxx 32464 2010-03-04 15:45:13Z matevz $
// Author: Matevz Tadel 2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TEveSelection.h"
#include "TEveProjectionBases.h"
#include "TEveCompound.h"
#include "TEveManager.h"

#include "TClass.h"

//______________________________________________________________________________
//
// Make sure there is a SINGLE running TEveSelection for each
// selection type (select/highlight).

ClassImp(TEveSelection);

//______________________________________________________________________________
TEveSelection::TEveSelection(const char* n, const char* t) :
   TEveElementList(n, t),
   fPickToSelect  (kPS_Projectable),
   fActive        (kTRUE),
   fIsMaster      (kTRUE)
{
   // Constructor.

   fSelElement       = &TEveElement::SelectElement;
   fIncImpSelElement = &TEveElement::IncImpliedSelected;
   fDecImpSelElement = &TEveElement::DecImpliedSelected;
}

//______________________________________________________________________________
void TEveSelection::SetHighlightMode()
{
   // Set to 'highlight' mode.

   // Most importantly, this sets the pointers-to-function-members in
   // TEveElement that are used to mark elements as (un)selected and
   // implied-(un)selected.

   fPickToSelect = kPS_Projectable;
   fIsMaster     = kFALSE;

   fSelElement       = &TEveElement::HighlightElement;
   fIncImpSelElement = &TEveElement::IncImpliedHighlighted;
   fDecImpSelElement = &TEveElement::DecImpliedHighlighted;
}


/******************************************************************************/
// Protected helpers
/******************************************************************************/

//______________________________________________________________________________
void TEveSelection::DoElementSelect(TEveSelection::SelMap_i entry)
{
   // Select element indicated by the entry and fill its
   // implied-selected set.

   TEveElement *el  = entry->first;
   Set_t       &set = entry->second;

   (el->*fSelElement)(kTRUE);
   el->FillImpliedSelectedSet(set);
   for (Set_i i = set.begin(); i != set.end(); ++i)
      ((*i)->*fIncImpSelElement)();
}

//______________________________________________________________________________
void TEveSelection::DoElementUnselect(TEveSelection::SelMap_i entry)
{
   // Deselect element indicated by the entry and clear its
   // implied-selected set.

   TEveElement *el  = entry->first;
   Set_t       &set = entry->second;

   for (Set_i i = set.begin(); i != set.end(); ++i)
      ((*i)->*fDecImpSelElement)();
   set.clear();
   (el->*fSelElement)(kFALSE);
}


/******************************************************************************/
// Overrides of child-element-management virtuals from TEveElement
/******************************************************************************/

//______________________________________________________________________________
Bool_t TEveSelection::AcceptElement(TEveElement* el)
{
   // Pre-addition check. Deny addition if el is already selected.
   // Virtual from TEveElement.

   return el != this && fImpliedSelected.find(el) == fImpliedSelected.end() &&
          el->IsA()->InheritsFrom(TEveSelection::Class()) == kFALSE;
}

//______________________________________________________________________________
void TEveSelection::AddElement(TEveElement* el)
{
   // Add an element into selection, virtual from TEveElement.

   TEveElementList::AddElement(el);

   SelMap_i i = fImpliedSelected.insert(std::make_pair(el, Set_t())).first;
   if (fActive)
   {
      DoElementSelect(i);
   }
   SelectionAdded(el);
}

//______________________________________________________________________________
void TEveSelection::RemoveElement(TEveElement* el)
{
   // Add an element into selection, virtual from TEveElement.
   // Overriden here just so that a signal can be emitted.

   TEveElementList::RemoveElement(el);
   SelectionRemoved(el);
}

//______________________________________________________________________________
void TEveSelection::RemoveElementLocal(TEveElement* el)
{
   // Virtual from TEveElement.

   SelMap_i i = fImpliedSelected.find(el);

   if (i != fImpliedSelected.end())
   {
      if (fActive)
      {
         DoElementUnselect(i);
      }
      fImpliedSelected.erase(i);
   }
   else
   {
      Warning("TEveSelection::RemoveElementLocal", "element not found in map.");
   }
}

//______________________________________________________________________________
void TEveSelection::RemoveElements()
{
   // Add an element into selection, virtual from TEveElement.
   // Overriden here just so that a signal can be emitted.

   TEveElementList::RemoveElements();
   SelectionCleared();
}

//______________________________________________________________________________
void TEveSelection::RemoveElementsLocal()
{
   // Virtual from TEveElement.

   if (fActive)
   {
      for (SelMap_i i = fImpliedSelected.begin(); i != fImpliedSelected.end(); ++i)
         DoElementUnselect(i);
   }
   fImpliedSelected.clear();
}

//______________________________________________________________________________
void TEveSelection::RemoveImpliedSelected(TEveElement* el)
{
   // Remove element from all implied-selected sets.
   //
   // This is called as part of the element destruction from
   // TEveManager::PreDeleteElement() and should not be called
   // directly.

   for (SelMap_i i = fImpliedSelected.begin(); i != fImpliedSelected.end(); ++i)
   {
      Set_i j = i->second.find(el);
      if (j != i->second.end())
         i->second.erase(j);
   }
}

//______________________________________________________________________________
void TEveSelection::RecheckImpliedSet(SelMap_i smi)
{
   // Recalculate implied-selected state for given selection entry.
   // Add new elements to implied-selected set and increase their
   // implied-selected count.

   Set_t set;
   smi->first->FillImpliedSelectedSet(set);
   for (Set_i i = set.begin(); i != set.end(); ++i)
   {
      if (smi->second.find(*i) == smi->second.end())
      {
         smi->second.insert(*i);
         ((*i)->*fIncImpSelElement)();
      }
   }
}

//______________________________________________________________________________
void TEveSelection::RecheckImpliedSetForElement(TEveElement* el)
{
   // If given element is selected or implied-selected with this
   // selection and recheck implied-set for given selection entry.

   // Top-level selected.
   {
      SelMap_i i = fImpliedSelected.find(el);
      if (i != fImpliedSelected.end())
         RecheckImpliedSet(i);
   }

   // Implied selected, need to loop over all.
   {
      for (SelMap_i i = fImpliedSelected.begin(); i != fImpliedSelected.end(); ++ i)
      {
         if (i->second.find(el) != i->second.end())
            RecheckImpliedSet(i);
      }
   }
}


//******************************************************************************
// Signals
//******************************************************************************

//______________________________________________________________________________
void TEveSelection::SelectionAdded(TEveElement* el)
{
   // Emit SelectionAdded signal.

   Emit("SelectionAdded(TEveElement*)", (Long_t)el);
}

//______________________________________________________________________________
void TEveSelection::SelectionRemoved(TEveElement* el)
{
   // Emit SelectionRemoved signal.

   Emit("SelectionRemoved(TEveElement*)", (Long_t)el);
}

//______________________________________________________________________________
void TEveSelection::SelectionCleared()
{
   // Emit SelectionCleared signal.

   Emit("SelectionCleared()");
}

//______________________________________________________________________________
void TEveSelection::SelectionRepeated(TEveElement* el)
{
   // Called when secondary selection changed internally.

   Emit("SelectionRepeated(TEveElement*)", (Long_t)el);
}

/******************************************************************************/
// Activation / deactivation of selection
/******************************************************************************/

//______________________________________________________________________________
void TEveSelection::ActivateSelection()
{
   // Activate this selection.

   for (SelMap_i i = fImpliedSelected.begin(); i != fImpliedSelected.end(); ++i)
      DoElementSelect(i);
   fActive = kTRUE;
}

//______________________________________________________________________________
void TEveSelection::DeactivateSelection()
{
   // Deactivate this selection.

   fActive = kFALSE;
   for (SelMap_i i = fImpliedSelected.begin(); i != fImpliedSelected.end(); ++i)
      DoElementUnselect(i);
}


/******************************************************************************/
// User input processing
/******************************************************************************/

//______________________________________________________________________________
TEveElement* TEveSelection::MapPickedToSelected(TEveElement* el)
{
   // Given element el that was picked or clicked by the user, find
   // the parent/ancestor element that should actually become the main
   // selected element according to current selection mode.

   if (el == 0)
      return 0;

   if (el->ForwardSelection())
   {
      return el->ForwardSelection();
   }

   switch (fPickToSelect)
   {
      case kPS_Ignore:
      {
         return 0;
      }
      case kPS_Element:
      {
         return el;
      }
      case kPS_Projectable:
      {
         TEveProjected* pted = dynamic_cast<TEveProjected*>(el);
         if (pted)
            return dynamic_cast<TEveElement*>(pted->GetProjectable());
         return el;
      }
      case kPS_Compound:
      {
         TEveElement* cmpnd = el->GetCompound();
         if (cmpnd)
            return cmpnd;
         return el;
      }
      case kPS_PableCompound:
      {
         TEveProjected* pted = dynamic_cast<TEveProjected*>(el);
         if (pted)
            el = dynamic_cast<TEveElement*>(pted->GetProjectable());
         TEveElement* cmpnd = el->GetCompound();
         if (cmpnd)
            return cmpnd;
         return el;
      }
      case kPS_Master:
      {
         TEveElement* mstr = el->GetMaster();
         if (mstr)
            return mstr;
         return el;
      }
   }
   return el;
}

//______________________________________________________________________________
void TEveSelection::UserPickedElement(TEveElement* el, Bool_t multi)
{
   // Called when user picks/clicks on an element. If multi is true,
   // the user is requiring a multiple selection (usually this is
   // associated with control-key being pressed at the time of pick
   // event).

   TEveElement *edit_el = el ? el->ForwardEdit() : 0;

   el = MapPickedToSelected(el);

   if (el || HasChildren())
   {
      if (!multi)
         RemoveElements();
      if (el)
      {
         if (HasChild(el))
             RemoveElement(el);
         else
            AddElement(el);
      }
      if (fIsMaster)
         gEve->ElementSelect(edit_el ? edit_el : el);
      gEve->Redraw3D();
   }
}

//______________________________________________________________________________
void TEveSelection::UserRePickedElement(TEveElement* el)
{
   // Called when secondary selection becomes empty.

   el = MapPickedToSelected(el);
   if (el && HasChild(el))
   {
      SelectionRepeated(el);
      gEve->Redraw3D();
   }
}

//______________________________________________________________________________
void TEveSelection::UserUnPickedElement(TEveElement* el)
{
   // Called when secondary selection becomes empty.

   el = MapPickedToSelected(el);
   if (el)
   {
      RemoveElement(el);
      gEve->Redraw3D();
   }
}
