private static string GetValueAtLabelBase(FluentQuery response, Direction direction, string[] textTypeOfValue, string[] labelInDocument)
        {
            response.QueryType = QueryType.SingleCapture;
            response.AppendToScript($"Text({string.Join("||", labelInDocument)}) {direction} [{Or(textTypeOfValue)}]");

            return(ExecuteSingleCapture(response));
        }
        private static string[] GetAnyBase(FluentQuery response, string[] textType)
        {
            response.QueryType = QueryType.Any;
            response.AppendToScript($"Any [{Or(textType)}]");

            return(response.ExecuteQuery().Select(x => x.Value).ToArray());
        }
        private static string FindValueForLabelBase(FluentQuery response, string[] textTypeOfValue, int maxSteps, string[] labelInDocument)
        {
            response.QueryType = QueryType.SingleCapture;
            response.AppendToScript($"Text({string.Join("||", labelInDocument)}) RD {maxSteps} [{Or(textTypeOfValue)}]");

            return(ExecuteSingleCapture(response));
        }
        private static string CaptureBase(FluentQuery response, string[] captureTextType)
        {
            if (response.QueryType == QueryType.None)
            {
                response.QueryType = QueryType.SingleCapture;
            }

            return(ExecuteSingleCapture(response.AppendToScript($"[{Or(captureTextType)}]")));
        }
        private static FluentQuery CaptureNamedBase(FluentQuery response, string[] captureTextType, string propertyName)
        {
            response.QueryType = QueryType.MultiCapture;

            if (string.IsNullOrWhiteSpace(propertyName))
            {
                throw new FluentQueryException("The specified pattern has multiple captures, a property name must be specified when capturing more than one value.");
            }

            return(response.AppendToScript((!string.IsNullOrWhiteSpace(propertyName) ? $"'{propertyName}': " : string.Empty) + $"[{Or(captureTextType)}]"));
        }
        private static Dictionary <string, string> ExecuteQuery(this FluentQuery fluentQuery)
        {
            if (fluentQuery.QueryType == QueryType.None)
            {
                throw new FluentQueryException("Query includes no capture tokens. Nothing to query for.");
            }

            fluentQuery.AppendToScript(";");

            var interpretationResultJson = fluentQuery
                                           .Interpreter
                                           .Interpret(fluentQuery.AnalyzedPage, fluentQuery.Script)
                                           .ConvertToJson(fluentQuery.Script);

            if (string.IsNullOrWhiteSpace(interpretationResultJson))
            {
                return(null);
            }

            var json = JObject.Parse(interpretationResultJson)[FluentQueryConstants.GeneratedScriptQuery];
            Dictionary <string, string> deserializedResult = null;

            switch (fluentQuery.QueryType)
            {
            case QueryType.SingleCapture:
                deserializedResult = JsonConvert.DeserializeObject <Dictionary <string, string> >(interpretationResultJson);
                break;

            case QueryType.MultiCapture:
                deserializedResult = JsonConvert.DeserializeObject <Dictionary <string, string> >(json.ToString());
                break;

            case QueryType.Any:
                deserializedResult = JsonConvert.DeserializeObject <string[]>(json.ToString())
                                     .Select((x, i) => new KeyValuePair <int, string>(i, x))
                                     .ToDictionary(x => x.Key.ToString(), x => x.Value);
                break;

            default: throw new FluentQueryException("Query type is invalid");
            }

            if (deserializedResult == null || deserializedResult.Count == 0)
            {
                return(null);
            }

            return(deserializedResult);
        }
 /// <summary>
 /// Following a pattern predicate or a capture, specify to move *Right* from there to look for the next element in the document for the next operation.
 /// </summary>
 /// <returns>A DocumentLab FluentQuery with a script extension that performs the traversal.</returns>
 public static FluentQuery Right(this FluentQuery response) => response.AppendToScript("Right");
 /// <summary>
 /// Following a pattern predicate or a capture, specify to move *Left* from there to look for the next element in the document for the next operation.
 /// </summary>
 /// <returns>A DocumentLab FluentQuery with a script extension that performs the traversal.</returns>
 public static FluentQuery Left(this FluentQuery response) => response.AppendToScript("Left");
 /// <summary>
 /// Following a pattern predicate or a capture, specify to move *Down* from there to look for the next element in the document for the next operation.
 /// </summary>
 /// <returns>A DocumentLab FluentQuery with a script extension that performs the traversal.</returns>
 public static FluentQuery Down(this FluentQuery response) => response.AppendToScript("Down");
 /// <summary>
 /// Following a pattern predicate or a capture, specify to move *Up* from there to look for the next element in the document for the next operation.
 /// </summary>
 /// <returns>A DocumentLab FluentQuery with a script extension that performs the traversal.</returns>
 public static FluentQuery Up(this FluentQuery response) => response.AppendToScript("Up");
 /// <summary>
 /// Specifies a tablecolumn for the preceding table query initializer
 /// </summary>
 /// <param name="columnName">The name to assign for the column in the result output</param>
 /// <param name="columnTextType">The text type considered valid in the table row's data for this column</param>
 /// <param name="labels">Labels that can be evaluated to identify the table on the page</param>
 /// <returns>A DocumentLab FluentQuery with a script extension that contains the table column definition</returns>
 public static FluentQuery TableColumn(this FluentQuery response, string columnName, string columnTextType, params string[] labels)
 => response.AppendToScript($"'{columnName}': [{columnTextType}({string.Join("||", labels)})]");
 private static FluentQuery MatchBase(FluentQuery response, string[] textType, string[] matchText)
 {
     return(response.AppendToScript(matchText.Count() > 0 ? $"{Or(textType.Select(x => $"{x}({string.Join("||", matchText)})").ToArray())}" : Or(textType)));
 }
 private static FluentQuery SubsetBase(FluentQuery response, Subset[] subset)
 {
     return(response.AppendToScript($"Subset({string.Join(", ", subset.ToString())})"));
 }
 /// <summary>
 /// Initiates a table query, a series of TableColumn method calls needs to follow this one.
 /// </summary>
 /// <returns>A DocumentLab FluentQuery with a script extension that initates the table query</returns>
 public static FluentQuery Table(this FluentQuery response) => response.AppendToScript("Table");
 /// <summary>
 /// Performs a Right-Down search from the previous predcate. A predicate or capture should follow. This is implicitly already used in the FindValueForLabel and GetValueForLabel methods. Use this method if you want to create more detailed patterns using RD.
 /// </summary>
 /// <param name="maxSteps">The maximum distance in cells between the previous predicate and the next predicate for the pattern to be valid.</param>
 /// <returns></returns>
 public static FluentQuery RightDownSearch(this FluentQuery response, int maxSteps) => response.AppendToScript($"RD {maxSteps}");