/*
 * $Id$
 * @author aakimov
 * @date   Jun 30, 2016 8:11:21 PM
 *
 * Copyright (C) 2016 Scytl Secure Electronic Voting SA
 *
 * All rights reserved.
 */
package com.scytl.math;

import java.math.BigInteger;
import java.util.List;

import com.scytl.math.jni.JNI;

/**
 * Implementation of {@link MultiExponentiatorFactory}.
 * 
 * @author aakimov
 */
public final class MultiExponentiatorFactoryImpl
        implements MultiExponentiatorFactory {
    private static final MultiExponentiatorFactoryImpl INSTANCE = new MultiExponentiatorFactoryImpl();

    private MultiExponentiatorFactoryImpl() {
    }

    /**
     * Returns the instance.
     * 
     * @return the instance
     */
    public static MultiExponentiatorFactoryImpl getInstance() {
        return INSTANCE;
    }

    @Override
    public MultiExponentiator newMultiExponentiator(List<BigInteger> bases,
            BigInteger modulus, int maximumBitLengthOfExponent) {
        MultiExponentiator exponentiator;
        int baseCount = bases.size();
        if (JNI.isAvailable()) {
            exponentiator = new NativeMultiExponentiator(bases, modulus,
                    maximumBitLengthOfExponent);
        } else if ((maximumBitLengthOfExponent <= 60 && baseCount < 4)
                || (60 < maximumBitLengthOfExponent
                        && maximumBitLengthOfExponent <= 256 && baseCount < 5)
                || (256 < maximumBitLengthOfExponent && baseCount < 6)) {
            exponentiator = new SlidingWindowMultiExponentiator(bases, modulus,
                    maximumBitLengthOfExponent);
        } else if ((maximumBitLengthOfExponent <= 60 && baseCount < 72)
                || (60 < maximumBitLengthOfExponent
                        && maximumBitLengthOfExponent <= 160 && baseCount < 186)
                || (160 < maximumBitLengthOfExponent
                        && maximumBitLengthOfExponent <= 256 && baseCount < 252)
                || (256 < maximumBitLengthOfExponent
                        && maximumBitLengthOfExponent <= 512 && baseCount < 420)
                || (512 < maximumBitLengthOfExponent
                        && maximumBitLengthOfExponent <= 768 && baseCount < 456)
                || (768 < maximumBitLengthOfExponent && baseCount < 608)) {
            exponentiator = new LimLeeMultiExponentiator(bases, modulus,
                    maximumBitLengthOfExponent);
        } else {
            exponentiator = new BrickellMultiExponentiator(bases, modulus,
                    maximumBitLengthOfExponent);
        }
        return exponentiator;
    }
}
