text: ﻿//========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: 
  //
  //=============================================================================
  
  #include "DmElementFramework.h"
  #include "datamodel.h"
  
  // memdbgon must be the last include file in a .cpp file!!!
  #include "tier0/memdbgon.h"
  
  
  //-----------------------------------------------------------------------------
  // Singleton instance
  //-----------------------------------------------------------------------------
  static CDmElementFramework g_DmElementFramework;
  CDmElementFramework *g_pDmElementFrameworkImp = &g_DmElementFramework;
  IDmElementFramework *g_pDmElementFramework = &g_DmElementFramework;
  
  
  //-----------------------------------------------------------------------------
  // Constructor
  //-----------------------------------------------------------------------------
  CDmElementFramework::CDmElementFramework() : m_phase(PH_EDIT), m_dirtyElements(128, 256) {
  }
  
  
  //-----------------------------------------------------------------------------
  // Methods of IAppSystem
  //-----------------------------------------------------------------------------
  bool CDmElementFramework::Connect(CreateInterfaceFn factory) {
      return true;
  }
  
  void CDmElementFramework::Disconnect() {
  }
  
  void *CDmElementFramework::QueryInterface(const char *pInterfaceName) {
      if (!V_strcmp(pInterfaceName, VDMELEMENTFRAMEWORK_VERSION))
          return (IDmElementFramework *) this;
  
      return NULL;
  }
  
  InitReturnVal_t CDmElementFramework::Init() {
      return INIT_OK;
  }
  
  void CDmElementFramework::Shutdown() {
      m_dependencyGraph.Cleanup();
  }
  
  
  //-----------------------------------------------------------------------------
  // element framework phase transition methods
  //-----------------------------------------------------------------------------
  void CDmElementFramework::EditApply() {
      g_pDataModelImp->RemoveUnreferencedElements();
  }
  
  void CDmElementFramework::Resolve(bool clearDirtyFlags) {
      int nCount = m_dirtyElements.Count();
      for (int ei = 0; ei < nCount; ++ei) {
          DmElementHandle_t h = m_dirtyElements[ei];
          CDmElement *pElement = g_pDataModel->GetElement(h);
          if (!pElement)
              continue;
  
          pElement->Resolve();
  
          if (clearDirtyFlags) {
              CDmeElementAccessor::MarkDirty(pElement, false); // marks element clean
              CDmeElementAccessor::MarkAttributesClean(pElement); // marks all attributes clean
          }
      }
  
      if (clearDirtyFlags) {
          m_dirtyElements.RemoveAll();
      }
  }
  
  
  //-----------------------------------------------------------------------------
  // Returns the current phase
  //-----------------------------------------------------------------------------
  DmPhase_t CDmElementFramework::GetPhase() {
      return FastGetPhase();
  }
  
  void CDmElementFramework::SetOperators(const CUtlVector<IDmeOperator *> &operators) {
      VPROF("CDmElementFramework::SetOperators()");
      m_dependencyGraph.Reset(operators);
  }
  
  void CDmElementFramework::BeginEdit() {
      Assert(m_phase == PH_EDIT || m_phase == PH_OUTPUT);
  
      if (m_phase == PH_EDIT) {
          m_phase = PH_EDIT_APPLY;
          EditApply();
  
          m_phase = PH_EDIT_RESOLVE;
          Resolve(false);
      }
  
      m_phase = PH_EDIT;
  }
  
  void CDmElementFramework::Operate(bool bResolve) {
      VPROF("CDmElementFramework::Operate");
  
      Assert(m_phase == PH_EDIT || m_phase == PH_OUTPUT);
  
      if (m_phase == PH_EDIT) {
          {
              VPROF("CDmElementFramework::PH_EDIT_APPLY");
              m_phase = PH_EDIT_APPLY;
              EditApply();
          }
  
          {
              VPROF("CDmElementFramework::PH_EDIT_RESOLVE");
              m_phase = PH_EDIT_RESOLVE;
              Resolve(false);
          }
      }
  
      {
          VPROF("CDmElementFramework::PH_DEPENDENCY");
          m_phase = PH_DEPENDENCY;
          bool cycle = m_dependencyGraph.CullAndSortOperators();
          if (cycle) {
              Warning("Operator cycle found during dependency graph traversal!\n");
          }
      }
  
      {
          VPROF("CDmElementFramework::PH_OPERATE");
          m_phase = PH_OPERATE;
          const CUtlVector<IDmeOperator *> &operatorsToRun = m_dependencyGraph.GetSortedOperators();
          uint on = operatorsToRun.Count();
          for (uint oi = 0; oi < on; ++oi) {
              operatorsToRun[oi]->Operate();
          }
      }
  
      if (bResolve) {
          VPROF("CDmElementFramework::PH_OPERATE_RESOLVE");
          m_phase = PH_OPERATE_RESOLVE;
          Resolve(true);
  
          m_phase = PH_OUTPUT;
      }
  }
  
  void CDmElementFramework::Resolve() {
      VPROF("CDmElementFramework::Resolve");
  
      Assert(m_phase == PH_OPERATE);
  
      m_phase = PH_OPERATE_RESOLVE;
      Resolve(true);
  
      m_phase = PH_OUTPUT;
  }
  
  void CDmElementFramework::AddElementToDirtyList(DmElementHandle_t hElement) {
      m_dirtyElements.AddToTail(hElement);
  }
  
  void CDmElementFramework::RemoveCleanElementsFromDirtyList() {
      int nCount = m_dirtyElements.Count();
      while (--nCount >= 0) {
          DmElementHandle_t h = m_dirtyElements[nCount];
          CDmElement *pElement = g_pDataModel->GetElement(h);
          if (!pElement)
              continue;
  
          if (!CDmeElementAccessor::IsDirty(pElement)) {
              m_dirtyElements.FastRemove(nCount);
          }
      }
  }
  