public FunctionGenerationInfo(FunctionNode function, double relevanceLevel)
        {
            Contract.Requires<ArgumentNullException>(function != null);

            Function = function;
            RelevanceLevel = relevanceLevel;
        }
        public TemplateParserResult Parse(FunctionNode functionNode)
        {
            Contract.Requires<ArgumentNullException>(functionNode != null);
            Contract.Ensures(Contract.Result<TemplateParserResult>() != null);

            _networkContext = new TemplateParserNetworkNodeContext(functionNode);
            _currentSentence = null;
            _sentenceContext.Clear();

            return ParseNode(functionNode);
        }
        internal FunctionNode(TaleNode taleNode, string name, FunctionNode baseNode)
            : base((TalesNetwork)taleNode.Network, name, baseNode)
        {
            Network.Edges.Add(this, taleNode, Net.NetworkEdgeType.PartOf);

            _functionType = baseNode._functionType;
            _actionNodes = new FunctionNodeContextNodeCollection(this, NetworkEdgeType.Action);
            _agentNodes = new FunctionNodeContextNodeCollection(this, NetworkEdgeType.Agent);
            _recipientNodes = new FunctionNodeContextNodeCollection(this, NetworkEdgeType.Recipient);
            _locativeNodes = new FunctionNodeContextNodeCollection(this, NetworkEdgeType.Locative);
        }
        private ITemplateParserContext ReplaceFunctionContext(FunctionNode function)
        {
            Contract.Assume(_currentContext != null);

            TemplateParserDictionaryContext dictionaryContext = new TemplateParserDictionaryContext();
            // TODO: Необходимо добавить учет связи Is-Instance.
            NetworkNode[] stopNodes =
            {
                function.Network.Nodes.GetNode("Персонаж"),
                function.Network.Nodes.GetNode("Положительный персонаж"),
                function.Network.Nodes.GetNode("Отрицательный персонаж"),
                function.Network.Nodes.GetNode("Место"),
                function.Network.Nodes.GetNode("Действие")
            };
            Action<IEnumerable<NetworkNode>, IEnumerable<NetworkNode>, NetworkEdgeType> fillDictionaryAction =
                (functionNodes, contextNodes, contextType) =>
                {
                    foreach (NetworkNode functionNode in functionNodes)
                    {
                        NetworkNode contextNode = contextNodes.FirstOrDefault(
                            node => AreHaveCommonAncestor(functionNode, node, stopNodes));

                        if (contextNode != null &&
                            !functionNodes.Contains(contextNode))
                        {
                            dictionaryContext.Add(contextType, contextNode);
                        }
                        else
                        {
                            dictionaryContext.Add(contextType, functionNode);
                        }
                    }
                };

            // TODO: Пока не уверен, должны ли унаследованные контекстные вершины
            //       также появляться в списке.

            fillDictionaryAction(
                function.Agents,
                _currentContext.ResolvedPersons,
                NetworkEdgeType.Agent);

            fillDictionaryAction(
                function.Recipients,
                _currentContext.ResolvedPersons,
                NetworkEdgeType.Recipient);

            fillDictionaryAction(
                function.Locatives,
                _currentContext.ResolvedLocatives,
                NetworkEdgeType.Locative);

            fillDictionaryAction(
                function.Actions,
                _currentContext.ResolvedActions,
                NetworkEdgeType.Action);

            //fillDictionaryAction(function.Recipients, _currentContext.Persons, NetworkEdgeType.Recipient);
            //fillDictionaryAction(function.Locatives, _currentContext.Locatives, NetworkEdgeType.Locative);
            //fillDictionaryAction(function.Actions, _currentContext.Actions, NetworkEdgeType.Action);

            return dictionaryContext;
        }
        private void GetChildContextNode(
			IDictionary<FunctionNode, TemplateParserResult> parserResults,
			TaleNode currentTaleNode,
			FunctionNode baseFunctionNode,
			NetworkEdgeType edgeType,
			TemplateParserDictionaryContext newParserContext)
        {
            TemplateParserResult baseFunctionNodeParserResult = parserResults[baseFunctionNode];
            var currentTaleContextNodes = new List<NetworkNode>();
            var baseTaleContextNodes = baseFunctionNode.OutgoingEdges.GetEdges(edgeType).Select(edge => edge.EndNode);
            bool found = false;

            foreach (FunctionNode functionNode in currentTaleNode.Functions)
            {
                currentTaleContextNodes.AddRange(functionNode.OutgoingEdges.GetEdges(edgeType).Select(edge => edge.EndNode));
            }

            foreach (NetworkNode baseTaleContextNode in baseTaleContextNodes)
            {
                if (currentTaleContextNodes.Any(node => node.IsInherit(baseTaleContextNode, false)))
                {
                    NetworkNode currentNode = null;

                    while (true)
                    {
                        NetworkEdge isAEdge = baseTaleContextNode.OutgoingEdges.GetEdge(NetworkEdgeType.IsA);

                        if (isAEdge != null)
                        {
                            currentNode = isAEdge.StartNode;

                            NetworkNode childNode = currentTaleContextNodes.FirstOrDefault(node => node == currentNode || node.BaseNode == currentNode);

                            if (childNode != null)
                            {
                                found = true;
                                newParserContext.Add(edgeType, childNode);
                                break;
                            }
                        }

                        if (isAEdge == null &&
                            currentNode != null)
                        {
                            found = true;
                            newParserContext.Add(edgeType, currentNode);
                            break;
                        }
                    }
                }
            }

            if (!found)
            {
                newParserContext.Add(edgeType, baseTaleContextNodes);
            }
        }
        private string GenerateText(FunctionNode function)
        {
            Contract.Assume(_currentContext != null);

            // 1. Сначала выполняется операция замещения контекста.

            ITemplateParserContext parserContext = ReplaceFunctionContext(function);

            // 2. Запомним контекстные вершины текущей функции.
            //    В последующем они будут использоваться для определения
            //    соблюдения принципа монотонности.

            _currentContext.CurrentContextNodes.AddRange(parserContext.SelectMany(pair => pair.Value));

            // 3. Затем текст функции генерируется с учетом измененного контекста.

            if (parserContext.Count == 0)
            {
                // TODO: Контекст генерации должен заполняться в любом случае.
                throw new InvalidOperationException();
                //return _templateParser.Parse(function).Text;
            }
            else
            {
                return _templateParser.Parse(function, parserContext).Text;
            }
        }
        protected override void LoadFromXElement(XElement xNetwork)
        {
            Contract.Requires<ArgumentNullException>(xNetwork != null);

            XNamespace xNamespace = SerializableObject.XNamespace;

            XElement xNodesBase = xNetwork.Element(xNamespace + "Nodes");
            var xNodes = xNodesBase.Elements(xNamespace + "Node");
            foreach (XElement xNode in xNodes)
            {
                XAttribute xNodeKindAttribute = xNode.Attribute("nodeKind");
                NetworkNode networkNode = null;

                if (xNodeKindAttribute == null)
                {
                    //networkNode = Nodes.Add();
                    throw new SerializationException();
                }
                else
                {
                    TaleNodeKind nodeKind = (TaleNodeKind)Enum.Parse(typeof(TaleNodeKind), xNodeKindAttribute.Value);

                    switch (nodeKind)
                    {
                        case TaleNodeKind.Tale:
                            networkNode = new TaleNode(this);
                            break;

                        case TaleNodeKind.TaleItem:
                            networkNode = new TaleItemNode(this);
                            break;

                        case TaleNodeKind.Function:
                            networkNode = new FunctionNode(this);
                            break;
                    }
                }

                networkNode.LoadFromXml(xNode);

                // TODO: Необходимо избавиться от этого костыля.
                if (!Nodes.Where(node => node.Id == networkNode.Id).Any())
                {
                    Nodes.Add(networkNode);
                }
            }

            XElement xEdgesBase = xNetwork.Element(xNamespace + "Edges");
            var xEdges = xEdgesBase.Elements(xNamespace + "Edge");
            foreach (XElement xEdge in xEdges)
            {
                NetworkEdge networkEdge = new TaleItemEdge(this);

                networkEdge.LoadFromXml(xEdge);

                // TODO: Необходимо избавиться от этого костыля.
                if (!Edges.Where(edge => edge.Id == networkEdge.Id).Any())
                {
                    Edges.Add(networkEdge);
                }
            }

            SetId();

            _isDirty = false;

            _baseActionNode = (TaleItemNode)Nodes[0];
            _baseLocativeNode = (TaleItemNode)Nodes[1];
            _basePersonNode = (TaleItemNode)Nodes[2];
            _baseFunctionNode = Nodes[3];
            _baseTaleNode = Nodes[4];
            _baseTemplateNode = Nodes[5];
        }
        private TemplateParserResult ParseNode(FunctionNode functionNode)
        {
            string template = functionNode.Template;
            Lexer lexer = new Lexer(template);
            LexerResult lexerResult = null;
            StringBuilder stringBuilder = new StringBuilder(DefaultTemplateBufferSize);
            List<NetworkEdgeType> unresolvedContext = new List<NetworkEdgeType>();

            _currentSentence = new List<TemplateToken>();

            while (lexer.ReadNextToken(out lexerResult))
            {
                switch (lexerResult.Type)
                {
                    case TokenType.Letter:
                        stringBuilder.Append(lexerResult.Token);
                        break;

                    case TokenType.Colon:
                        // TODO: Костыль.
                        // В случае начала прямой речи, необходимо обновить контекст.
                        stringBuilder.Append(lexerResult.Token);

                        while (lexer.PeekNextToken(out lexerResult) &&
                               lexerResult.Type == TokenType.Space)
                        {
                            stringBuilder.Append(lexerResult.Token);
                        }

                        if (lexerResult.Type == TokenType.Quotes)
                        {
                            Contract.Assume(_currentSentence != null);
                            _sentenceContext.Add(_currentSentence);
                            _currentSentence = new List<TemplateToken>();
                            stringBuilder.Append(lexerResult.Token);
                        }
                        break;

                    case TokenType.Space:
                    case TokenType.Punctuation:
                        stringBuilder.Append(lexerResult.Token);
                        break;

                    case TokenType.Point:
                        Contract.Assume(_currentSentence != null);
                        _sentenceContext.Add(_currentSentence);
                        _currentSentence = new List<TemplateToken>();
                        stringBuilder.Append(lexerResult.Token);
                        break;

                    case TokenType.LeftBrace:
                        StringBuilder templateBuilder = new StringBuilder(128);
                        bool isOk = false;

                        while (lexer.ReadNextToken(out lexerResult))
                        {
                            if (lexerResult.Type == TokenType.RightBrace)
                            {
                                isOk = true;
                                break;
                            }

                            templateBuilder.Append(lexerResult.Token);
                        }

                        if (!isOk)
                        {
                            throw new TemplateParserException();
                        }

                        TemplateParserPluginResult parserResult = ParseTemplateItem(templateBuilder.ToString());

                        if (parserResult.Text == null)
                        {
                            unresolvedContext.AddRange(parserResult.UnresolvedContext);
                        }
                        else
                        {
                            _currentSentence.AddRange(parserResult.TemplateTokens);
                            stringBuilder.Append(parserResult.Text);
                        }
                        break;
                }
            }

            if (_currentSentence != null &&
                _currentSentence.Count > 0)
            {
                _sentenceContext.Add(_currentSentence);
            }

            return new TemplateParserResult(stringBuilder.ToString(), _sentenceContext, unresolvedContext);
        }