//
// https://www.ramecera.it/myscrewdriver.html
// e-mail: screwdriver@ramecera.it
//
/* This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html */
package it.ramecera.screwdriver.component;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import it.ramecera.salad.analysis.Flute;
import it.ramecera.salad.analysis.JavaAnnotation;
import it.ramecera.salad.analysis.JavaProperty;
import it.ramecera.salad.everyday.Candies;
import it.ramecera.salad.everyday.ExactException;
import it.ramecera.salad.everyday.Mix;
import it.ramecera.salad.everyday.Strings;
import it.ramecera.salad.file.Equipment;
import it.ramecera.screwdriver.CandyScrew;
import it.ramecera.screwdriver.Cst;
import it.ramecera.screwdriver.Markup;
import it.ramecera.screwdriver.Skill;
import it.ramecera.screwdriver.Train;
import it.ramecera.screwdriver.outfits.JspKit;
import it.ramecera.screwdriver.outfits.MenuKit;
import it.ramecera.screwdriver.outfits.TableOutfit;

/**
 * <p>
 * Application to automatically generate files that make up an
 * application.
 * </p>
 * 
 * @author M. Maglioni
 *         <p>
 *         ​​Company: Ramecera™<br>
 *         Creation date: 2020-04-09<br>
 *         Last updated: 2020-09-09<br>
 *         </p>
 *         <p>
 *         History:<br>
 *         The description of N# is in project plan report.<br>
 *         2020-09-03 implementation of N3<br>
 *         2020-09-09 implementation of N8<br>
 *         </p>
 */
public abstract class FileComponent {

	// PROTECTED

	/** the main features of the application */
	protected Skill skill;
	/** the properties of the job */
	protected CandyScrew candies;
	/** directory with recycle bin function */
	protected String recycleBinY;

	protected final static String SERVER_HOME = "${jboss.server.home.url}";

	// PUBLIC

	/** the content of the file to be built */
	public String producedMaterial = "";
	/** the snippet to be copied, path and file name */
	public String snippetG;
	/** Jsp kit of JSP features */
	public JspKit jspKit = new JspKit();
	/** Jsp kit of JSP features */
	public MenuKit menuKit = new MenuKit();

	/** name of the Quartz configuration file */
	public static final String QUARTZ_JOB_XML_F = "quartz-job.xml";

	// PRIVATE
	//
	// private static final String sep = System.getProperty(
	// "file.separator");
	// /** ordinary logger */
	// private static final Logger logger = Logger.getLogger(
	// FileComponent.class);

	/**
	 * <p>
	 * Class for producing the component file.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param markupE the list of markups
	 * @param trainE the train list
	 * @param candyScrew list of application properties
	 * @throws IOException ordinary exception
	 * @throws FileNotFoundException ordinary exception
	 * @throws ExactException ordinary exception
	 * @throws ExactException standard exception */
	public abstract void synthesis(HashMap<String, Markup> markupE,
			List<Train> trainE, CandyScrew candyScrew)

			throws FileNotFoundException, IOException, ExactException,
			ExactException;

	/** @param markupE the list of markups
	 * @throws ExactException exception specified by a numeric code */
	abstract public void directory(HashMap<String, Markup> markupE)

			throws ExactException;

	/**
	 * <p>
	 * Class for writing the component file.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param y output directory
	 * @param nomeFileOutput output file
	 * @param filenameInput input file name
	 * @param type the extension of the output file; only java,
	 *        properties, xml and jsp are allowed
	 * @param candies the set of properties external to the application
	 * @param recycleBinY recycle bin directory
	 * @throws ExactException specified by a numeric code
	 * @throws IOException ordinary exception
	 * @throws FileNotFoundException ordinary exception */
	public void write(final String y, final String nomeFileOutput,
			final String filenameInput, final String type,
			CandyScrew candies, final String recycleBinY)

			throws ExactException, FileNotFoundException, IOException {
		skill.toTarget(y, nomeFileOutput, producedMaterial,
				filenameInput, recycleBinY, type);
	}

	/**
	 * <p>
	 * Class for deleting the component file. Return false if the file
	 * does not exist or cannot be moved.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param y directory of the file to be deleted
	 * @param f file from delete
	 * @param trash directory where you put the deleted files
	 * @param skill TODO
	 * @return if the operation was successful */
	public static boolean deleteComponent(final String y,
			final String f, File trash, Skill skill) {
		File x = new File(Mix.dress_C(y) + f);
		if (!x.exists()) {
			return false;
		}
		skill.buildDirectory(trash);
		File destinazione = new File(trash.getPath() + "/" + f);
		destinazione.delete();
		return x.renameTo(destinazione);
	}

	/**
	 * <p>
	 * Overload of the previous method.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param y directory of the file to be deleted
	 * @param f file from delete
	 * @param trash directory where you put the deleted files
	 * @param skill TODO
	 * @return if the operation was successful */
	public static boolean deleteComponent(final String y,
			final String f, final String trash, Skill skill) {
		return deleteComponent(y, f, new File(trash), skill);
	}

	/** @param filenameInput class name
	 * @param outputPath path to go to write
	 * @param outputFile name of the output file
	 * @param candies application main constants
	 * @param trashY the directory with trash function
	 * @param skill set of application descriptive data
	 * @param tableJ index in the list of DB tables
	 * @param markupE map of markups
	 * @param tipoFileInput type of input file, as classified inside the
	 *        box
	 * @throws ExactException standard exception
	 * @throws IOException standard exception
	 * @throws FileNotFoundException standard exception */
	public static void addClass(final String filenameInput,
			final String outputPath, final String outputFile,
			CandyScrew candies, final String trashY, Skill skill,
			final int tableJ, HashMap<String, Markup> markupE,
			final String tipoFileInput)

			throws ExactException, FileNotFoundException, IOException {

		String dir = candies.snippetsYS + tipoFileInput;
		String material = Equipment.oneStringUnicode_A(dir + "/"
				+ filenameInput, "UTF-8");
		material = Strings.replaceFirst(material, "package +zoccolo+",
				"package " + skill.pckg);
		material = material.replaceAll("\\x2bApplicaz\\x2b", Mix
				.uppercaseFirstChar(skill.applicationNameLower));
		material = material.replaceAll("import \\x2bzoccolo\\x2b",
				"import " + skill.pckg);
		material = material.replaceAll("\\x2bnocciolo\\x2b",
				outputFile);
		if (tableJ > -1) {
			material = material.replaceAll("\\x2btabella\\x2b",
					skill.tableDBE.get(tableJ).entityName);
			material = material.replaceAll("\\x2bdbschema\\x2b",
					skill.tableDBE.get(tableJ).railLowercase);
			material = Strings.replaceFirst(material, "+jpapath+",
					skill.tableDBE.get(tableJ).pathDots);
		}
		material = material.replaceAll("\\x2bRail\\x2b", Cst.RAILU
				+ skill.tabUser[1]);
		material = material.replaceAll("\\x2brail\\x2b", Cst.RAIL
				+ skill.tabUser[1]);
		material = material.replaceAll("\\x2btabuser\\x2b", Mix
				.uppercaseFirstChar(skill.tabUser[0]));
		if (!markupE.get("xencoder").recurrenceE.isEmpty() && markupE
				.get("xencoder").recurrenceE.get(0).locomotor.text
						.equalsIgnoreCase("useridmd5")) {
			String t = "";
			t += "public String getCredentials() {" + Candies.LF;
			t += Candies.TABS + Candies.TABS
					+ "String s = super.getPrincipal()" + Candies.LF;
			t += Candies.TABS + Candies.TABS
					+ "+ (String) super.getCredentials();" + Candies.LF;
			t += Candies.TABS + Candies.TABS + "MessageDigest m = null;"
					+ Candies.LF;
			t += Candies.TABS + Candies.TABS + "try {" + Candies.LF;
			t += Candies.TABS + Candies.TABS + Candies.TABS
					+ "m = MessageDigest.getInstance(\"MD5\");"
					+ Candies.LF;
			t += Candies.TABS + Candies.TABS
					+ "} catch (NoSuchAlgorithmException e) {"
					+ Candies.LF;
			t += Candies.TABS + Candies.TABS + "}" + Candies.LF;
			t += Candies.TABS + Candies.TABS
					+ "m.update(s.getBytes(), 0, s.length());"
					+ Candies.LF;
			t += Candies.TABS + Candies.TABS
					+ "return new BigInteger(1, m.digest()).toString(16);"
					+ Candies.LF;
			t += Candies.TABS + "}";
			material = Strings.replaceFirst(material, "+newMethod+", t);
		} else {
			material = Strings.replaceFirst(material, "+newMethod+",
					"");
		}
		skill.toTarget(outputPath, outputFile, material, filenameInput,
				trashY, "java");
	}

	/** @param inputFileName obvious
	 * @param outputFileName obvious
	 * @param outputPath path of the output file
	 * @param candies external properties
	 * @param recycleBinY directory-trashcan, i.e. where to put the
	 *        files to be deleted
	 * @param skill set of application descriptive data
	 * @throws ExactException a standard exception
	 * @throws IOException standard exception
	 * @throws FileNotFoundException standard exception */
	public static void addFile(final String inputFileName,
			String outputFileName, final String outputPath,
			CandyScrew candies, final String recycleBinY, Skill skill)

			throws ExactException, FileNotFoundException, IOException {

		String dir = candies.snippetsYS;
		String extension = Mix.estraiExtension(inputFileName);
		String tipo = "xml";
		if (extension != null && extension.equals("xml")) {
			dir += "xml/";
		} else if (extension != null && extension.equals("css")) {
			dir += "css/";
		} else if (inputFileName.endsWith("_jsp.txt")) {
			dir += "jsp/";
			tipo = "jsp";
		} else if (inputFileName.endsWith(".properties")) {
			dir += "properties/";
		}
		if (extension != null && extension.equals("java")) {
			tipo = extension;
		} else if (extension != null && extension.equals(
				"properties")) {
			tipo = extension;
		} else if (extension != null && extension.equals("jsp")) {
			tipo = extension;
		}
		String material = Equipment.oneString(dir + inputFileName);
		material = Strings.replaceFirst(material, "+Applicaz+", Mix
				.uppercaseFirstChar(skill.applicationNameLower));
		if (skill.authenticationErrorMenu == null) {
			material = Strings.replaceFirst(material, "+navigation+",
					"");
		} else {
			material = Strings.replaceFirst(material, "+navigation+",
					"<jsp:include page=\"../includes/navigation_"
							+ skill.authenticationErrorMenu
							+ ".jsp\" />");
		}
		material = material.replaceAll("\\x2bapplicaz\\x2b",
				skill.applicationNameLower);
		skill.toTarget(outputPath, outputFileName, material,
				inputFileName, recycleBinY, tipo);
	}

	/** identifies the type of the key; it doesn't have to be a
	 * primitive type */

	protected String[] locateKey(TableOutfit ct)

			throws ExactException, FileNotFoundException, IOException {

		Flute flute = ct.flute;
		int i = 0;
		int j = 0;
		String tipo = null;
		String nome = null;
		String[] b = new String[3];
		for (; i < flute.fpropertyE.size(); i++) {
			JavaProperty p = flute.fpropertyE.get(i);
			j = 0;
			for (; j < p.fannotationE.size(); j++) {
				JavaAnnotation a = p.fannotationE.get(j);
				if (a.fnome.equals("EmbeddedId") | a.fnome.equals(
						"Id")) {
					if (p.fprimitivo != null) {
						ExactException ce = new ExactException(
								"In the «" + ct.entityName + ".java»"
										+ " the key «" + p.fnome
										+ "» is declared by the primitive type «"
										+ p.fprimitivo
										+ "», it is not allowed.", 1101,
								this.getClass().getName(), "");
						throw ce;
					}
					tipo = p.fclasse;
					nome = p.fnome;
					break;
				}
			}
			if (j < p.fannotationE.size()) {
				break;
			}
		}
		if (i == flute.fpropertyE.size()) {
			// b [0] = "";
			// b [1] = "";
			// b [2] = "";
			// return b;
			ExactException ce = new ExactException("In the file "
					+ ct.entityName + ".java"
					+ "there are no Id annotation or Embedded Id.",
					1102, this.getClass().getName(), "");
			throw ce;
		}
		/* the 3 elements are: 1) property annotation; 2) property
		 * class; 3) name of the property */
		b[0] = flute.fpropertyE.get(i).fannotationE.get(j).fnome;
		b[1] = tipo;
		b[2] = nome;
		return b;
	}

	/**
	 * <p>
	 * Identifies the type of the key; must not be a primitive type
	 * </p>
	 * 
	 * @param ct table main elements
	 * @param nomeColonna column name
	 * @return whether the DB table column is present or not */

	public static boolean checkColumn(TableOutfit ct,
			String nomeColonna) {

		Flute flute = ct.flute;
		int i = 0;
		for (; i < flute.fpropertyE.size(); i++) {
			JavaProperty p = flute.fpropertyE.get(i);
			if (p.fnome.equalsIgnoreCase(nomeColonna)) {
				break;
			}
		}
		return i < flute.fpropertyE.size();
	}
}