/*
 * Project: e-Dec Example Code
 * (C) 2017 Bundesamt fuer Informatik und Telekommunikation, CH
 */
package ch.admin.bit.edec.examples.fileHandling;

import ch.admin.bit.edec.examples.EdecRequestResponse;
import ch.admin.bit.edec.examples.EdecRequestType;
import ch.admin.bit.edec.examples.PropertyProvider;
import ch.admin.bit.edec.examples.ws.HttpsRequest;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

/*
 * Helper class for all the file operations.
 */
public class FileHandler {
  private static final Log log = LogFactory.getLog(HttpsRequest.class);

  /**
   * This text will be replaced by the request content.
   */
  public static final String SOAP_REPLACEMENT_STRING = "###PLACEHOLDER###";

  /**
   * Loads a text file from the supplied path.
   *
   * @param fileName Full quallified name to load the file from.
   * @return Loaded text.
   * @throws FileHandlerException Thrown if the file couldn't be loaded.
   */
  public static String loadTextFile(String fileName) throws FileHandlerException {
    BufferedReader br = null;
    FileReader fr = null;
    StringBuilder file = new StringBuilder();

    try {
      fr = new FileReader(fileName);
      br = new BufferedReader(fr);
      String sCurrentLine;

      while ((sCurrentLine = br.readLine()) != null) {
        file.append(sCurrentLine);
      }
    }
    catch (IOException e) {
      throw new FileHandlerException("Couldn't load file", e);
    }
    finally {
      try {
        if (br != null)
          br.close();
        if (fr != null)
          fr.close();
      }
      catch (IOException ex) {
        throw new FileHandlerException("Couldn't load file", ex);
      }
    }
    return file.toString();
  }

  /**
   * Loads a text resource from the classpath.
   *
   * @param fileName File to read.
   * @return Loaded text.
   * @throws FileHandlerException Thrown if file couldn't be loaded.
   */
  public static String loadTextResource(String fileName) throws FileHandlerException {
    //String path0 = FileHandler.class.getResource(fileName).getPath();
    String path = Thread.currentThread().getContextClassLoader().getResource(fileName).getPath();
    return loadTextFile(path);
  }

  /**
   * Loads a XML file from the supplied path. Then, it tries to determine the type of request and fills the EdecRequestResponse object.
   *
   * @param fileName Full qualified file name to load.
   * @return Fully initialized EdecRequestResponse object.
   * @throws FileHandlerException Thrown if the file couldn't be loaded or if the XML is of unknown type.
   */
  public static EdecRequestResponse loadXmlFile(String fileName) throws FileHandlerException {
    String xml = loadTextFile(fileName);
    String soapEnvelope = loadTextResource(PropertyProvider.getProperty(PropertyProvider.PROP_SOAP_ENVELOPE_FILE));
    String fullRequest = soapEnvelope.replace(SOAP_REPLACEMENT_STRING, xml);

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = null;
    Document doc = null;
    EdecRequestType type = null;

    try {
      builder = factory.newDocumentBuilder();
      InputSource is = new InputSource(new StringReader(xml));
      doc = builder.parse(is);

      if (null != doc && null != doc.getLastChild()) {
        String ndType = doc.getLastChild().getNodeName();
        if (ndType.contains(EdecRequestType.TYPE_EDEC.getName())) {
          type = EdecRequestType.TYPE_EDEC;
        }
        else if (ndType.contains(EdecRequestType.TYPE_BORDEREAU.getName())) {
          type = EdecRequestType.TYPE_BORDEREAU;
        }
        else if (ndType.contains(EdecRequestType.TYPE_RECEIPT.getName())) {
          type = EdecRequestType.TYPE_RECEIPT;
        }
        else {
          type = null;
        }
      }
    }
    catch (ParserConfigurationException e) {
      throw new FileHandlerException("Couldn't load file", e);
    }
    catch (SAXException e) {
      throw new FileHandlerException("Couldn't load file", e);
    }
    catch (IOException e) {
      throw new FileHandlerException("Couldn't load file", e);
    }

    EdecRequestResponse request = new EdecRequestResponse(fullRequest, type);
    return request;
  }

  /**
   * Saves a file to the supplied path.
   *
   * @param fileName Full qualified file name.
   * @param content  Text to save.
   * @throws FileHandlerException Thrown if file couldn't be saved.
   */
  public static void saveXmlFile(String fileName, String content) throws FileHandlerException {
    try {
      FileUtils.writeStringToFile(new File(fileName), content, "utf-8");
    }
    catch (IOException e) {
      log.error("Couldn't write file! ", e);
      throw new FileHandlerException("Couldn't write file! ", e);
    }
  }

  public static  KeyStore loadStore(InputStream storeStream, String storePassword) {
    char[] password = storePassword.toCharArray();
    KeyStore store = null;
    try {
      store = KeyStore.getInstance(KeyStore.getDefaultType());

      // load the stream to your store
      store.load(storeStream, password);
    }
    catch (CertificateException e) {
      log.error(e.getMessage());
    }
    catch (NoSuchAlgorithmException e) {
      log.error(e.getMessage());
    }
    catch (KeyStoreException e) {
      log.error(e.getMessage());
    }
    catch (IOException e) {
      log.error(e.getMessage());
    }

    return store;
  }
}
