/*
 * Copyright
 *   2007 axYus - www.axyus.com
 *   2008 L.Meckert - laurent.meckert.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package fr.gouv.finances.cp.xemelios.plugin.signerfichier;

import java.io.File;
import java.util.Vector;
import javax.xml.namespace.NamespaceContext;

/**
 *
 * @author laurent.meckert
 */
public abstract class FileSigner implements IFileSigner {

    protected File inputFile;
    protected File outputFile;
    protected File keystoreFile;
    protected String keystorePassword;
    protected String alias;
    protected String aliasPassword;
    protected String keystoreType;
    protected String algorithm;
    protected NamespaceContext nsCtx;
    protected Vector<String> subtractFilters = new Vector<String>();
    protected Vector<String> intersectFilters = new Vector<String>();

    public void setNsCtx(NamespaceContext ctx) {
        nsCtx = ctx;
    }
    /**
     * Codes de gravite pour examen  rapide du resultat
     * tout va bien
     */
    public static final int SIGN_GOOD = 0;
    /**
     * Codes de gravite pour examen  rapide du resultat
     * warning
     */
    public static final int SIGN_BAD = 1;
    /**
     * Codes de gravite pour examen  rapide du resultat
     * erreur grave
     */
    public static final int SIGN_VERYBAD = 2;
    /**
     * statut/résultat globzl de la vérification
     */
    protected int status = 0;
    /**
     * Le fichier xml a ete correctement parse
     */
    public static final int PARSEOK = 1;
    /**
     * Le fichier des cles a ete correctement charge
     */
    public static final int LOADKSOK = 2;
    /**
     * La cle privee est bien charge
     */
    public static final int LOADPKOK = 4;
    /**
     * L'algorithme de signature est supporte
     */
    public static final int ALGOIDOK = 8;
    /**
     * La signature s'est bien passe
     */
    public static final int SIGNOK = 16;
    /**
     * Le fichier signé a bien été produit
     */
    public static final int WRITEOK = 32;
    // Methodes de confort pour detailler le statut

    /**
     *
     * @return true si le fichier XML a ete correctement parsé
     */
    public boolean parseOK() {
        return (status & PARSEOK) != 0 ? true : false;
    }

    /**
     *
     * @return true si le keystore est bien charge
     */
    public boolean loadKsOK() {
        return (status & LOADKSOK) != 0 ? true : false;
    }

    /**
     *
     * @return true si la cle privee est bien charge
     */
    public boolean loadPkOK() {
        return (status & LOADPKOK) != 0 ? true : false;
    }

    /**
     *
     * @return true si l'algorithme de signature est supporte
     */
    public boolean algoIdOK() {
        return (status & ALGOIDOK) != 0 ? true : false;
    }

    /**
     *
     * @return true si signature ok
     */
    public boolean signOK() {
        return (status & SIGNOK) != 0 ? true : false;
    }

    /**
     *
     * @return true si fichier de sortie nbien ecrit
     */
    public boolean writeOK() {
        return (status & WRITEOK) != 0 ? true : false;
    }
    // Methodes de confort pour positionner le statut
    // accessibles que aux classes derivees

    protected void setParseOK(boolean b) {
        if (b) {
            status = status | PARSEOK;
        } else {
            status = status & ~PARSEOK;
        }
    }

    protected void setLoadKsOK(boolean b) {
        if (b) {
            status = status | LOADKSOK;
        } else {
            status = status & ~LOADKSOK;
        }
    }

    protected void setLoadPkOK(boolean b) {
        if (b) {
            status = status | LOADPKOK;
        } else {
            status = status & ~LOADPKOK;
        }
    }

    protected void setAlgoIdOK(boolean b) {
        if (b) {
            status = status | ALGOIDOK;
        } else {
            status = status & ~ALGOIDOK;
        }
    }

    protected void setSignOK(boolean b) {
        if (b) {
            status = status | SIGNOK;
        } else {
            status = status & ~SIGNOK;
        }
    }

    protected void setWriteOK(boolean b) {
        if (b) {
            status = status | WRITEOK;
        } else {
            status = status & ~WRITEOK;
        }
    }

    public File getInputFile() {
        return inputFile;
    }

    public void setInputFile(File inputFile) {
        this.inputFile = inputFile;
    }

    public File getOutputFile() {
        return outputFile;
    }

    public void setOutputFile(File outputFile) {
        this.outputFile = outputFile;
    }

    public File getKeystoreFile() {
        return keystoreFile;
    }

    public void setKeystoreFile(File keystoreFile) {
        this.keystoreFile = keystoreFile;
    }

    public String getKeystorePassword() {
        return keystorePassword;
    }

    public void setKeystorePassword(String keystorePassword) {
        this.keystorePassword = keystorePassword;
    }

    public String getDetails(String rawalias) {
        return rawalias;
    }

    public String getIssuedFor(String rawalias) {
        return rawalias;
    }

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }

    public String getAliasPassword() {
        return aliasPassword;
    }

    public void setAliasPassword(String aliasPassword) {
        this.aliasPassword = aliasPassword;
    }

    /**
     *
     * @param algorithm
     */
    protected void setAlgorithm(String algorithm) {
        this.algorithm = algorithm;
    }

    /**
     *
     *
     * @return algorithm
     */
    protected String getAlgorithm() {
        return algorithm;
    }

    protected static String kstypeFromSuffix(String suffix) {

        if (suffix == null) {
            return "PKCS12";
        }

        if (suffix.equalsIgnoreCase("jks") || suffix.equalsIgnoreCase("ks")) {
            return "JKS";
        }
        if (suffix.equalsIgnoreCase("jce")) {
            return "JCEKS";
        }
        if (suffix.equalsIgnoreCase("p12") || suffix.equalsIgnoreCase("pfx")) {
            return "PKCS12";
        }
        return "PKCS12";
    }

    /**
     *
     * @return
     */
    public String getKeystoreType() {

        if (keystoreFile != null) {
            int n = keystoreFile.getName().lastIndexOf('.');
            String extension = keystoreFile.getName().substring(n + 1);
            keystoreType = kstypeFromSuffix(extension);
        }

        return keystoreType;
    }

    public void addSubtractFilter(String xpath) {
        subtractFilters.add(xpath);
    }

    public void addIntersectFilter(String xpath) {
        intersectFilters.add(xpath);
    }

    /**
     * donne l'etat sous forme lisible (pour compte rendu)
     *@return une chaine de caracteres prete a l'affichage
     */
    public String getStatusAsString() {
        StringBuffer sb = new StringBuffer();
        if (!parseOK()) {
            sb.append("Le fichier n'est pas un fichier XML correct \n");
        } else if (loadKsOK()) {
            //    sb.append("Le magasin de clés " + getKeystoreFile().getName() + " est correctement chargé\n");
            sb.append("Le magasin de clés est correctement chargé\n");
            if (loadPkOK()) {
                sb.append("La cle d'alias " + getAlias() + " est correctement chargée\n");
                if (algoIdOK()) {
                    sb.append("Algorithme de signature reconnu : " + getAlgorithm() + "\n");
                } else {
                    sb.append("Algorithme de signature INCONNU ou non supporté : " + getAlgorithm() + "\n");
                }
            } else {
                sb.append("La cle d'alias " + getAlias() + " N'A PAS PU ETRE CHARGEE\n");
            }




            if (signOK()) {
                sb.append("La signatures a réussi!\n");
                if (writeOK()) {
                    sb.append("L'écriture du fichier de sortie " + getOutputFile().getName() + " a réussi!\n");
                } else {
                    sb.append("L'écriture du fichier de sortie " + getOutputFile().getName() + " a ECHOUE\n");
                }
            } else {
                sb.append("La  signature a ECHOUE\n ");
            }
        } else {
            sb.append("Impossible de charger magasin de cles " + getKeystoreFile().getName() + " \n");
        }


        return sb.toString();
    }

    /**
     * donne l'etat condense (pour compte rendu)
     *@return int une des 3 valeurs VFY_GOOD  VFY_BAD  VFY_VERYBAD
     */
    public int getStatusAsSeverity() {
        //    int res = SIGN_BAD;
        if (!parseOK()) {
            return SIGN_VERYBAD;
        } // meme pas du xml correct ..

        if (loadKsOK()) {
            if (!signOK()) {
                return SIGN_VERYBAD;  // pas pu signer
            } else {
                if (!writeOK()) {
                    return SIGN_VERYBAD;  // pas pu creer le fichier de sortie
                } else {
                    return SIGN_GOOD;
                }
            }
        } else {
            return SIGN_BAD;   // pas pu charger les cles
        }


    }

    public void dispose() {
    }
}
