/*
		private ProjectMethod FindMethodSymbolAndProjectInSolution(MethodDescriptor methodDescriptor, CallGraph<MethodDescriptor, ALocation> callgraph)
        {
            return RoslynSymbolFactory.FindMethodSymbolAndProjectInSolution(this.Solution, methodDescriptor);
        }

        #region Just a test to discard about programation of a deletion o a croncrete type
        internal void RemoveTypesFromNode(MethodDescriptor methodDescriptor, string text)
        {
            var m = RoslynSymbolFactory.FindMethodSymbolInSolution(this.Solution, methodDescriptor);
            var am = new AMethod(m);
            var entityProcessor = (MethodEntityProcessor<ANode, AType, AMethod>)
                this.Dispatcher.GetEntityWithProcessor(EntityFactory<AMethod>.Create(am));
            var entity = entityProcessor.MethodEntity;
            var pg = entity.PropGraph;
            ANode n = pg.FindNodeInPropationGraph(text);
            var statementProcessor = new StatementProcessor<ANode, AType, AMethod>(am, entity.ReturnVariable, entity.ThisRef, entity.ParameterNodes, pg);
            
            statementProcessor.RegisterRemoveNewExpressionAssignment(n);
            // entity.RemoveCallees();
            entityProcessor.DoDelete();

            //entity.InvalidateCaches();
        }

        internal void RemoveAsignment(MethodDescriptor methodDescriptor, string p1, string p2)
        {
            var roslynMethod = RoslynSymbolFactory.FindMethodSymbolInSolution(this.Solution, methodDescriptor);
            var aMethod = new AMethod(roslynMethod);
            var entityProcessor = this.Dispatcher.GetEntityWithProcessor(
                EntityFactory<AMethod>.Create(aMethod)) as MethodEntityProcessor<ANode, AType, AMethod>;
            var entity = entityProcessor.MethodEntity;
            
            var syntaxNode = Utils.FindMethodDeclaration(aMethod);

            var nodes = syntaxNode.DescendantNodes().OfType<AssignmentExpressionSyntax>();
            var node = nodes.First(a => a.Left.ToString() == p1 && a.Right.ToString() == p2);

            ANode lhs = entity.PropGraph.FindNodeInPropationGraph(p1);
            ANode rhs = entity.PropGraph.FindNodeInPropationGraph(p2);

            var statementProcessor = new StatementProcessor<ANode, AType, AMethod>(aMethod, 
                    entity.ReturnVariable, entity.ThisRef, entity.ParameterNodes, entity.PropGraph);

            statementProcessor.RegisterRemoveAssignment(lhs, rhs);
            entityProcessor.DoDelete();

            //entity.InvalidateCaches();
        }

        /// <summary>
        /// A test of how we should proceed when a method is modified
        /// </summary>
        /// <param name="methodDescriptor"></param>
        /// <param name="newCode"></param>
        internal void UpdateMethod(MethodDescriptor methodDescriptor, string newCode, CallGraph<MethodDescriptor, ALocation> callgraph)
        {
            // Find the method and project of the method to be updated
            var projectMethdod = FindMethodSymbolAndProjectInSolution(methodDescriptor, callgraph);
            var oldRoslynMethod = projectMethdod.Method;
            var project = projectMethdod.Project;
            
            var aMethod = new AMethod(oldRoslynMethod);
            //entityProcessor.MethodEntity.Save(roslynMethod.ContainingType.Name + "_" + roslynMethod.Name + "_orig.dot");
            //--------------------------------------------------------------------------------------------------------
            // This is to mimic a change in the method. We need to create a new comp
            var methodDecSyntax = Utils.FindMethodDeclaration(aMethod);   
            var newMethodBody = SyntaxFactory.ParseStatement(newCode) as BlockSyntax;            
            // here we update the method body
            var newMethodSyntax = methodDecSyntax.WithBody(newMethodBody);
            // This is a trick to recover the part of the syntax tree after replacing the project syntax tree
            var annotation = new SyntaxAnnotation("Hi");
            newMethodSyntax = newMethodSyntax.WithAdditionalAnnotations(annotation);
            // update the syntax tree
            var oldRoot = methodDecSyntax.SyntaxTree.GetRoot();
            var newRoot = oldRoot.ReplaceNode(methodDecSyntax, newMethodSyntax);
            // Compute the new compilation and semantic model
            var oldCompilation = project.GetCompilationAsync().Result;
            var newCompilation = oldCompilation.ReplaceSyntaxTree(oldRoot.SyntaxTree, newRoot.SyntaxTree);
            var newSemanticModel = newCompilation.GetSemanticModel(newRoot.SyntaxTree);
            // Recover the method node
            var recoveredMethodNode = newRoot.GetAnnotatedNodes(annotation).Single();
            //////////////////////////////////////////////////////

            // Get the entity corresponding to the new (updated) method
            var updatedRoslynMethod = newSemanticModel.GetDeclaredSymbol(recoveredMethodNode) as IMethodSymbol;

            PerformUpdate(oldRoslynMethod, newSemanticModel, updatedRoslynMethod);
        }

        public void PerformUpdate(IMethodSymbol oldRoslynMethod, SemanticModel newSemanticModel, IMethodSymbol newRoslynMethod)
        {
            var aMethod = new AMethod(oldRoslynMethod);
            // Get the entity and processor 
            var entityDescriptor = EntityFactory<AMethod>.Create(aMethod);
            var entityProcessor = this.Dispatcher.GetEntityWithProcessor(entityDescriptor) as MethodEntityProcessor<ANode, AType, AMethod>;
            var oldMethodEntity = entityProcessor.MethodEntity;
            var syntaxProcessor = new MethodSyntaxProcessor(newRoslynMethod, newSemanticModel, Dispatcher);
            var newEntity = syntaxProcessor.ParseMethod() as MethodEntity<ANode, AType, AMethod>;

            // I propagate the removal of the node that represent the input parameters of the callees
            // This is to simulate the deletion of the method. 
            // Do I need to do this? 
            var propGraphOld = oldMethodEntity.PropGraph;
            var invoOld = GetInvocations(propGraphOld);
            foreach (var invocation in invoOld)
            {
                foreach (var aCallee in invocation.ComputeCalleesForNode(propGraphOld))
                {
                    RemoveCall(aCallee,invocation);
                }
            }
            // This is to force the callers to call me
            //foreach(var callerConext in  entity.Callers)
            //{
            //    var caller = callerConext.Caller;
            //    var callerEntityProcessor = Dispatcher.GetEntityWithProcessor(new MethodEntityDescriptor<AMethod>(caller));
            //    callerEntityProcessor.DoAnalysis(); 
            //}
            // Here we propagate the removal of the retvalue of the method we eliminate
            if (oldMethodEntity.ReturnVariable != null)
            {
                var returnTypes = oldMethodEntity.GetTypes(oldMethodEntity.ReturnVariable);
                foreach (var callersContext in oldMethodEntity.Callers)
                {
                    RemoveReturnValuesFromCallerLHS(returnTypes, callersContext.Caller, callersContext.CallLHS);
                }
            }

            this.Dispatcher.RegisterEntity(entityDescriptor, newEntity);
            // I get an entity processor to analyze the new entity
            var newEntityProcessor = Dispatcher.GetEntityWithProcessor(entityDescriptor) as MethodEntityProcessor<ANode, AType, AMethod>;
            /// I need to copy all the input data from the old method 
            newEntity.CopyInterfaceDataAndCallers(oldMethodEntity);
            newEntityProcessor.DoAnalysis();

            var propGraphNew = newEntity.PropGraph;
            var invoNew = GetInvocations(propGraphNew);
            //newEntityProcessor.MethodEntity.Save(oldRoslynMethod.ContainingType.Name + "_" + oldRoslynMethod.Name + "_d.dot");
            oldMethodEntity.InvalidateCaches();
        }

        private void RemoveReturnValuesFromCallerLHS(ISet<AType> returnTypes, AMethod aCaller, ANode lhs)
        {
            var entityProcessorforCaller = (MethodEntityProcessor<ANode, AType, AMethod>)
                Dispatcher.GetEntityWithProcessor(EntityFactory<AMethod>.Create((AMethod)aCaller));
            var callerEntity = entityProcessorforCaller.MethodEntity;

            var statementProcessor = new StatementProcessor<ANode, AType, AMethod>((AMethod)aCaller,
                    callerEntity.ReturnVariable, callerEntity.ThisRef, callerEntity.ParameterNodes,
                    callerEntity.PropGraph);
            //callerEntity.PropGraph.
            statementProcessor.RegisterRemoveTypes(lhs, returnTypes);
            //callerEntity.InvalidateCaches();
            entityProcessorforCaller.DoDelete();
        }

        private void RemoveCall(AMethod aCallee, AInvocationExp<AMethod,AType,ANode> invocation)
        {
            var entityProcessorforCallee = Dispatcher.GetEntityWithProcessor(EntityFactory<AMethod>.Create((AMethod)aCallee)) as MethodEntityProcessor<ANode, AType, AMethod>;
            var calleeEntity = entityProcessorforCallee.MethodEntity;
            calleeEntity.InvalidateCaches();
            // Delete progragation of arguments and receiver
            var statementProcessor = new StatementProcessor<ANode, AType, AMethod>((AMethod)aCallee,
                    calleeEntity.ReturnVariable, calleeEntity.ThisRef, calleeEntity.ParameterNodes,
                    calleeEntity.PropGraph);
            foreach (var p in calleeEntity.ParameterNodes)
            {
                statementProcessor.RegisterRemoveNewExpressionAssignment(p);
            }
            if (calleeEntity.ThisRef != null)
                statementProcessor.RegisterRemoveNewExpressionAssignment(calleeEntity.ThisRef);
            // entity.RemoveCallees();
            entityProcessorforCallee.DoDelete();
            var context = new CallConext<AMethod, ANode>(invocation.Caller,invocation.LHS,invocation.CallNode);
            calleeEntity.RemoveFromCallers(context);
        }

        private static List<AInvocationExp<AMethod, AType, ANode>> GetInvocations(PropagationGraph<ANode, AType, AMethod> propGraphOld)
        {
            var invoList = new List<AInvocationExp<AMethod, AType, ANode>>();
            foreach (var oldCall in propGraphOld.CallNodes)
            {
                var oldCallInfo = propGraphOld.GetInvocationInfo(oldCall);
                invoList.Add(oldCallInfo);
            }
            return invoList;
        }

        #endregion
*/

        #region Callgraph
        private static void UpdateCallGraph(IEntityProcessor entityProcessor, 
                                            CallGraph<MethodDescriptor, LocationDescriptor> callgraph, Solution solution)
        {
            Contract.Assert(entityProcessor != null);
            var methodEntity = (MethodEntity)entityProcessor.Entity;
            Contract.Assert(methodEntity.MethodDescriptor != null);
            var callerMethod = methodEntity.MethodDescriptor;

            var pair = ProjectCodeProvider.GetProjectProviderAndSyntaxAsync(callerMethod, solution).Result;
			if (pair != null)
			{
				var codeProvider = pair.Item1;
				// Hack
				var methodEntityProcessor = new MethodEntityProcessor(methodEntity, ((MethodEntityProcessor)entityProcessor).dispatcher, codeProvider);
				//(MethodEntityProcessor)entityProcessor;
				var callSitesForMethod = methodEntityProcessor.GetCalleesInfo();
				foreach (var callSiteNode in callSitesForMethod.Keys)
				{
					foreach (var calleeAMethod in callSitesForMethod[callSiteNode])
					{
						//var callee = Utils.FindMethodSymbolDeclaration(this.Solution, ((AMethod)calleeAMethod).RoslynMethod);
						var callee = calleeAMethod;
						Logger.Instance.Log("SolutionAnalyzer", "UpdateCallGraph", "\t-> {0}", callee);
						callgraph.AddCallAtLocation(callSiteNode.LocationDescriptor, callerMethod, callee);
					}
				}
			}
        }
        private static CallGraph<MethodDescriptor, LocationDescriptor> ReBuildCallGraph(Dispatcher dispatcher, Solution solution)
        {
            var callgraph = new CallGraph<MethodDescriptor, LocationDescriptor>();
            // pg.PropagateDeletionOfNodes();
            foreach (var e in dispatcher.GetAllEntites())
            {
                var entityProcessor = new MethodEntityProcessor((MethodEntity)e, dispatcher);// e.GetEntityProcessor(dispatcher);
                var methodEntity = (MethodEntity)entityProcessor.Entity;
                if (methodEntity.MethodDescriptor.ToString().Contains("Main"))
                {
                    callgraph.AddRootMethod(methodEntity.MethodDescriptor);
                }
                // Updates the callGraph
                UpdateCallGraph(entityProcessor, callgraph, solution);
            }
            //callgraph.Save("cg_d.dot");

            return callgraph;
        }
        /// <summary>
        /// Try to get the roslyn methods on the fly
        /// Currently works with one project.
        /// </summary>
        public void AnalyzeOnDemand()
        {
			Contract.Assert(this.Dispatcher != null);
			var cancellationToken = new CancellationTokenSource();
			var projectIDs = this.Solution.GetProjectDependencyGraph().GetTopologicallySortedProjects(cancellationToken.Token);
			foreach (var projectId in projectIDs)
			{
				var project = this.Solution.GetProject(projectId);
				var compilation = project.GetCompilationAsync().Result;

                var triple = ProjectCodeProvider.GetProviderContainingEntryPointAsync(project, cancellationToken.Token).Result;
                var provider = triple.Item1;
                IMethodSymbol mainSymbol = triple.Item2;
                var tree = triple.Item3;
				if (provider != null)
				{
                    var model = provider.Compilation.GetSemanticModel(tree);
					cancellationToken.Cancel(); // cancel out outstanding processing tasks
                    var methodVisitor = new MethodSyntaxProcessor(model, tree, mainSymbol);

					var mainMethodEntity = methodVisitor.ParseMethod();
                    this.Dispatcher.RegisterEntity(mainMethodEntity.EntityDescriptor, mainMethodEntity);
                    var mainEntityProcessor = new MethodEntityProcessor((MethodEntity)mainMethodEntity, this.Dispatcher);
                    //var mainMethodDescriptor =  new MethodDescriptor(mainSymbol);
                    //var mainMethodEntityDescriptor = EntityFactory.Create(mainMethodDescriptor);
                    //var mainEntityProcessor = this.Dispatcher.GetEntityWithProcessorAsync(mainMethodEntityDescriptor).Result ;

					// Just a test
					//mainEntityProcessor.MethodEntity.CurrentContext = new CallConext<AMethod, ANode>(mainEntityProcessor.MethodEntity.Method, null, null);

					mainEntityProcessor.DoAnalysis();

					Logger.Instance.Log("SolutionAnalyzer", "AnalyzeOnDemand", "--- Done with propagation ---");
				}
			}

			if (this.Dispatcher is QueueingDispatcher)
            {
                var qd = (QueueingDispatcher)this.Dispatcher;
                while (!qd.IsDoneProcessing)
                {
                    Logger.Instance.Log("SolutionAnalyzer", "AnalyzeOnDemand", "Waiting for the queue to empty up...");
                    Thread.Sleep(1000);
                }
            }

        }