// $Header: /cvs/gled-1.2/GledCore/Glasses/ZList.cxx,v 1.15 2005/04/08 11:20:13 matevz Exp $

// Copyright (C) 1999-2005, Matevz Tadel. All rights reserved.
// This file is part of GLED, released under GNU General Public License version 2.
// For the licensing terms see $GLEDSYS/LICENSE or http://www.gnu.org/.


//______________________________________________________________________
// ZList
//
//

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Need member-lid, member-cid limiters for Add methods. DONE
// This should also be used for Links to Lists ...
// there can specify member-lid, member-cid of list, that can be assigned.
// have: ZList*   mOperators; L{list<Operator>}, p7 translates that to 1, 8 (eg)
// SetOperators(ZList* x) { 
//   if(lid or cid differr) {
//	instantiate x->lid, x->cid
//	try dyn-casting to self.lid, self.cid
//   }
// But then can get more restrictive list-contents than originally
// anticipated.
//
// This in contrast to dis-activation of Glasses and providing
// Add/Remove wrappers (as in SaturnInfo or SunQueen)


#include "ZList.h"
#include "ZList.c7"

#include <Glasses/ZQueen.h>
#include <Glasses/ZKing.h>
#include <Net/Ray.h>
#include <Stones/ZComet.h>
#include <Gled/GledNS.h>

#include <algorithm>
#include <iterator>

ClassImp(ZList)

/**************************************************************************/

 void ZList::_init()
{
  mSize = 0;
  mLid  = 0; mCid  = 0;
  mStampListAdd_CB = 0;		mStampListAdd_CBarg = 0;
  mStampListRemove_CB = 0;	mStampListRemove_CBarg = 0;
  mStampListRebuild_CB = 0;	mStampListRebuild_CBarg = 0;
  mStampListClear_CB = 0;	mStampListClear_CBarg = 0;
}

/**************************************************************************/

 void ZList::reference_all() {
  PARENT_GLASS::reference_all();
  mListMutex.Lock();
  for(lpZGlass_i i=mGlasses.begin(); i!=mGlasses.end(); ++i)
    (*i)->IncRefCount(this);
  mListMutex.Unlock();
}

 void ZList::unreference_all() {
  PARENT_GLASS::unreference_all();
  mListMutex.Lock();
  for(lpZGlass_i i=mGlasses.begin(); i!=mGlasses.end(); ++i)
    (*i)->DecRefCount(this);
  mListMutex.Unlock();
}

/**************************************************************************/

 void ZList::clear_list()
{
  mGlasses.clear();
  mSize = 0;
}

/**************************************************************************/

 Int_t ZList::remove_references_to(ZGlass* lens)
{
  Int_t nl = ZGlass::remove_references_to(lens);

  int n = 0;
  mListMutex.Lock();
  for(lpZGlass_i i=mGlasses.begin(); i!=mGlasses.end(); ++i) {
    if(*i == lens) {
      lpZGlass_i j = i; --i;
      mGlasses.erase(j);
      ++n;
    }
  }
  mListMutex.Unlock();
  if(n) {
    if(n == 1) StampListRemove(lens);
    else       StampListRebuild();
  }

  return nl + n;
}


/**************************************************************************/

 void ZList::new_element_check(ZGlass* g)
{
  static const string _eh("ZList::new_element_check ");

  if(g == 0) {
    throw(_eh + "called with null ZGlass*.");
  }
  if(mLid && mCid) {
    if(!GledNS::IsA(g, FID_t(mLid, mCid))) {
      throw(_eh + "lens of wrong FID_t.");
    }
  }
}

/**************************************************************************/

 TimeStamp_t ZList::Copy(lpZGlass_t& dest)
{
  GMutexHolder _lstlck(mListMutex);
  copy(mGlasses.begin(), mGlasses.end(), back_inserter(dest));
  return mTimeStamp;
}

 ZGlass* ZList::First()
{
  GMutexHolder _lstlck(mListMutex);
  return mSize ? mGlasses.front() : 0;
}

 ZGlass* ZList::Last()
{ 
  GMutexHolder _lstlck(mListMutex);
  return mSize ? mGlasses.back() : 0;
}

 ZGlass* ZList::GetElementByName(const Text_t* name)
{ return GetElementByName(string(name)); }

 ZGlass* ZList::GetElementByName(const string& name)
{
  ZGlass* ret = 0;
  mListMutex.Lock();
  for(lpZGlass_i i=mGlasses.begin(); i!=mGlasses.end(); ++i) {
    if(strcmp(name.c_str(), (*i)->GetName()) == 0) {
      ret = *i;
      break;
    }
  }
  mListMutex.Unlock();
  return ret;
}

/**************************************************************************/

 ZList* ZList::AssertPath(const Text_t* path, const Text_t* new_el_type)
{
  // Makes sure that 'path' exists. From the missing element onwards
  // creates new sub-lists of type 'new_el_type'.
  // Throws an exception if:
  // a) link dereferencing is found in path;
  // b) would have to create a missing element under some other queen;
  // c) element in path is not a list;
  // d) instantiation fails.

  static const string _eh("ZList::AssertPath ");

  namespace GNS = GledNS;

  FID_t new_el_fid = GNS::FindClassID(new_el_type);
  if(new_el_fid.is_null())
    throw(_eh + "unknown list element type '" + new_el_type + "'.");


  list<GNS::url_token> ts;
  GNS::tokenize_url(path, ts);

  ZList* l = this;
  for(list<GNS::url_token>::iterator i=ts.begin(); i!=ts.end(); ++i) {
    switch (i->type()) {

    case GNS::url_token::link_sel: {
      throw(_eh + "link found but only list elements expected.");
      break;
    }

    case GNS::url_token::list_sel: {
      ZGlass* e = l->GetElementByName(*i);
      if(e != 0) {
	l = dynamic_cast<ZList*>(e);
	if(l == 0)
	  throw(_eh + "path element is not a list.");
      } else {
	if(l->GetQueen() != mQueen)
	  throw(_eh + "path leading to another queen.");

	if(mQueen->GetKing()->GetLightType() == ZKing::LT_Fire) {
	  ZGlass* g = GledNS::ConstructLens(new_el_fid);
	  if(g == 0) throw(_eh + "direct lens construction failed.");
	  g->SetName(i->c_str());
	  mQueen->CheckIn(g); l->Add(g);
	  l = dynamic_cast<ZList*>(g);
	} else {
	  auto_ptr<ZMIR> att_mir( l->S_Add(0) );
	  auto_ptr<ZMIR> inst_mir
	    ( mQueen->S_InstantiateWAttach
	      (l, 0, att_mir->Lid, att_mir->Cid, att_mir->Mid,
	       new_el_fid.lid, new_el_fid.cid, i->c_str())
	      );
	  auto_ptr<ZMIR_Result_Report> res( mSaturn->ShootMIRWaitResult(inst_mir) );
	  if(res->HasException())
	    throw(_eh + "got exception: " + res->Exception.Data());
	  if(res->HasResult()) {
	    ID_t id; *res >> id;
	    l = dynamic_cast<ZList*>(mSaturn->DemangleID(id));
	  } else
	    throw(_eh + "bad MIR result.");
	}
	if(l == 0)
	  throw(_eh + "instantiation of missing element failed.");
      }
      break;
    }

    default:
      throw(_eh + "unknown token type.");
      break;

    } // end switch
  } // end for

  return l;
}

 void ZList::Swallow(ZGlass* entry, Bool_t replace_p,
		    const Text_t* path, const Text_t* new_el_type)
{
  // A helper function for adding configuration DB entries.
  // Mostly intended for use from scripts.
  // Should NOT be called on exposed object-spaces!

  ZList *l = AssertPath(path, new_el_type);
  if(entry->GetSaturnID() == 0) mQueen->CheckIn(entry);
  ZGlass* ex_entry = l->GetElementByName(entry->GetName());
  if(ex_entry)
    if(replace_p)
      l->Remove(ex_entry);
    else 
      return;
  l->Add(entry);
}

 void ZList::Swallow(const Text_t* path, ZGlass* entry)
{
  Swallow(entry, true, path, "ZList");
}

/**************************************************************************/
/**************************************************************************/

 void ZList::SetElementFID(FID_t fid)
{
  mLid = fid.lid; mCid = fid.cid;
  Stamp(FID());
}

 void ZList::Add(ZGlass* g)
{
  new_element_check(g);
  mListMutex.Lock();
  mGlasses.push_back(g); ++mSize;
  StampListAdd(g, 0);
  mListMutex.Unlock();
  g->IncRefCount(this);
}

 void ZList::AddBefore(ZGlass* g, ZGlass* before)
{
  new_element_check(g);
  mListMutex.Lock();
  lpZGlass_i i = find(mGlasses.begin(), mGlasses.end(), before);
  mGlasses.insert(i, g); ++mSize;
  StampListAdd(g, before);
  mListMutex.Unlock();
  g->IncRefCount(this);
}

 void ZList::AddFirst(ZGlass* g)
{
  new_element_check(g);
  mListMutex.Lock();
  ZGlass* b4 = mSize > 0 ? mGlasses.front() : 0;
  mGlasses.push_front(g); ++mSize;
  StampListAdd(g, b4);
  mListMutex.Unlock();
  g->IncRefCount(this);
}

 void ZList::Remove(ZGlass* g)
{
  if(mSize==0) return;
  mListMutex.Lock();
  lpZGlass_i i = find(mGlasses.begin(), mGlasses.end(), g);
  bool succ;
  if(succ = (i!=mGlasses.end())) {
    mGlasses.erase(i); --mSize;
    StampListRemove(g);
  }
  mListMutex.Unlock();
  if(succ) g->DecRefCount(this);
}

 void ZList::RemoveLast(ZGlass* g)
{
  if(mSize==0) return;
  mListMutex.Lock();
  bool succ = false;
  lpZGlass_i i = mGlasses.end();
  do {
    if(*(--i) == g) {
      mGlasses.erase(i); --mSize;
      StampListRemove(g);
      succ = true;
      break;
    }
  } while(i!=mGlasses.begin());
  mListMutex.Unlock();
  if(succ) g->DecRefCount(this);
}

/**************************************************************************/

 void ZList::ClearList()
{
  static const string _eh("ZList::ClearList ");

  if(mSize == 0) return;

  lpZGlass_t foo;
  ISdebug(1, _eh + GForm("locking list '%s'.", GetName()));
  mListMutex.Lock();
  foo.swap(mGlasses);
  clear_list();
  StampListClear();
  mListMutex.Unlock();
  ISdebug(1, _eh + GForm("unlocked list '%s'.", GetName()));
  for(lpZGlass_i i=foo.begin(); i!=foo.end(); ++i) {
    (*i)->DecRefCount(this);
  }
  ISdebug(1, _eh + GForm("sfinished for '%s'.", GetName()));
}

 void ZList::ClearAllReferences()
{
  PARENT_GLASS::ClearAllReferences();
  ClearList();
}

/**************************************************************************/

 void ZList::RemoveLensesViaQueen(Bool_t recurse)
{
  // Sends MIR to queen and waits for result.
  // This should be called from a detached thread.

  if(IsEmpty()) return;

  auto_ptr<ZMIR> mir( mQueen->S_RemoveLenses(this, recurse) );
  auto_ptr<ZMIR_Result_Report> res( mSaturn->ShootMIRWaitResult(mir) );
  if(res->HasException())
    throw(string(res->Exception.Data()));
}

/**************************************************************************/

 Bool_t ZList::Has(ZGlass* g)
{
  mListMutex.Lock();
  lpZGlass_i i = find(mGlasses.begin(), mGlasses.end(), g);
  bool ret = (i != mGlasses.end());
  mListMutex.Unlock();
  return ret;
}

/**************************************************************************/

 void ZList::SortByName()
{
  GMutexHolder llck(mListMutex);
  if(mSize < 2) return;
  multimap<string, ZGlass*> nmap;
  for(lpZGlass_i i=mGlasses.begin(); i!=mGlasses.end(); ++i) {
    nmap.insert(pair<string, ZGlass*>((*i)->GetName(), *i));
  }
  mGlasses.clear();
  for(multimap<string, ZGlass*>::iterator i=nmap.begin(); i!=nmap.end(); ++i) {
    mGlasses.push_back(i->second);
  }
  StampListRebuild();
}

/**************************************************************************/
/**************************************************************************/

// !! The analogous calls in ZGlass have lid/cid counterparts.
// Didn't need them for lists so far. And don't see why I would.
// Just slightly non-consistent.

 TimeStamp_t ZList::StampListAdd(ZGlass* g, ZGlass* b4)
{
  ++mTimeStamp;
  if(mQueen && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_list_add, mTimeStamp, Ray::EB_StructuralChange));
    ray->SetBeta(g);
    ray->SetGamma(b4);
    mQueen->EmitRay(ray);
  }
  if(mStampListAdd_CB)
    mStampListAdd_CB(this, g, b4, mStampListAdd_CBarg);

  return mTimeStamp;
}

 TimeStamp_t ZList::StampListRemove(ZGlass* g)
{
  ++mTimeStamp;
  if(mQueen && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_list_remove, mTimeStamp, Ray::EB_StructuralChange));
    ray->SetBeta(g);
    mQueen->EmitRay(ray);
  }
  if(mStampListRemove_CB)
    mStampListRemove_CB(this, g, mStampListRemove_CBarg);

  return mTimeStamp;
}

 TimeStamp_t ZList::StampListRebuild()
{
  ++mTimeStamp;
  if(mQueen && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_list_rebuild, mTimeStamp, Ray::EB_StructuralChange));
    mQueen->EmitRay(ray);
  }
  if(mStampListRebuild_CB)
    mStampListRebuild_CB(this, mStampListRebuild_CBarg);

  return mTimeStamp;
}

 TimeStamp_t ZList::StampListClear()
{
  ++mTimeStamp;
  if(mQueen && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_list_clear, mTimeStamp, Ray::EB_StructuralChange));
    mQueen->EmitRay(ray);
  }
  if(mStampListClear_CB)
    mStampListClear_CB(this, mStampListClear_CBarg);

  return mTimeStamp;
}

/**************************************************************************/

 void ZList::SetStampListAdd_CB(zlist_stampadd_f foo, void* arg)
{
  mStampListAdd_CB = foo; mStampListAdd_CBarg = arg;
}
 void ZList::SetStampListRemove_CB(zlist_stampremove_f foo, void* arg)
{
  mStampListRemove_CB = foo; mStampListRemove_CBarg = arg;
}
 void ZList::SetStampListRebuild_CB(zlist_stamprebuild_f foo, void* arg)
{
  mStampListRebuild_CB = foo; mStampListRebuild_CBarg = arg;
}
 void ZList::SetStampListClear_CB(zlist_stampclear_f foo, void* arg)
{
  mStampListClear_CB = foo; mStampListClear_CBarg = arg;
}

/**************************************************************************/

 void ZList::Streamer(TBuffer &b)
{
  UInt_t R__s, R__c;

  if(b.IsReading()) {

    Version_t v = b.ReadVersion(&R__s, &R__c);
    ZGlass::Streamer(b);
    b >> mSize >> mLid >> mCid;
    ISdebug(D_STREAM, GForm("ZList::Streamer reading %d elements (%d,%d).",
			    mSize, mLid, mCid));
    mIDs.clear();
    ID_t id;
    for(UInt_t i=0; i<mSize; i++) { b >> id; mIDs.push_back(id); }
    b.CheckByteCount(R__s, R__c, ZList::IsA());

  } else {

    R__c = b.WriteVersion(ZList::IsA(), kTRUE);
    ZGlass::Streamer(b);
    b << mSize << mLid << mCid;
    ISdebug(D_STREAM, GForm("ZList::Streamer writing %d elements (%d,%d).",
			    mSize, mLid, mCid));
    for(lpZGlass_i i=mGlasses.begin(); i!=mGlasses.end(); i++)
      b << (*i)->GetSaturnID();
    b.SetByteCount(R__c, kTRUE);

  }
}

/**************************************************************************/

 Int_t ZList::RebuildAllRefs(An_ID_Demangler* idd)
{
  return RebuildLinkRefs(idd) + RebuildListRefs(idd);
}

 Int_t ZList::RebuildListRefs(An_ID_Demangler* idd)
{
  Int_t ret = 0;
  mGlasses.clear(); mSize = 0;
  for(lID_i i=mIDs.begin(); i!=mIDs.end(); ++i) {
    ZGlass* lens = idd->DemangleID(*i);
    if(lens) {
      try {
	lens->IncRefCount(this);
	mGlasses.push_back(lens); ++mSize;
      }
      catch(...) {
	++ret;
      }
    } else {
      ++ret;
    }
  }
  mIDs.clear();
  return ret;
}

/**************************************************************************/


ROOT page - Home page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.