package graphql.parser;

import graphql.Assert;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Contains parsing code for the StringValue types in the grammar
 */
class StringValueParsing {
    private final static String ESCAPED_TRIPLE_QUOTES = "\\\\\"\"\""; // ahh Java + Regex
    private final static String THREE_QUOTES = "\"\"\"";

    static String parseTripleQuotedString(String strText) {
        int end = strText.length() - 3;
        String s = strText.substring(3, end);
        s = s.replaceAll(ESCAPED_TRIPLE_QUOTES, THREE_QUOTES);
        return removeIndentation(s);
    }

    /*
       See https://github.com/facebook/graphql/pull/327/files#diff-fe406b08746616e2f5f00909488cce66R758
     */
    static String removeIndentation(String rawValue) {
        String[] lines = rawValue.split("\\n");
        int minIndent = Integer.MAX_VALUE;
        for (int i = 0; i < lines.length; i++) {
            if (i == 0) continue;
            String line = lines[i];
            int length = line.length();
            int indent = leadingWhitespace(line);
            if (indent < length && indent < minIndent) {
                minIndent = indent;
            }
        }
        List<String> lineList = new ArrayList<>(Arrays.asList(lines));
        if (minIndent != Integer.MAX_VALUE) {
            for (int i = 0; i < lineList.size(); i++) {
                String line = lineList.get(i);
                if (i == 0) continue;
                if (line.length() > minIndent) {
                    line = line.substring(minIndent);
                    lineList.set(i, line);
                }
            }
        }
        while (!lineList.isEmpty()) {
            String line = lineList.get(0);
            if (line.isEmpty()) {
                lineList.remove(0);
            } else {
                break;
            }
        }
        while (!lineList.isEmpty()) {
            int endIndex = lineList.size() - 1;
            String line = lineList.get(endIndex);
            if (line.isEmpty()) {
                lineList.remove(endIndex);
            } else {
                break;
            }
        }
        StringBuilder formatted = new StringBuilder();
        for (int i = 0; i < lineList.size(); i++) {
            String line = lineList.get(i);
            if (i == 0) {
                formatted.append(line);
            } else {
                formatted.append("\n");
                formatted.append(line);
            }
        }
        return formatted.toString();
    }

    private static int leadingWhitespace(String line) {
        int count = 0;
        for (int i = 1; i < line.length(); i++) {
            char ch = line.charAt(i);
            if (ch != ' ' && ch != '\t') {
                break;
            }
            count++;
        }
        return count;
    }

    static String parseSingleQuotedString(String string) {
        StringWriter writer = new StringWriter(string.length() - 2);
        int end = string.length() - 1;
        for (int i = 1; i < end; i++) {
            char c = string.charAt(i);
            if (c != '\\') {
                writer.write(c);
                continue;
            }
            char escaped = string.charAt(i + 1);
            i += 1;
            switch (escaped) {
                case '"':
                    writer.write('"');
                    continue;
                case '/':
                    writer.write('/');
                    continue;
                case '\\':
                    writer.write('\\');
                    continue;
                case 'b':
                    writer.write('\b');
                    continue;
                case 'f':
                    writer.write('\f');
                    continue;
                case 'n':
                    writer.write('\n');
                    continue;
                case 'r':
                    writer.write('\r');
                    continue;
                case 't':
                    writer.write('\t');
                    continue;
                case 'u':
                    String hexStr = string.substring(i + 1, i + 5);
                    int codepoint = Integer.parseInt(hexStr, 16);
                    i += 4;
                    writer.write(codepoint);
                    continue;
                default:
                    Assert.assertShouldNeverHappen();
            }
        }
        return writer.toString();
    }
}

@@ -40,16 +40,41 @@
 .Assert;
+%0Aimport graphql.Internal;
 %0A%0Aimport
@@ -247,16 +247,33 @@
 mar%0A */%0A
+@Internal%0Apublic 
 class St
@@ -291,16 +291,16 @@
 rsing %7B%0A
-
     priv
@@ -439,24 +439,31 @@
 %5C%22%5C%22%22;%0A%0A    
+public 
 static Strin
@@ -818,20 +818,27 @@
      */%0A
-
     
+public 
 static S
@@ -2939,16 +2939,23 @@
  %7D%0A%0A    
+public 
 static S

make StringValueParsing public, but marked as Internal