package com.njcn.advance.utils;

import cn.hutool.core.util.StrUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Random;

import static java.math.BigDecimal.ROUND_HALF_UP;

public class NumberUtil {
    private static final int DEFAULT_SCALE = 10;
    private static final RoundingMode DEFAULT_ROUNDINGMODE = RoundingMode.HALF_UP;

    private static Random rand = new Random();

    public static boolean isNumber(String str) {
        return isDouble(str);
    }

    public static boolean isInt(String str) {
        if (StrUtil.isEmpty(str))
            return false;
        try
        {
            Integer.parseInt(str);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    public static boolean isInteger(String str) {
        return isInt(str);
    }

    public static boolean isLong(String str) {
        if (StrUtil.isEmpty(str))
            return false;
        try
        {
            Long.parseLong(str);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    public static boolean isFloat(String str) {
        if (StrUtil.isEmpty(str))
            return false;
        try
        {
            Float.parseFloat(str);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    public static boolean isDouble(String str) {
        if (StrUtil.isEmpty(str))
            return false;
        try
        {
            Double.parseDouble(str);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    public static double round(double v, int scale) {
        BigDecimal b = new BigDecimal(Double.toString(v));
        return b.setScale(scale, ROUND_HALF_UP).doubleValue();
    }

    public static int getRandomInt(int max) {
        return rand.nextInt(max);
    }

    public static int toInt(byte[] bs) {
        return toInt(bs, 0);
    }

    public static int toInt(byte[] bs, int start) {
        int i = 0;
        i += ((bs[start] & 0xFF) << 24);
        i += ((bs[(start + 1)] & 0xFF) << 16);
        i += ((bs[(start + 2)] & 0xFF) << 8);
        i += (bs[(start + 3)] & 0xFF);
        return i;
    }

    public static byte[] toBytes(int i) {
        byte[] bs = new byte[4];
        bs[0] = ((byte)(i >> 24));
        bs[1] = ((byte)(i >> 16));
        bs[2] = ((byte)(i >> 8));
        bs[3] = ((byte)(i & 0xFF));
        return bs;
    }

    public static void toBytes(int i, byte[] bs, int start) {
        bs[start] = ((byte)(i >> 24));
        bs[(start + 1)] = ((byte)(i >> 16));
        bs[(start + 2)] = ((byte)(i >> 8));
        bs[(start + 3)] = ((byte)(i & 0xFF));
    }

    public static short toShort(byte[] bs) {
        return toShort(bs, 0);
    }

    public static short toShort(byte[] bs, int start) {
        short i = 0;
        i = (short)(i + ((bs[(start + 0)] & 0xFF) << 8));
        i = (short)(i + (bs[(start + 1)] & 0xFF));
        return i;
    }

    public static byte[] toBytes(short i) {
        byte[] bs = new byte[2];
        bs[0] = ((byte)(i >> 8));
        bs[1] = ((byte)(i & 0xFF));
        return bs;
    }

    public static void toBytes(short i, byte[] bs, int start) {
        bs[(start + 0)] = ((byte)(i >> 8));
        bs[(start + 1)] = ((byte)(i & 0xFF));
    }

    public static byte[] toBytes(long i) {
        byte[] bs = new byte[8];
        bs[0] = ((byte)(int)(i >> 56));
        bs[1] = ((byte)(int)(i >> 48));
        bs[2] = ((byte)(int)(i >> 40));
        bs[3] = ((byte)(int)(i >> 32));
        bs[4] = ((byte)(int)(i >> 24));
        bs[5] = ((byte)(int)(i >> 16));
        bs[6] = ((byte)(int)(i >> 8));
        bs[7] = ((byte)(int)(i & 0xFF));
        return bs;
    }

    public static void toBytes(long l, byte[] bs, int start) {
        byte[] arr = toBytes(l);
        for (int i = 0; i < 8; i++)
            bs[(start + i)] = arr[i];
    }

    public static long toLong(byte[] bs) {
        return toLong(bs, 0);
    }

    public static long toLong(byte[] bs, int index) {
        return (bs[index] & 0xFF) << 56 | (bs[(index + 1)] & 0xFF) << 48 | (bs[(index + 2)] & 0xFF) << 40 |
                (bs[(index + 3)] & 0xFF) << 32 | (bs[(index + 4)] & 0xFF) << 24 | (bs[(index + 5)] & 0xFF) << 16 |
                (bs[(index + 6)] & 0xFF) << 8 | (bs[(index + 7)] & 0xFF) << 0;
    }

    public static String format(Number n, String format) {
        DecimalFormat df = new DecimalFormat(format);
        return df.format(n);
    }
    public static Double formatNumber(Number n, String format) {
        return Double.valueOf(format(n,format));
    }
    public static Double formatNumber(Number n) {
        String format = "0.00";
        return Double.valueOf(format(n,format));
    }

    public static ArrayList<Integer> getBinaryList(int num) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        String binStr = Integer.toBinaryString(num);
        for (int i = 0; i < binStr.length(); i++) {
            if (binStr.charAt(i) == '1') {
                int intpow = (int)Math.pow(2.0D, binStr.length() - i - 1);
                list.add(Integer.valueOf(intpow));
            }
        }
        return list;
    }


    public static BigDecimal getBigDecimal(Object number) {
        if (number == null) {
            return null;
        }
        if ((number instanceof BigDecimal))
            return (BigDecimal)number;
        if (((number instanceof Double)) || ((number instanceof Float)))
            return new BigDecimal(number.toString());
        if ((number instanceof Integer))
            return new BigDecimal(((Integer)number).intValue());
        if ((number instanceof Long)) {
            return new BigDecimal(((Long)number).longValue());
        }
        return new BigDecimal(number.toString());
    }

    public static Number div(Number a, Number b) {
        return getBigDecimal(a).divide(getBigDecimal(b), DEFAULT_SCALE, DEFAULT_ROUNDINGMODE);
    }

    public static Number div(Number a, Number b, int scale) {
        return getBigDecimal(a).divide(getBigDecimal(b), scale, DEFAULT_ROUNDINGMODE);
    }

    public static Number sum(Number a, Number b) {
        return getBigDecimal(a).add(getBigDecimal(b));
    }

    public static Number sub(Number a, Number b) {
        return getBigDecimal(a).subtract(getBigDecimal(b));
    }

    public static Number mul(Number a, Number b) {
        return getBigDecimal(a).multiply(getBigDecimal(b));
    }

    public static boolean equal(Number a, Number b) {
        if (((a instanceof Float)) || ((b instanceof Float)) || ((a instanceof Double)) || ((b instanceof Double))) {
            return Math.abs(a.floatValue() - b.floatValue()) < 1.0E-006D;
        }
        return a.equals(b);
    }

    /**
     * 判断key在数组arr中是否存在
     * @param arr 数组
     * @param key 待查找值
     * @return key在数组arr中是否存在，true：存在，false：不存在
     */
    public static boolean exist(Long[] arr, long key) {
        for(int i=0; i<arr.length; i++) {
            if(equal(arr[i], key)) {
                return true;
            }
        }
        return false;
    }
}