/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package plate.wellmann.shop.business;

import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import org.apache.log4j.Logger;
import plate.wellmann.shop.persistence.Customer;

/**
 *
 * @author Patrick
 */
@Named
@RequestScoped
public class PasswordManager implements Serializable {

    final static Logger logger = Logger.getLogger(PasswordManager.class);

    @PersistenceContext(name = "MySQL-Wellmann")
    private EntityManager em;

    //private Password password;
    private Customer costumer;
    
    private final int keyLength = 256;

    public byte[] hashPassword(final char[] password, final byte[] salt, final int iterations) {

//        if(costumer == Customer.nullCustomer || costumer == null){
//            logger.error("Tried to create hash for Nullcostumer!");
//            return null;
//        }
        try {
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
            PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, this.keyLength);
            SecretKey key = skf.generateSecret(spec);
            //this.password = new Password(this.costumer, key.getEncoded());
            logger.debug("Hash created!");
            return key.getEncoded();
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            logger.error("Failure creating hash for with:" + e);
            return null;
            //throw new RuntimeException( e );
        }
    }
    
    public byte[] hashPasswordCostumer(final char[] password, Customer cost) {

        if(costumer == Customer.nullCustomer || costumer == null){
            logger.error("Tried to create hash for Nullcostumer!");
            return null;
        }
        try {
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
            PBEKeySpec spec = new PBEKeySpec(password, cost.getSalt().getSalt(), cost.getSalt().getInterations(), keyLength);
            SecretKey key = skf.generateSecret(spec);
            logger.debug("Hash created!");
            return key.getEncoded();
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            logger.error("Failure creating hash for" + cost.getEmail() + "with: " + e);
            return null;
        }
    }

    /*
    @Transactional
    public boolean passwordCheckEmail(final String email, final byte[] password) {
        TypedQuery<Customer> query = em.createNamedQuery("Costumer.findByEmail", Customer.class);
        query.setParameter("email", email);
        try {
            Customer cost;
            cost = query.getSingleResult();

            boolean equals = Arrays.equals(password, cost.getPassword().getPassword());

            for (int i = 0; i < password.length; i++) {
                password[i] = 0;
            }

            return equals;
        } catch (NoResultException e) {
            return false;
        }
    }

    public boolean passwordCheckCostumer(final Customer cost, final String password) {
        byte[] pw = hashPasswordCostumer(password.toCharArray(), cost);
        
        boolean equals = Arrays.equals(pw, cost.getPassword().getPassword());
        
        for (int i = 0; i < pw.length; i++) {
            pw[i] = 0;
        }
        
        return equals;

    }

    @Transactional
    public boolean changePassword(Customer cost, String newPassword, String oldPassword) {
        if (cost == Customer.nullCustomer || cost == null) {
            logger.error("Nullcostumer tried to change Password");
            return false;
        }
        
        if(passwordCheckCostumer(cost, oldPassword)){
            cost.getPassword().setPassowrd(hashPasswordCostumer(newPassword.toCharArray(), cost));
            logger.info("Password changed for " + cost.getEmail());
        } else {
            return false;
        }
        
        try {
            em.persist(cost);
            logger.info("Password changed for " + cost.getEmail());
            return true;
        } catch (Exception e) {
            logger.error("Couldn't save new password to " + cost.getEmail() + " with: " + e.toString());
            return false;
        }
    }*/

    public byte[] generateRandomPassword() {
        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[20];
        random.nextBytes(bytes);
        return bytes;
    }

    public Customer getCostumer() {
        return costumer;
    }

    public void setCostumer(Customer costumer) {
        this.costumer = costumer;
    }
}
