// $Header: /cvs/gled-1.2/GledCore/Glasses/ZGlass.cxx,v 1.13 2005/03/11 17:50:15 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/.

//______________________________________________________________________
// ZGlass
//
// Base class of Gled enabled classes.
// Provides infrastructure for integration with the Gled system.
//
// mGlassBits: collection of flags that allow (memory optimised)
// handling of lenses.

#include "ZGlass.h"
#include "ZGlass.c7"

#include <Glasses/ZList.h>
#include <Glasses/ZQueen.h>
#include <Glasses/ZKing.h>
#include <Glasses/ZMirFilter.h>
#include <Stones/ZComet.h>
#include <Gled/GThread.h>

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

namespace ZGlassBits {
  UShort_t kFixedName = 0x1;
  UShort_t kDying     = 0x2;
}

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

ClassImp(ZGlass)

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

 void ZGlass::_init()
{
  mSaturn = 0; mQueen = 0;
  mGlassBits = 0; mSaturnID=0;
  mGuard = 0;
  bMIRActive = true; bAcceptRefs = true;
  mRefCount = mMoonRefCount = mSunRefCount = mFireRefCount = mEyeRefCount = 0; 
  mTimeStamp = mStampReqTring = 0;
  pSetYNameCBs = 0;
  mStamp_CB = mStampLink_CB = 0; mStamp_CBarg = mStampLink_CBarg = 0;

  bUseDispList = false;
}

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

/**************************************************************************/
// Hairy Inlines
/**************************************************************************/

// inline /// used to be in the header ... gave segvs with cint
 void ZGlass::set_link_or_die(ZGlass*& link, ZGlass* new_val, FID_t fid)
{
  if(link == new_val) return;
  if(link) link->DecRefCount(this);
  if(new_val) {
    try { new_val->IncRefCount(this); }
    catch(...) {
      if(link) { link = 0; StampLink(fid); }
      throw;
    }
  }
  link = new_val;
  StampLink(fid);
}


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

 void ZGlass::reference_all() {
  lppZGlass_t link_refs;
  CopyLinkRefs(link_refs);
  for(lppZGlass_i i=link_refs.begin(); i!=link_refs.end(); ++i) {
    if(**i) {
      try {
	(**i)->IncRefCount(this);
      }
      catch(string exc) {
	**i = 0;
      }
    }
  }
}

 void ZGlass::unreference_all() {
  lppZGlass_t link_refs;
  CopyLinkRefs(link_refs);
  for(lppZGlass_i i=link_refs.begin(); i!=link_refs.end(); ++i) {
    if(**i) {
      (**i)->DecRefCount(this);
    }
  }
}

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

 Int_t ZGlass::remove_references_to(ZGlass* lens)
{
  // Removes all references to *lens*.
  // Virtual ... lists overrirde it but also call the ZGlass version
  // for unreferencing of links.
  // Emits Rays, but does NOT call DecRefCount: this is done by wrapper
  // RemoveReferencesTo() (and sometimes by ZQueen during lens delition).

  lppZGlass_t link_refs;
  CopyLinkRefs(link_refs);
  Int_t n = 0;
  for(lppZGlass_i i=link_refs.begin(); i!=link_refs.end(); ++i) {
    if(**i == lens) {
      **i = 0;
      ++n;
    }
  }
  if(n) StampLink();
  return n;
}

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

 string ZGlass::Identify() const
{
  return string(GForm("'%s'[%d]", mName.Data(), mSaturnID));
}

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

 void ZGlass::WriteLock()
{
  if(mQueen) mQueen->SubjectWriteLock();
  ReadLock();
}

 void ZGlass::WriteUnlock()
{
  ReadUnlock();
  if(mQueen) mQueen->SubjectWriteUnlock();
}


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

 ZMIR* ZGlass::get_MIR()
{
  return GThread::get_mir();
}

 ZMIR* ZGlass::assert_MIR_presence(const string& header, int what)
{
  ZMIR* mir = GThread::get_mir();
  if(mir == 0) {
    throw(header + "must be called via a MIR.");
  }
  if((what & MC_IsFlare) && mir->HasRecipient()) {
    throw(header + "must be called via a flared MIR.");
  }
  if((what & MC_IsBeam) && !mir->HasRecipient()) {
    throw(header + "must be called via a beamed MIR.");
  }
  if((what & MC_HasResultReq) && !mir->HasResultReq()) {
    throw(header + "must be called with a result request set.");
  }
  return mir;
}

 ZMIR* ZGlass::suggest_MIR_presence(const string& header, int what)
{
  ZMIR* mir = GThread::get_mir();
  if(mir == 0) {
    ISwarn(header + "should be called via a MIR.");
    return 0;
  }
  if((what & MC_IsFlare) && mir->HasRecipient()) {
    ISwarn(header + "should be called via a flared MIR.");
  }
  if((what & MC_IsBeam) && !mir->HasRecipient()) {
    ISwarn(header + "should be called via a beamed MIR.");
  }
  if((what & MC_HasResultReq) && !mir->HasResultReq()) {
    ISwarn(header + "should be called with a result request set.");
  }
  return mir;
}

/**************************************************************************/
// YNameChangeCB

typedef set<ZGlass::YNameChangeCB*>		spYNameChangeCB_t;	
typedef set<ZGlass::YNameChangeCB*>::iterator	spYNameChangeCB_i;	

void ZGlass::register_name_change_cb(ZGlass::YNameChangeCB* rec)
{
  if(mGlassBits & ZGlassBits::kFixedName) return;
  ReadLock();
  if(pSetYNameCBs == 0)
    pSetYNameCBs = new set<YNameChangeCB*>;
  pSetYNameCBs->insert(rec);
  ReadUnlock();
}

void ZGlass::unregister_name_change_cb(ZGlass::YNameChangeCB* rec)
{
  ReadLock();
  if(pSetYNameCBs != 0)
    pSetYNameCBs->erase(rec);
  ReadUnlock();
}

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

 void ZGlass::SetName(const Text_t* n)
{
  if(mGlassBits & ZGlassBits::kFixedName) {
    Stamp(FID());
    throw(string("ZGlass::SetName lens has FixedName bit set"));
  }
  string name(n);
  WriteLock();
  if(pSetYNameCBs != 0) {
    for(set<YNameChangeCB*>::iterator i=pSetYNameCBs->begin(); i!=pSetYNameCBs->end(); ++i) {
      (*i)->y_name_change_cb(this, name);
    }
  }
  mName = name.c_str();
  Stamp(FID());
  WriteUnlock();
  if(mQueen == this) {
    ZMIR* mir = get_MIR();
    if(mir && ! mir->HasRecipient()) mQueen->BasicQueenChange(*mir);
  }
}

 void ZGlass::SetTitle(const Text_t* t)
{
  WriteLock();
  mTitle = t;
  Stamp(FID());
  WriteUnlock();
  if(mQueen == this) {
    ZMIR* mir = get_MIR();
    if(mir && ! mir->HasRecipient()) mQueen->BasicQueenChange(*mir);
  }
}

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

 ZMirFilter* ZGlass::GetGuard() const
{
  ReadLock();
  ZMirFilter* _ret = mGuard;
  ReadLock();
  return _ret;
}

 void ZGlass::SetGuard(ZMirFilter* guard)
{
  // Might want to read-lock if LOCK_SET_METHS is true in project7.
  set_link_or_die((ZGlass*&)mGuard, guard, FID());
}

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

 ZGlass::~ZGlass()
{
  // !!!!! Should unref all links; check zlist, too
  delete pSetYNameCBs;
}

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

 void ZGlass::UpdateGlassView()
{
  if(mQueen && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_change, mTimeStamp, FID()));
    mQueen->EmitRay(ray);
  }
  if(mStamp_CB) mStamp_CB(this, mStamp_CBarg);
}

 void ZGlass::UpdateAllViews()
{
  if(mQueen && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_change, mTimeStamp, FID_t(0,0)));
    mQueen->EmitRay(ray);
  }
  if(mStamp_CB) mStamp_CB(this, mStamp_CBarg);
}

 void ZGlass::ReTriangulate()
{
  mStampReqTring = Stamp();
}

 void ZGlass::RebuildRnrScheme()
{
  Stamp(FID_t(0,0), 0x1);
}

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

 bool ZGlass::IsSunSpace()
{
  // Returns true if this lens is in local Saturn's sun-space.

  ZKing* sk = mSaturn->GetKing();
  return (mSaturnID >= sk->GetMinID() && mSaturnID <= sk->GetMaxID());
}

 bool ZGlass::IsSunOrFireSpace()
{
  // Returns true if this lens is in local Saturn's sun or fire-space.

  return (mSaturnID >= mSaturn->GetKing()->GetMinID());
}

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

 Short_t ZGlass::IncRefCount(ZGlass* from)
{
  // Called to notify *this* that *from* desires to reference it.
  // Throws an exception if the reference is not allowed by *this*
  // lens or its queen.

  static const string _eh("ZGlass::IncRefCount ");

  if(mQueen && from->mQueen) {
    mQueen->SubjectRefCntLock();
    // !!! Here ask queen if it's OK
    if(!bAcceptRefs) {
      mQueen->SubjectRefCntUnlock();
      throw(_eh + "lens not accepting references.");
    }
    switch(from->mQueen->GetKing()->GetLightType()) {
    case ZKing::LT_Moon: ++mMoonRefCount; break;
    case ZKing::LT_Sun:  ++mSunRefCount;  break;
    case ZKing::LT_Fire:
    default:		 ++mFireRefCount; break;
    }
    ++mRefCount;
    ++mReverseRefs[from];
    mQueen->SubjectRefCntUnlock();
    // Stamp(FID());
  }
  return mRefCount;
}

void ZGlass::dec_ref_count(hpZGlass2Int_i& i, UShort_t n)
{
  switch(i->first->mQueen->GetKing()->GetLightType()) {
  case ZKing::LT_Moon: mMoonRefCount -= n; break;
  case ZKing::LT_Sun:  mSunRefCount  -= n; break;
  case ZKing::LT_Fire:
  default:	       mFireRefCount -= n; break;
  }
  mRefCount -= n;
  i->second -= n;
}

 Short_t ZGlass::DecRefCount(ZGlass* from, UShort_t n)
{
  // Called to notify *this* that it is no longer referenced by lens from.

  static const string _eh("ZGlass::DecRefCount ");

  if(mQueen && from->mQueen) {
    mQueen->SubjectRefCntLock();
    
    hpZGlass2Int_i i = mReverseRefs.find(from);
    if(i == mReverseRefs.end()) {
      mQueen->SubjectRefCntUnlock();
      ISerr(_eh + Identify() + " not referenced by " + from->Identify() + ".");
    }
    if(n > i->second) {
      ISwarn(_eh + GForm("%s, called by %s: mismatch %d > %d.", Identify().c_str(),
			 from->Identify().c_str(), n, i->second));
      n = i->second;
    }

    dec_ref_count(i, n);

    if(i->second <= 0) mReverseRefs.erase(i);
    if(mRefCount == 0 && mQueen) mQueen->ZeroRefCount(this);
    mQueen->SubjectRefCntUnlock();
    // Stamp(FID());
  }
  return mRefCount;
}

 Short_t ZGlass::IncEyeRefCount()
{
  return ++mEyeRefCount;
}

 Short_t ZGlass::DecEyeRefCount()
{
  return --mEyeRefCount;
}

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

 void ZGlass::ClearLinks()
{
  lppZGlass_t link_refs;
  CopyLinkRefs(link_refs);
  int n = 0;
  for(lppZGlass_i i=link_refs.begin(); i!=link_refs.end(); ++i) {
    if(**i) {
      (**i)->DecRefCount(this);
      **i = 0;
      ++n;
    }
  }
  if(n) StampLink();
}

 void ZGlass::ClearAllReferences()
{
  ClearLinks();
}

 Int_t ZGlass::RemoveReferencesTo(ZGlass* lens)
{
  Int_t n = remove_references_to(lens);
  if(n) lens->DecRefCount(this, n);
  return n;
}

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

 ZGlass* ZGlass::GetLinkByName(const Text_t* link_name)
{ return GetLinkByName(string(link_name)); }

 ZGlass* ZGlass::GetLinkByName(const string& link_name)
{
  // Returns glass pointed to by link with name link_name.
  // Attempts link_name == LinkMemberName and
  // link_name == Class::LinkMemberName.
  // Throws an exception (string) if link does not exist.
  // In principle could have a map link-name->link-specs.

  // Should go in reverse direction !!!!
  // Locking doesn't make much sense.

  lLinkRep_t lr; CopyLinkReps(lr);
  for(lLinkRep_i i=lr.begin(); i!=lr.end(); ++i) {
    if(link_name == i->fLinkInfo->fName || link_name == i->fLinkInfo->FullName())
      return i->fLinkRef;
  }
  throw(string(GForm("ZGlass::GetLinkByName link '%s' does not exist in '%s' (id=%u)",
		     link_name.c_str(), GetName(), GetSaturnID())));
}

 ZGlass* ZGlass::FindLensByPath(const Text_t* url)
{ return FindLensByPath(string(url)); }

 ZGlass* ZGlass::FindLensByPath(const string& url)
{
  static const string _eh("ZGlass::FindLensByPath ");
  using namespace GledNS;

  list<url_token> l;
  tokenize_url(url, l);
  ZGlass* g = this;
  try {
    for(list<url_token>::iterator i=l.begin(); i!=l.end(); ++i) {
      if(g == 0) {
	// !!! give more details
	throw(_eh + "null lens; probably a link is not set");
      }
      switch (i->type()) {
      case url_token::link_sel: {
	g = g->GetLinkByName(*i);
	break;
      }
      case url_token::list_sel: {
	ZList* l = dynamic_cast<ZList*>(g);
	if(l == 0) {
	  // !!! give more details
	  throw(_eh + "url element is not a list");
	}
	g = l->GetElementByName(*i);
	break;
      }
      default:
	ISerr(_eh + "unknown token type. Attempting to ignore ...");
	break;
      }
    }
  }
  catch(string exc) {
    ISerr(exc);
    throw;
  }

  return g;
}

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

 TimeStamp_t ZGlass::Stamp(FID_t fid, UChar_t eye_bits)
{
  ++mTimeStamp;
  if(mQueen && mQueen->GetStamping() && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_change, mTimeStamp, fid, eye_bits));
    mQueen->EmitRay(ray);
  }
  if(mStamp_CB) mStamp_CB(this, mStamp_CBarg);

  return mTimeStamp;
}

 TimeStamp_t ZGlass::StampLink(FID_t fid)
{
  ++mTimeStamp;
  if(mQueen && mSaturn->AcceptsRays()) {
    auto_ptr<Ray> ray
      (Ray::PtrCtor(this, RayNS::RQN_link_change, mTimeStamp, fid,
		    Ray::EB_StructuralChange));
    mQueen->EmitRay(ray);
  }
  if(mStampLink_CB) mStampLink_CB(this, mStampLink_CBarg);

  return mTimeStamp;
}

 void ZGlass::SetStamp_CB(zglass_stamp_f foo, void* arg)
{
  mStamp_CB = foo; mStamp_CBarg = arg;
}
 void ZGlass::SetStampLink_CB(zglass_stamp_f foo, void* arg)
{
  mStampLink_CB = foo; mStampLink_CBarg = arg;
}

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

 Int_t ZGlass::RebuildAllRefs(An_ID_Demangler* idd)
{
  return RebuildLinkRefs(idd);
}


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.