/*******************************************************************************
 * Copyright (c) 2020 Bart Jacobs and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 */
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import org.eclipse.jdt.internal.compiler.parser.Parser;

public class GenerateParserScript {

	private static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }

	public static void main(String[] args) throws IOException, InterruptedException {
		File grammarDir = new File("../grammar");
		File parserDir = new File("../src/org/eclipse/jdt/internal/compiler/parser");
		String jikespg = System.getProperty("JIKESPG");
		assertTrue(jikespg != null);

		if (!jikespg.equals("JIKESPG_EXTERNAL")) {
			// Run JikesPG
			Process process = Runtime.getRuntime().exec(new String[] {jikespg, "java.g"}, null, grammarDir);
			boolean ok = false;
			try (BufferedReader jikespgOutput = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
				for (;;) {
					String line = jikespgOutput.readLine();
					if (line == null)
						break;
					System.out.println(line);
					if (line.equals("This grammar is LALR(1)."))
						ok = true;
				}
			}
			int exitCode = process.waitFor();
			assertTrue(exitCode == 0);
			if (!ok)
				System.exit(1);
		}

		// Update parserNN.rsc and readableNames.props
		File javadclFile = new File(grammarDir, "javadcl.java");
		File javahdrFile = new File(grammarDir, "javahdr.java");
		Parser.buildFilesFromLPG(javadclFile.toString(), javahdrFile.toString());
		for (int i = 1; i <= 24; i++) {
			String filename = "parser"+i+".rsc";
			Files.move(new File(filename).toPath(), new File(parserDir, filename).toPath(), StandardCopyOption.REPLACE_EXISTING);
		}
		{
			String filename = "readableNames.props";
			Files.move(new File(filename).toPath(), new File(parserDir, filename).toPath(), StandardCopyOption.REPLACE_EXISTING);
		}

		// Update TerminalTokens.java
		File javasymFile = new File(grammarDir, "javasym.java");
		File terminalTokensFile = new File(parserDir, "TerminalTokens.java");
		String javasymText = new String(Files.readAllBytes(javasymFile.toPath())).replace("\r\n",  "\n");
		String terminalTokensText = new String(Files.readAllBytes(terminalTokensFile.toPath()));
		{
			String startTag = "// BEGIN_AUTOGENERATED_REGION\n";
			int start = terminalTokensText.indexOf(startTag);
			assertTrue(start >= 0);
			start += startTag.length();
			String terminalTokensProlog = terminalTokensText.substring(0, start);

			String javasymProlog =
					"interface javasym\n" + 
					"{\n" + 
					"    public final static int\n" +
					"      ";
			assertTrue(javasymText.startsWith(javasymProlog));
			javasymText = javasymText.substring(javasymProlog.length());
			javasymText = javasymText.replace(",\n      ", ",\n\t\t\t\t\t\t\t");
			javasymText = javasymText.replace("TokenName$eof", "TokenNameEOF");
			javasymText = javasymText.replace("TokenName$error", "TokenNameERROR");
			javasymText = javasymText.replace("TokenNamenon-sealed", "TokenNamenon_sealed");
			Files.write(terminalTokensFile.toPath(), (terminalTokensProlog + "\tint " + javasymText).getBytes());
		}

		// Update ParserBasicInformation.java
		File javadefFile = new File(grammarDir, "javadef.java");
		File parserBasicInformationFile = new File(parserDir, "ParserBasicInformation.java");
		String javadefText = new String(Files.readAllBytes(javadefFile.toPath())).replace("\r\n", "\n");
		String parserBasicInformationText = new String(Files.readAllBytes(parserBasicInformationFile.toPath()));
		{
			String startTag = "// BEGIN_AUTOGENERATED_REGION";
			int start = parserBasicInformationText.indexOf(startTag);
			assertTrue(start >= 0);
			start += startTag.length();
			String parserBasicInformationProlog = parserBasicInformationText.substring(0, start);

			String javadefProlog =
					"interface javadef\n" + 
					"{\n" + 
					"    public final static int";
			assertTrue(javadefText.startsWith(javadefProlog));
			javadefText = javadefText.substring(javadefProlog.length());
			javadefText = javadefText.replace("\n      ", "\n\t\t\t\t\t");
			javadefText = javadefText.replaceAll(" +", " ");
			javadefText = javadefText.replace("};\n\n", "}\n");

			Files.write(parserBasicInformationFile.toPath(), (parserBasicInformationProlog + javadefText).getBytes());
		}

		// Update method consumeRule in Parser.java
		File parserFile = new File(parserDir, "Parser.java");
		String parserText = new String(Files.readAllBytes(parserFile.toPath()));
		File javaActionFile = new File(grammarDir, "JavaAction.java");
		String javaActionText = new String(Files.readAllBytes(javaActionFile.toPath()))
									.replace("\r\n",  "\n").replace(" \n", "\n").replace(" \n", "\n");
		{
			String startTag = "// BEGIN_AUTOGENERATED_REGION_CONSUME_RULE\n";
			String endTag = "// END_AUTOGENERATED_REGION_CONSUME_RULE\n";
			int start = parserText.indexOf(startTag);
			assertTrue(start >= 0);
			start += startTag.length();
			int end = parserText.indexOf(endTag, start);
			assertTrue(end >= 0);

			String newParserText = parserText.substring(0, start) + javaActionText + parserText.substring(end);

			Files.write(parserFile.toPath(), newParserText.getBytes());
		}

		// Clean up JikesPG output files
		Files.delete(javadclFile.toPath());
		Files.delete(javahdrFile.toPath());
		Files.delete(javaActionFile.toPath());
		Files.delete(javasymFile.toPath());
		Files.delete(javadefFile.toPath());
		Files.delete(new File(grammarDir, "javaprs.java").toPath());
		Files.delete(new File(grammarDir, "java.l").toPath());
	}

}
