package org.machizaud;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.sql.*;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

import static java.lang.System.out;

/**
 * User: Andréa
 * Date: 12/01/11
 * Time: 10:37
 */
public class Exam {
    private static final Logger logger = Logger.getLogger(Exam.class.getCanonicalName());

    /**
     * Données BDD Oracle
     */
    private static String url = "jdbc:oracle:thin:@localhost:1521:XE";
    private static String driver = "oracle.jdbc.driver.OracleDriver";
    private static String login = "Andréa";
    private static String pass = "qU651IfS";

    private static Connection conn = null;
    private static boolean isDriverRegistered = false;

    public static Connection getConnection() {
        try {
            if (!isDriverRegistered) {
                Driver oracleDriver = (Driver) Class.forName(driver).newInstance();
                DriverManager.registerDriver(oracleDriver);
                isDriverRegistered = true;
            }
            if (conn == null) {
                conn = DriverManager.getConnection(url, login, pass);
            }
        } catch (SQLException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (ClassNotFoundException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InstantiationException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return conn;
    }

    /**
     * Données XML
     */
    private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
    private static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";

    private static int testFileCounter = 0;
    private static final Scanner inputScanner = new Scanner(System.in);

    /**
     * Construit un sejour sous format xml, pour finir la saisie des prestations appuyer sur <Entrée> lors de la saisie d'une novuelle prestation
     *
     * @return le nom du fichier correspondant au fichier crée
     */
    public static String buildSejour() {
        try {
            Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

            Element sejour = dom.createElement("sejour");
            dom.appendChild(sejour);

            out.print("Saisir l'id du séjour : ");
            sejour.setAttribute("id", inputScanner.nextLine());

            Element client = dom.createElement("client");
            sejour.appendChild(client);

            out.print("Saisir l'id du client : ");
            client.setAttribute("id", inputScanner.nextLine());

            out.print("Saisir le nom du client : ");
            client.setAttribute("nom", inputScanner.nextLine());

            out.print("Saisir le prenom du client : ");
            client.setAttribute("prenom", inputScanner.nextLine());

            out.print("Saisir la date de naissance du client : ");
            client.setAttribute("dateNaissance", inputScanner.nextLine());

            out.print("Saisir l'adresse du client : ");
            client.setAttribute("adresse", inputScanner.nextLine());

            Element lieu = dom.createElement("lieu");
            sejour.appendChild(lieu);

            out.print("Saisir l'id du lieu : ");
            lieu.setAttribute("id", inputScanner.nextLine());

            out.print("Saisir le nom du lieu : ");
            lieu.setAttribute("libelle", inputScanner.nextLine());

            out.print("Saisir l'adresse du lieu : ");
            lieu.setAttribute("adresse", inputScanner.nextLine());

            Element quand = dom.createElement("quand");
            sejour.appendChild(quand);

            out.print("Saisir la date du départ : ");
            quand.setAttribute("depart", inputScanner.nextLine());

            out.print("Saisir la durée du séjour : ");
            quand.setAttribute("nombreJours", inputScanner.nextLine());

            String readed = "";
            Element tarification = dom.createElement("tarification");
            sejour.appendChild(tarification);
            tarification.setAttribute("total", "0");
            do {
                out.print("Choisissez une prestation à ajouter : ");

                readed = inputScanner.nextLine();

                if (readed.equals(""))
                    break;

                Element prestation = dom.createElement("prestation");
                tarification.appendChild(prestation);
                prestation.setAttribute("libelle", readed);

                out.print("Choisissez le prix pour cette prestation : ");
                readed = inputScanner.nextLine();
                prestation.setAttribute("tarif", readed);

                tarification.setAttribute("total",
                        String.valueOf(
                                Integer.parseInt(tarification.getAttribute("total"))
                                        + Integer.parseInt(readed)));
            } while (true);

            return saveXML(dom, String.format("sejour%d.xml", testFileCounter++));

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static boolean validXML(String xmlPath, String xsdPath) {

        try {
            DocumentBuilderFactory domBuilderFactory = DocumentBuilderFactory.newInstance();
            domBuilderFactory.setIgnoringComments(true);
            domBuilderFactory.setNamespaceAware(true);
            domBuilderFactory.setValidating(true);
            domBuilderFactory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
            domBuilderFactory.setAttribute(JAXP_SCHEMA_SOURCE, new File(xsdPath));

            DocumentBuilder domBuilder = domBuilderFactory.newDocumentBuilder();
            domBuilder.setErrorHandler(new FatalErrorHandler());

            domBuilder.parse(new File(xmlPath));

            return true;
        } catch (SAXParseException ex) {
            logger.log(Level.SEVERE, "Document is not valid against given schema : \n\t" + ex.getMessage());
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    private static String saveXML(Document dom, String filename) {
        try {
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

            BufferedWriter bw = new BufferedWriter(
                    new FileWriter(filename));
            //initialize StreamResult with File object to save to file
            StreamResult result = new StreamResult(bw);
            DOMSource source = new DOMSource(dom);
            transformer.transform(source, result);

            bw.close();

            return filename;
        } catch (TransformerException ex) {
            logger.log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }

        return null;
    }

    public static void insertSejourData(String xmlfile) {
        try {
            BufferedReader bw = new BufferedReader(
                    new FileReader(xmlfile));
            StringBuilder sb = new StringBuilder();

            String line =null;
            while((line = bw.readLine()) != null)
                    sb.append(line+"\n");

            String query = "INSERT INTO sejour (description)VALUES('" + sb.toString() + "')";
            PreparedStatement insertStatement = getConnection().prepareStatement(query);

            ResultSet set = insertStatement.executeQuery();

            System.out.println("Set fetch size : " + set.getFetchSize());

        } catch (SQLException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String filename = "sejour0.xml";
        String xsdPath = "xml/sejour.xsd";
        out.println("Fichier xml valide ? " + validXML(filename, xsdPath));
        insertSejourData(filename);
    }

    /**
     * Error handler when trying to validate XML against an XSD
     */
    private static class FatalErrorHandler implements ErrorHandler {
        @Override
        public void warning(SAXParseException exception) throws SAXException {
            throw new SAXException("Warning encountered : " + exception.getLocalizedMessage(), exception);
        }

        @Override
        public void error(SAXParseException exception) throws SAXException {
            throw new SAXException("Error encountered : " + exception.getLocalizedMessage(), exception);
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
            throw new SAXException("Fatal Error encountered : " + exception.getLocalizedMessage(), exception);
        }
    }
}
