///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Copyright (C) 1995-2002 by the Board of Trustees of Leland Stanford      //
//  Junior University.  See LICENSE for details.                             //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////


#include "scope.h"


// static variables implicitly initialized to 0
int Scope::_currentScopeLevel;
int Scope::_scopeCount;
PScope Scope::_topScope;
PScope Scope::_globalScope;
Array_List<HelperFunc> *Scope::_helpers;
int Scope::_helperCnt;


unsigned Scope_Init::_count;


///////////////////////////////////////////////////////////////////////////////
// Scope_Init class methods                                                  //
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scope_Init::Scope_init					     //
// Description: Initialize Scope static variables                            //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
Scope_Init::Scope_Init()
{
  if (_count++ == 0) {
    Scope::_currentScopeLevel = -1;
    ASSERT(Scope::_globalScope == NULL);
    Scope::_globalScope = Scope::_topScope = new Scope();
  }
}


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scope_Init::~Scope_Init					     //
// Description: Clean up global scope                                        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
Scope_Init::~Scope_Init()
{
  if (--_count == 0) {
    // TODO: Get rid of exit memory leaks
    //    delete Scope::_globalScope;
    Scope::_globalScope = Scope::_topScope = NULL;
  }
}


///////////////////////////////////////////////////////////////////////////////
// End of Scope_Init class methods                                           //
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// Scope class methods                                                       //
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scope::Scope						     //
// Description: Scope constructor.                                           //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
Scope::Scope(PScope prev) : _prevScope(prev), _undoChain(NULL)
{
   _scopeLevel = ++_currentScopeLevel;
   _scopeNum = ++_scopeCount;
}


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scope::~Scope						     //
// Description: Scope destructor.  Automatically restores all objects in the //
// scope as well as calling all helper functions.                            //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
Scope::~Scope()
{
  PScoped_Obj pso = _undoChain;
  while (pso != NULL)
    pso = pso->Restore();

  for (int i=0; i<_helperCnt; i++) {
    (*(*_helpers)[i])();
  }
}


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scope::AddToChain						     //
// Description: Add a scoped object to the chain of objects in this scope.   //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
void Scope::AddToChain(PScoped_Obj pso)
{
   pso->_undoChainNext = _undoChain;
   _undoChain = pso;
}


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scope::RegisterHelper					     //
// Description: Add a function to be called each time a scope is popped.     //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
void Scope::RegisterHelper(HelperFunc h)
{
  if (!_helpers)
    _helpers = new Array_List<HelperFunc>;

  _helperCnt++;
  _helpers->Append(h);
}


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scope::Pop							     //
// Description: Pop the top scope (calls destructor which restores objects). //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
void Scope::Pop()
{
   PScope psTop = _topScope;
   ASSERT_MSG(psTop->_prevScope != NULL,
	      ("Illegal to pop last scope off of stack."));
   _topScope = psTop->_prevScope;
   _currentScopeLevel--;
   delete psTop;
}


///////////////////////////////////////////////////////////////////////////////
// End of Scope class methods                                                //
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// Scoped_Obj class methods                                                  //
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scoped_Obj::Scoped_Obj					     //
// Description: Constructor for scoped objects.  The object is associated    //
// with a given scope, which defaults to the current top scope.              //
// Automatically adds the object to the list of objects in the scope.        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
Scoped_Obj::Scoped_Obj(PScope pscope) : 
  _pscope((pscope == NULL) ? Scope::TopScope() : pscope),
  _restore(NULL)
{
  ASSERT_MSG(_pscope != NULL, ("NULL scope pointer"));
  _pscope->AddToChain(this);
}


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scoped_Obj::Update						     //
// Description: Moves the object to the current scope and makes a copy so    //
// that the object can be restored when the current scope is popped.         //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
void Scoped_Obj::Update(void)
{
   _restore = MakeCopy();
   _pscope = Scope::TopScope();
   _pscope->AddToChain(this);
}


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Function: Scoped_Obj::Restore					     //
// Description: Removes an object from the current scope, restoring it to    //
// its previous state if a previous state was saved.  Returns the next item  //
// in the list of objects in this scope.                                     //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
PScoped_Obj Scoped_Obj::Restore(void)
{
  PScoped_Obj psoResult = _undoChainNext;
  if (_restore != NULL) {
    PScoped_Obj psoRestore = _restore->_restore;
    _pscope = _restore->_pscope;
    _undoChainNext = _restore->_undoChainNext;
    RestoreData();
    delete _restore;
    _restore = psoRestore;
  }
  else DeleteSelf();
  return psoResult;
}


///////////////////////////////////////////////////////////////////////////////
// End of Scoped_Obj class methods                                           //
///////////////////////////////////////////////////////////////////////////////
