/*

SPDX-FileCopyrightText: Copyright 2021 Siemens
SPDX-License: GPL-3.0-only
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.


 */

package javareporter;

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.jd.core.v1.api.printer.Printer;

import javareporter.ApiStorage.ApiEntry;

public class NXOpenPrinter implements Printer {
	protected static final String TAB = "  ";
	protected static final String NEWLINE = "\n";
	protected static ApiStorage apiStorage = new ApiStorage();

	public static void Reset()
	{

		apiStorage.Reset();
	}

	protected int indentationCount = 0;
	protected static StringBuilder sb = new StringBuilder();
	protected String CurrentJarFile = "";
	protected String CurrentClassFile = "";

	public void SetCurrentClassorJarFile(String file, boolean isJar)
	{
		if (isJar)
		{
			CurrentJarFile = file;
		}
		else
		{
			CurrentClassFile = file;
		}
	}


	@Override public String toString() 
	{
		return sb.toString(); 
	}


	public String printAsJson()
	{
		StringBuilder js = new StringBuilder();


		js.append("[\n");

		js.append("  {\n");
		js.append("    \"MetaData\": {\n");
		
		
		if (Utils.GetIsRunningUnittest())
		{
			js.append("        \"JavaBomReporterVersion\": \"\",\n");
			js.append("        \"BuildVersion\": \"\",\n");
			js.append("        \"DateCreated\": \"\"\n"); 
		}
		else
		{
			js.append("        \"JavaBomReporterVersion\": \"" + Utils.GetToolVersion() + "\",\n");
			js.append("        \"BuildVersion\": \"" + Utils.GetBuildVersion() + "\",\n");
			js.append("        \"DateCreated\": \"" + ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + "\"\n"); 
		}

		js.append("    }\n");
		js.append("  },\n");

		Map<String, Map<String, Map<String, List<ApiEntry>>>> dataMap = apiStorage.GetMap();

		js.append("  {\n");

		int VersionMapCount = 0;

		for (Entry<String, Map<String, Map<String, List<ApiEntry>>>> versionEntry : dataMap.entrySet()) {

			
			if (VersionMapCount != 0)
			{
				js.append(",\n");
			}
			
			js.append("    \"" + versionEntry.getKey() +"\"" + ": {\n" );
			int fullMapCount = 0;
			for (Map.Entry<String,  Map<String, List<ApiEntry>>> entry : versionEntry.getValue().entrySet()) {

				if (fullMapCount != 0)
				{
					js.append(",\n");
				}

				js.append("      \"" + entry.getKey() +"\"" + ": {\n" );

				int apiMapCount = 0;
				for (Map.Entry<String, List<ApiEntry>> entry2 : entry.getValue().entrySet())
				{
					if (apiMapCount != 0)
					{
						js.append(",\n");
					}
					js.append("        \"" + entry2.getKey() + "\"" + ": [\n" );
					int apiEntryCount = 0;
					for (ApiEntry value : entry2.getValue())
					{

						if (apiEntryCount != 0)
						{
							js.append(",\n");
						}

						js.append("          {\n");
						js.append("            \"ContainingClass\":\"" + value.getClassFile()+ "\",\n");
						js.append("            \"NXOpenUsage\":\"" + value.getUsage()+ "\",\n");
						js.append("            \"ApiName\":\"" + value.getApiName()+ "\"\n");

						js.append("          }");

						if (apiEntryCount == entry2.getValue().size() - 1)
						{
							js.append("\n");
						}

						apiEntryCount ++;

					}
					js.append("        ]");
					if (apiMapCount == entry.getValue().entrySet().size() - 1)
					{
						js.append("\n");
					}
					apiMapCount++;
				}

				js.append("      }");
				if (fullMapCount == versionEntry.getValue().entrySet().size() - 1)
				{
					js.append("\n");
				}


				fullMapCount++;
			}
			
			js.append("    }");
			if (VersionMapCount == dataMap.entrySet().size() - 1)
			{
				js.append("\n");
			}


			VersionMapCount++;
			
		}
		js.append("  }\n");
		js.append("]\n");
		return js.toString();
	}

	@Override public void start(int maxLineNumber, int majorVersion, int minorVersion) {}
	@Override public void end() {}

	@Override public void printText(String text) { 
		apiStorage.AppendToCurrentLine(text, false);
		sb.append(text); 
	}
	@Override public void printNumericConstant(String constant) { 
		apiStorage.AppendToCurrentLine(constant, false);
		sb.append(constant);
	}
	@Override public void printStringConstant(String constant, String ownerInternalName) {
		apiStorage.AppendToCurrentLine(constant, false);
		sb.append(constant);
	}
	@Override public void printKeyword(String keyword) {
		apiStorage.AppendToCurrentLine(keyword, false);
		sb.append(keyword); 
	}
	@Override public void printDeclaration(int type, String internalTypeName, String name, String descriptor)
	{
		apiStorage.AppendToCurrentLine(name, false);
		sb.append(name);
	}
	@Override public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName)
	{ 
		String fullyQualifiedName = internalTypeName.replace('/', '.').replace("$", ".");

		if (type != 1)
		{
			fullyQualifiedName += "." + name;
		}
		if (fullyQualifiedName.contains("nxopen"))
		{
			apiStorage.AddToMap(type, fullyQualifiedName, CurrentJarFile + "|" + CurrentClassFile, ownerInternalName,  descriptor);
		}
		apiStorage.AppendToCurrentLine(name, false);
		sb.append(name);
	}

	@Override public void indent() { this.indentationCount++; }
	@Override public void unindent() { this.indentationCount--; }

	@Override public void startLine(int lineNumber) { for (int i=0; i<indentationCount; i++) sb.append("    "); }
	@Override public void endLine() {
		apiStorage.AppendToCurrentLine("", true);
		sb.append(NEWLINE);
	}
	@Override public void extraLine(int count) { while (count-- > 0) sb.append(NEWLINE); }

	@Override public void startMarker(int type) {}
	@Override public void endMarker(int type) {}
}
