/* BdfServer - Copyright (c) 2011-2021 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.impl;

import fr.exemole.bdfserver.api.managers.PasswordManager;
import fr.exemole.bdfserver.api.storage.PasswordStorage;
import java.util.Arrays;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import net.fichotheque.Fichotheque;
import net.fichotheque.sphere.Redacteur;
import net.fichotheque.utils.SphereUtils;
import net.mapeadores.util.security.PasswordChecker;


/**
 *
 * @author Vincent Calame
 */
class PasswordManagerImpl implements PasswordManager {

    private final Fichotheque fichotheque;
    private final PasswordStorage passwordStorage;

    PasswordManagerImpl(Fichotheque fichotheque, PasswordStorage passwordStorage) {
        this.fichotheque = fichotheque;
        this.passwordStorage = passwordStorage;
        check();
    }

    private void check() {
        String[] passwordArray = passwordStorage.getPasswordArray();
        SortedMap<String, String> passwordMap = toSortedMap(passwordArray);
        int length = passwordArray.length;
        for (int i = 0; i < length; i = i + 2) {
            String checkedKey = testKey(passwordArray[i]);
            if (checkedKey != null) {
                passwordMap.put(checkedKey, passwordArray[i + 1]);
            }
        }
        String[] newArray = toPasswordArray(passwordMap);
        if (!Arrays.equals(passwordArray, newArray)) {
            passwordStorage.savePasswordArray(newArray);
        }
    }

    @Override
    public boolean checkPassword(String passwordKey, String passwordValue) {
        String[] passwordArray = passwordStorage.getPasswordArray();
        int length = passwordArray.length;
        for (int i = 0; i < length; i = i + 2) {
            if (passwordArray[i].equals(passwordKey)) {
                return PasswordChecker.check(passwordValue, passwordArray[i + 1]);
            }
        }
        return false;
    }

    @Override
    public synchronized void setPassword(String passwordKey, String passwordValue) {
        SortedMap<String, String> map = toSortedMap(passwordStorage.getPasswordArray());
        if ((passwordValue == null) || (passwordValue.length() == 0)) {
            map.remove(passwordKey);
        } else {
            map.put(passwordKey, PasswordChecker.getHash(PasswordChecker.PBKDF2, passwordValue));
        }
        passwordStorage.savePasswordArray(toPasswordArray(map));
    }

    @Override
    public String getEncryptedPassword(String passwordKey) {
        String[] passwordArray = passwordStorage.getPasswordArray();
        int length = passwordArray.length;
        for (int i = 0; i < length; i = i + 2) {
            if (passwordArray[i].equals(passwordKey)) {
                return passwordArray[i + 1];
            }
        }
        return null;
    }

    @Override
    public synchronized void setEncryptedPassword(String passwordKey, String encryptedPasswordValue) {
        SortedMap<String, String> map = toSortedMap(passwordStorage.getPasswordArray());
        if ((encryptedPasswordValue == null) || (encryptedPasswordValue.length() == 0)) {
            map.remove(passwordKey);
        } else {
            map.put(passwordKey, encryptedPasswordValue);
        }
        passwordStorage.savePasswordArray(toPasswordArray(map));
    }

    @Override
    public String[] toPasswordArray() {
        return passwordStorage.getPasswordArray();
    }

    private String testKey(String key) {
        if (key.equals("confirm")) {
            return null;
        }
        try {
            Redacteur redacteur = SphereUtils.parse(fichotheque, key);
            return redacteur.getGlobalId();
        } catch (SphereUtils.RedacteurLoginException rle) {
            if (rle.getType() == SphereUtils.MALFORMED_KEY) {
                return key;
            } else {
                return null;
            }
        }
    }

    private static String[] toPasswordArray(Map<String, String> passwordMap) {
        int size = passwordMap.size();
        String[] array = new String[size * 2];
        int p = 0;
        for (Map.Entry<String, String> entry : passwordMap.entrySet()) {
            array[2 * p] = entry.getKey();
            array[2 * p + 1] = entry.getValue();
            p++;
        }
        return array;
    }

    private static SortedMap<String, String> toSortedMap(String[] passwordArray) {
        SortedMap<String, String> map = new TreeMap<String, String>();
        int length = passwordArray.length;
        for (int i = 0; i < length; i = i + 2) {
            map.put(passwordArray[i], passwordArray[i + 1]);
        }
        return map;
    }

}
