<commit_before>﻿/*
   Copyright 2012-2019 <NAME>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RDFSharp.Model;

namespace RDFSharp.Query
{

    /// <summary>
    /// RDFPropertyPath represents a chain of properties connecting two terms in a RDF datasource.
    /// </summary>
    public class RDFPropertyPath : RDFPatternGroupMember
    {

        #region Properties
        /// <summary>
        /// Start of the path
        /// </summary>
        public RDFPatternMember Start { get; internal set; }

        /// <summary>
        /// Steps of the path
        /// </summary>
        internal List<RDFPropertyPathStep> Steps { get; set; }

        /// <summary>
        /// Depth of the path
        /// </summary>
        internal Int32 Depth { get; set; }

        /// <summary>
        /// End of the path
        /// </summary>
        public RDFPatternMember End { get; internal set; }
        #endregion

        #region Ctors
        /// <summary>
        /// Default-ctor to build a path between the given terms
        /// </summary>
        public RDFPropertyPath(RDFPatternMember start, RDFPatternMember end)
        {

            //Start
            if (start != null)
            {
                if (start is RDFResource || start is RDFVariable)
                {
                    this.Start = start;
                }
                else
                {
                    throw new RDFQueryException("Cannot create RDFPropertyPath because given \"start\" parameter is neither a resource or a variable.");
                }
            }
            else
            {
                throw new RDFQueryException("Cannot create RDFPropertyPath because given \"start\" parameter is null.");
            }

            //Steps
            this.Steps = new List<RDFPropertyPathStep>();

            //Depth
            this.Depth = 0;

            //End
            if (end != null)
            {
                if (end is RDFResource || end is RDFVariable)
                {
                    this.End = end;
                }
                else
                {
                    throw new RDFQueryException("Cannot create RDFPropertyPath because given \"end\" parameter is neither a resource or a variable.");
                }
            }
            else
            {
                throw new RDFQueryException("Cannot create RDFPropertyPath because given \"end\" parameter is null.");
            }

        }
        #endregion

        #region Interfaces
        /// <summary>
        /// Gives the string representation of the path
        /// </summary>
        public override String ToString()
        {
            return this.ToString(new List<RDFNamespace>());
        }
        internal String ToString(List<RDFNamespace> prefixes)
        {
            return RDFQueryPrinter.PrintPropertyPath(this, prefixes);
        }
        #endregion

        #region Methods
        /// <summary>
        /// Adds the given alternative steps to the path. If only one is given, it is considered sequence.
        /// </summary>
        public RDFPropertyPath AddAlternativeSteps(List<RDFPropertyPathStep> alternativeSteps)
        {
            //Avoid chaining of alternative steps
            if (this.Steps.LastOrDefault()?.StepFlavor == RDFQueryEnums.RDFPropertyPathStepFlavors.Alternative)
            {
                RDFQueryEvents.RaiseGENERICQueryEvaluation("AddAlternativeSteps: chaining of alternative steps detected, discarding last ones.");
                return this;
            }   

            if (alternativeSteps != null && alternativeSteps.Any())
            {
                this.Depth++;
                if (alternativeSteps.Count == 1)
                {
                    this.Steps.Add(alternativeSteps[0].SetOrdinal(this.Steps.Count)
                                                      .SetFlavor(RDFQueryEnums.RDFPropertyPathStepFlavors.Sequence));
                }
                else
                {
                    alternativeSteps.ForEach(alternativeStep =>
                    {
                        this.Steps.Add(alternativeStep.SetOrdinal(this.Steps.Count)
                                                      .SetFlavor(RDFQueryEnums.RDFPropertyPathStepFlavors.Alternative));
                    });
                }

                //Avoid evaluability of ground property paths
                if (this.Start is RDFVariable || this.End is RDFVariable || this.Depth > 1)
                {
                    this.IsEvaluable = true;
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddAlternativeSteps: non-ground property path detected, evaluability granted or confirmed.");
                }   
                else
                { 
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddAlternativeSteps: ground property path detected, evaluability not granted.");
                }
            }
            return this;
        }

        /// <summary>
        /// Adds the given sequence step to the path
        /// </summary>
        public RDFPropertyPath AddSequenceStep(RDFPropertyPathStep sequenceStep)
        {
            if (sequenceStep != null)
            {
                this.Depth++;
                this.Steps.Add(sequenceStep.SetOrdinal(this.Steps.Count)
                                           .SetFlavor(RDFQueryEnums.RDFPropertyPathStepFlavors.Sequence));

                //Avoid evaluability of ground property paths
                if (this.Start is RDFVariable || this.End is RDFVariable || this.Depth > 1)
                {
                    this.IsEvaluable = true;
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddSequenceStep: non-ground property path detected, evaluability granted or confirmed.");
                }   
                else
                { 
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddSequenceStep: ground property path detected, evaluability not granted.");
                }
            }
            return this;
        }

        /// <summary>
        /// Gets the list of patterns corresponding to the path
        /// </summary>
        internal List<RDFPattern> GetPatternList()
        {
            List<RDFPattern> patterns = new List<RDFPattern>();

            #region Single Property
            if (this.Steps.Count == 1)
            {

                //InversePath (swap start/end)
                if (this.Steps[0].IsInverseStep)
                {
                    patterns.Add(new RDFPattern(this.End, this.Steps[0].StepProperty, this.Start));
                }

                //Path
                else
                {
                    patterns.Add(new RDFPattern(this.Start, this.Steps[0].StepProperty, this.End));
                }

            }
            #endregion

            #region Multiple Properties<commit_msg>#65 Optimize new depth logics of property paths<commit_after>﻿/*
   Copyright 2012-2019 <NAME>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RDFSharp.Model;

namespace RDFSharp.Query
{

    /// <summary>
    /// RDFPropertyPath represents a chain of properties connecting two terms in a RDF datasource.
    /// </summary>
    public class RDFPropertyPath : RDFPatternGroupMember
    {

        #region Properties
        /// <summary>
        /// Start of the path
        /// </summary>
        public RDFPatternMember Start { get; internal set; }

        /// <summary>
        /// Steps of the path
        /// </summary>
        internal List<RDFPropertyPathStep> Steps { get; set; }

        /// <summary>
        /// Depth of the path
        /// </summary>
        internal Int32 Depth { get; set; }

        /// <summary>
        /// End of the path
        /// </summary>
        public RDFPatternMember End { get; internal set; }
        #endregion

        #region Ctors
        /// <summary>
        /// Default-ctor to build a path between the given terms
        /// </summary>
        public RDFPropertyPath(RDFPatternMember start, RDFPatternMember end)
        {

            //Start
            if (start != null)
            {
                if (start is RDFResource || start is RDFVariable)
                {
                    this.Start = start;
                }
                else
                {
                    throw new RDFQueryException("Cannot create RDFPropertyPath because given \"start\" parameter is neither a resource or a variable.");
                }
            }
            else
            {
                throw new RDFQueryException("Cannot create RDFPropertyPath because given \"start\" parameter is null.");
            }

            //Steps
            this.Steps = new List<RDFPropertyPathStep>();

            //Depth
            this.Depth = 0;

            //End
            if (end != null)
            {
                if (end is RDFResource || end is RDFVariable)
                {
                    this.End = end;
                }
                else
                {
                    throw new RDFQueryException("Cannot create RDFPropertyPath because given \"end\" parameter is neither a resource or a variable.");
                }
            }
            else
            {
                throw new RDFQueryException("Cannot create RDFPropertyPath because given \"end\" parameter is null.");
            }

        }
        #endregion

        #region Interfaces
        /// <summary>
        /// Gives the string representation of the path
        /// </summary>
        public override String ToString()
        {
            return this.ToString(new List<RDFNamespace>());
        }
        internal String ToString(List<RDFNamespace> prefixes)
        {
            return RDFQueryPrinter.PrintPropertyPath(this, prefixes);
        }
        #endregion

        #region Methods
        /// <summary>
        /// Adds the given alternative steps to the path. If only one is given, it is considered sequence.
        /// </summary>
        public RDFPropertyPath AddAlternativeSteps(List<RDFPropertyPathStep> alternativeSteps)
        {
            if (alternativeSteps != null && alternativeSteps.Any())
            {
                #region Depth Guard
                if (this.Steps.Count == 0 
                        || alternativeSteps.Count == 1
                            || this.Steps.LastOrDefault()?.StepFlavor == RDFQueryEnums.RDFPropertyPathStepFlavors.Sequence)
                {
                    this.Depth++;
                }
                #endregion

                #region Steps Update
                if (alternativeSteps.Count == 1)
                {
                    this.Steps.Add(alternativeSteps[0].SetOrdinal(this.Steps.Count)
                                                      .SetFlavor(RDFQueryEnums.RDFPropertyPathStepFlavors.Sequence));
                }
                else
                {
                    alternativeSteps.ForEach(alternativeStep =>
                    {
                        this.Steps.Add(alternativeStep.SetOrdinal(this.Steps.Count)
                                                      .SetFlavor(RDFQueryEnums.RDFPropertyPathStepFlavors.Alternative));
                    });
                }
                #endregion

                #region Evaluability Guard
                if (this.Start is RDFVariable || this.End is RDFVariable || this.Depth > 1)
                {
                    this.IsEvaluable = true;
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddAlternativeSteps: non-ground property path detected, evaluability granted or confirmed.");
                }   
                else
                { 
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddAlternativeSteps: ground property path detected, evaluability not granted.");
                }
                #endregion
            }
            return this;
        }

        /// <summary>
        /// Adds the given sequence step to the path
        /// </summary>
        public RDFPropertyPath AddSequenceStep(RDFPropertyPathStep sequenceStep)
        {
            if (sequenceStep != null)
            {
                #region Steps Update
                this.Depth++;
                this.Steps.Add(sequenceStep.SetOrdinal(this.Steps.Count)
                                           .SetFlavor(RDFQueryEnums.RDFPropertyPathStepFlavors.Sequence));
                #endregion

                #region Evaluability Guard
                if (this.Start is RDFVariable || this.End is RDFVariable || this.Depth > 1)
                {
                    this.IsEvaluable = true;
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddSequenceStep: non-ground property path detected, evaluability granted or confirmed.");
                }   
                else
                { 
                    RDFQueryEvents.RaiseGENERICQueryEvaluation("AddSequenceStep: ground property path detected, evaluability not granted.");
                }
                #endregion
            }
            return this;
        }

        /// <summary>
        /// Gets the list of patterns corresponding to the path
        /// </summary>
        internal List<RDFPattern> GetPatternList()
        {
            List<RDFPattern> patterns = new List<RDFPattern>();

            #region Single Property
            if (this.Steps.Count == 1)
            {

                //InversePath (swap start/end)
                if (this.Steps[0].IsInverseStep)
                {
                    patterns.Add(new RDFPattern(this.End, this.Steps[0].StepProperty, this.Start));
                }

                //Path
                else
                {
                    patterns.Add(new RDFPattern(this.Start, this.Steps[0].StepProperty, this.End));
                }

            }
            #endregion

            #region Multiple Properties
{'fraction_non_alphanumeric': 0.08181637651419872, 'fraction_numerical': 0.0033097239690209838, 'mean_word_length': 1.3878615457562826, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5703', 'n_tokens_mistral': 3736, 'n_tokens_neox': 3519, 'n_words': 988}