context: /*
   * GrGen: graph rewrite generator tool -- release GrGen.NET 4.4
   * Copyright (C) 2003-2015 Universitaet Karlsruhe, Institut fuer Programmstrukturen und Datenorganisation, LS Goos; and free programmers
   * licensed under LGPL v3 (see LICENSE.txt included in the packaging of this file)
   * www.grgen.net
   */
  
  // by Moritz Kroll, Edgar Jakumeit
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.IO;
  using Microsoft.CSharp;
  using System.CodeDom.Compiler;
  using System.Reflection;
  using de.unika.ipd.grGen.libGr;
  
  namespace de.unika.ipd.grGen.lgsp
  {
      /// <summary>
      /// An implementation of the IGraphProcessingEnvironment, to be used with LGSPGraphs.
      /// </summary>
      public class LGSPGraphProcessingEnvironment : LGSPSubactionAndOutputAdditionEnvironment, IGraphProcessingEnvironment
      {
          private LGSPTransactionManager transactionManager;
          public LGSPDeferredSequencesManager sequencesManager;
          
          private bool clearVariables = false;
          private IEdge currentlyRedirectedEdge;
  
          private IUserProxyForSequenceExecution userProxy;
          private IUserProxyForSequenceExecution compliantUserProxy = new CompliantUserProxyForSequenceExecution();
  
          protected Dictionary<IGraphElement, LinkedList<Variable>> ElementMap = new Dictionary<IGraphElement, LinkedList<Variable>>();
          protected Dictionary<String, Variable> VariableMap = new Dictionary<String, Variable>();
  
  
          public LGSPGraphProcessingEnvironment(LGSPGraph graph, LGSPActions actions)
              : base(graph, actions)
          {
              transactionManager = new LGSPTransactionManager(this);
              sequencesManager = new LGSPDeferredSequencesManager();
              SetClearVariables(true);
          }
  
          public override void Initialize(LGSPGraph graph, LGSPActions actions)
          {
              SetClearVariables(false);
              base.Initialize(graph, actions);
              SetClearVariables(true);
          }
  
          void RemovingNodeListener(INode node)
          {
              LGSPNode lgspNode = (LGSPNode)node;
              if((lgspNode.lgspFlags & (uint)LGSPElemFlags.HAS_VARIABLES) != 0)
              {
                  foreach(Variable var in ElementMap[lgspNode])
                      VariableMap.Remove(var.Name);
                  ElementMap.Remove(lgspNode);
                  lgspNode.lgspFlags &= ~(uint)LGSPElemFlags.HAS_VARIABLES;
              }
          }
  
          void RemovingEdgeListener(IEdge edge)
          {
              if(edge == currentlyRedirectedEdge)
              {
                  currentlyRedirectedEdge = null;
                  return; // edge will be added again before other changes, keep the variables
              }
  
              LGSPEdge lgspEdge = (LGSPEdge)edge;
              if((lgspEdge.lgspFlags & (uint)LGSPElemFlags.HAS_VARIABLES) != 0)
              {
                  foreach(Variable var in ElementMap[lgspEdge])
                      VariableMap.Remove(var.Name);
                  ElementMap.Remove(lgspEdge);
                  lgspEdge.lgspFlags &= ~(uint)LGSPElemFlags.HAS_VARIABLES;
              }
          }
  
          void RetypingNodeListener(INode oldNode, INode newNode)
          {
              LGSPNode oldLgspNode = (LGSPNode)oldNode;
              LGSPNode newLgspNode = (LGSPNode)newNode;
              if((oldLgspNode.lgspFlags & (uint)LGSPElemFlags.HAS_VARIABLES) != 0)
              {
                  LinkedList<Variable> varList = ElementMap[oldLgspNode];
                  foreach(Variable var in varList)
                      var.Value = newLgspNode;
                  ElementMap.Remove(oldLgspNode);
                  ElementMap[newLgspNode] = varList;
                  newLgspNode.lgspFlags |= (uint)LGSPElemFlags.HAS_VARIABLES;
              }
          }
  
          void RetypingEdgeListener(IEdge oldEdge, IEdge newEdge)
          {
              LGSPEdge oldLgspEdge = (LGSPEdge)oldEdge;
              LGSPEdge newLgspEdge = (LGSPEdge)newEdge;
              if((oldLgspEdge.lgspFlags & (uint)LGSPElemFlags.HAS_VARIABLES) != 0)
              {
                  LinkedList<Variable> varList = ElementMap[oldLgspEdge];
                  foreach(Variable var in varList)
                      var.Value = newLgspEdge;
                  ElementMap.Remove(oldLgspEdge);
                  ElementMap[newLgspEdge] = varList;
                  newLgspEdge.lgspFlags |= (uint)LGSPElemFlags.HAS_VARIABLES;
              }
          }
  
          void RedirectingEdgeListener(IEdge edge)
          {
              currentlyRedirectedEdge = edge;
          }
  
          void ClearGraphListener()
          {
              foreach(INode node in graph.Nodes)
              {
                  LGSPNode lgspNode = (LGSPNode)node;
                  if((lgspNode.lgspFlags & (uint)LGSPElemFlags.HAS_VARIABLES) != 0)
                  {
                      foreach(Variable var in ElementMap[lgspNode])
                          VariableMap.Remove(var.Name);
                      ElementMap.Remove(lgspNode);
                      lgspNode.lgspFlags &= ~(uint)LGSPElemFlags.HAS_VARIABLES;
                  }
              }
  
              foreach(IEdge edge in graph.Edges)
              {
                  LGSPEdge lgspEdge = (LGSPEdge)edge;
                  if((lgspEdge.lgspFlags & (uint)LGSPElemFlags.HAS_VARIABLES) != 0)
                  {
                      foreach(Variable var in ElementMap[lgspEdge])
                          VariableMap.Remove(var.Name);
                      ElementMap.Remove(lgspEdge);
                      lgspEdge.lgspFlags &= ~(uint)LGSPElemFlags.HAS_VARIABLES;
                  }
              }
          }
  
          public ITransactionManager TransactionManager
          { 
              get { return transactionManager; }
          }
          
          public void CloneGraphVariables(IGraph old, IGraph clone)
          {
              // TODO: implement
          }
  
          public override void Custom(params object[] args)
          {
              if(args.Length == 0) goto invalidCommand;
  
              bool newClearVariables;
              switch((String)args[0])
              {
                  case "set_max_matches":
                      base.Custom(args);
                      return;
  
                  case "adaptvariables":
                      if(args.Length != 2)
                          throw new ArgumentException("Usage: adaptvariables <bool>\n"
                                  + "If <bool> == true, variables are cleared (nulled) if they contain\n"
                                  + "graph elements which are removed from the graph, and rewritten to\n"
                                  + "the new element on retypings. Saves from outdated and dangling\n"
                                  + "variables at the cost of listening to node and edge removals and retypings.\n"
                                  + "Dangerous! Disable this only if you don't work with variables.");
  
                      if(!bool.TryParse((String)args[1], out newClearVariables))
                          throw new ArgumentException("Illegal bool value specified: \"" + (String)args[1] + "\"");
                      SetClearVariables(newClearVariables);
                      return;
              }
  
          invalidCommand:
              string errorMsg = "";
              try
              {
                  base.Custom(args);
              }
              catch(ArgumentException ex)
              {
                  errorMsg = ex.Message;
              }
  
              throw new ArgumentException(errorMsg
                  + "- adaptvariables: Sets whether variables are cleared if they contain\n"
                  + "     elements which are removed from the graph, and rewritten to\n"
                  + "     the new element on retypings.\n");
          }
  
          internal void SetClearVariables(bool newClearVariables)
          {
              if(newClearVariables == clearVariables)
                  return;
  
              if(newClearVariables)
              {
                  // start listening to remove events so we can clear variables if they occur
                  graph.OnRemovingNode += RemovingNodeListener;
                  graph.OnRemovingEdge += RemovingEdgeListener;
                  graph.OnRetypingNode += RetypingNodeListener;
                  graph.OnRetypingEdge += RetypingEdgeListener;
                  graph.OnRedirectingEdge += RedirectingEdgeListener;
                  graph.OnClearingGraph += ClearGraphListener;
              }
              else
              {
                  // stop listening to remove events, we can't clear variables anymore when they happen
                  graph.OnRemovingNode -= RemovingNodeListener;
                  graph.OnRemovingEdge -= RemovingEdgeListener;
                  graph.OnRetypingNode -= RetypingNodeListener;
                  graph.OnRetypingEdge -= RetypingEdgeListener;
                  graph.OnRedirectingEdge -= RedirectingEdgeListener;
                  graph.OnClearingGraph -= ClearGraphListener;
              }
          }
  
  
          public int ApplyRewrite(RuleInvocationParameterBindings paramBindings, int which, int localMaxMatches, bool special, bool test, List<FilterCall> filters)
          {
              int curMaxMatches = (localMaxMatches > 0) ? localMaxMatches : MaxMatches;
  
              object[] parameters;
              if(paramBindings.ArgumentExpressions.Length > 0)
              {
                  parameters = paramBindings.Arguments;
                  for(int i = 0; i < paramBindings.ArgumentExpressions.Length; i++)
                  {
                      if(paramBindings.ArgumentExpressions[i] != null)
                          parameters[i] = paramBindings.ArgumentExpressions[i].Evaluate(this);
                  }
              }
              else parameters = null;
  
              if(paramBindings.Subgraph != null)
                  SwitchToSubgraph((IGraph)paramBindings.Subgraph.GetVariableValue(this));
  
  #if DEBUGACTIONS || MATCHREWRITEDETAIL
              PerformanceInfo.StartLocal();
  #endif
              IMatches matches = paramBindings.Action.Match(this, curMaxMatches, parameters);
  #if DEBUGACTIONS || MATCHREWRITEDETAIL
              PerformanceInfo.StopMatch();
  #endif
              for(int i=0; i<filters.Count; ++i)
                  paramBindings.Action.Filter(this, matches, filters[i]);
  
  
gt:             Matched(matches, null, special);