/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var sqrt = require( './../../../../base/special/sqrt' );
var floor = require( './../../../../base/special/floor' );
var FLOAT64_MAX_SAFE_INTEGER = require( '@stdlib/constants/float64/max-safe-integer' );
var WHEEL_PRIMES = require( './wheel_primes.json' );


// MAIN //

/**
* Returns a boolean indicating whether a number is a prime.
*
* @param {number} x - value to test
* @returns {boolean} boolean indicating whether a value is a prime number
*
* @example
* var bool = isPrime( 5.0 );
* // returns true
*
* @example
* var bool = isPrime( 4.0 );
* // returns false
*/
function isPrime( x ) {
	var N;
	var i;

	// Check whether the number is an integer...
	if ( floor( x ) !== x ) {
		return false;
	}
	// Check whether the number is positive...
	if ( x <= 3 ) {
		return (x > 1); // primes: 2, 3
	}
	// Check whether the number is even...
	if ( x > FLOAT64_MAX_SAFE_INTEGER || x%2 === 0 ) {
		return false;
	}
	// Check for small primes...
	if ( x < 9 ) {
		return true; // primes: 5, 7
	}
	// Check whether the number is evenly divisible by `3`...
	if ( x%3 === 0 ) {
		return false;
	}
	// Check whether the number is evenly divisible by `5`...
	if ( x%5 === 0 ) {
		return false;
	}
	// Check whether the number is evenly divisible by `7`...
	if ( x%7 === 0 ) {
		return false;
	}
	// Check whether the number is a prime number in the wheel...
	if ( WHEEL_PRIMES[ x ] ) {
		return true;
	}
	// Use trial division (with wheel factorization; see https://en.wikipedia.org/wiki/Wheel_factorization) to detect composite numbers, leveraging the fact that all primes greater than `210` are of the form `210k±1`...
	N = floor( sqrt( x ) );
	for ( i = 11; i <= N; i += 210 ) {
		if (
			x%i === 0 ||       // 11
			x%(i+2) === 0 ||   // 13
			x%(i+6) === 0 ||   // 17
			x%(i+8) === 0 ||   // 19
			x%(i+12) === 0 ||  // 23
			x%(i+18) === 0 ||  // 29
			x%(i+20) === 0 ||  // 31
			x%(i+26) === 0 ||  // 37
			x%(i+30) === 0 ||  // 41
			x%(i+32) === 0 ||  // 43
			x%(i+36) === 0 ||  // 47
			x%(i+42) === 0 ||  // 53
			x%(i+48) === 0 ||  // 59
			x%(i+50) === 0 ||  // 61
			x%(i+56) === 0 ||  // 67
			x%(i+60) === 0 ||  // 71
			x%(i+62) === 0 ||  // 73
			x%(i+68) === 0 ||  // 79
			x%(i+72) === 0 ||  // 83
			x%(i+78) === 0 ||  // 89
			x%(i+86) === 0 ||  // 97
			x%(i+90) === 0 ||  // 101
			x%(i+92) === 0 ||  // 103
			x%(i+96) === 0 ||  // 107
			x%(i+98) === 0 ||  // 109
			x%(i+102) === 0 || // 113
			x%(i+110) === 0 || // 121 (relatively prime)
			x%(i+116) === 0 || // 127
			x%(i+120) === 0 || // 131
			x%(i+126) === 0 || // 137
			x%(i+128) === 0 || // 139
			x%(i+132) === 0 || // 143 (relatively prime)
			x%(i+138) === 0 || // 149
			x%(i+140) === 0 || // 151
			x%(i+146) === 0 || // 157
			x%(i+152) === 0 || // 163
			x%(i+156) === 0 || // 167
			x%(i+158) === 0 || // 169 (relatively prime)
			x%(i+162) === 0 || // 173
			x%(i+168) === 0 || // 179
			x%(i+170) === 0 || // 181
			x%(i+176) === 0 || // 187 (relatively prime)
			x%(i+180) === 0 || // 191
			x%(i+182) === 0 || // 193
			x%(i+186) === 0 || // 197
			x%(i+188) === 0 || // 199
			x%(i+198) === 0 || // 209 (relatively prime)
			x%(i+200) === 0    // 211
		) {
			return false;
		}
	}
	return true;
}


// EXPORTS //

module.exports = isPrime;
