package cn.iocoder.yudao.framework.common.thealgorithms.conversions;

import java.util.Arrays;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.Scanner;

///**
// * Class for converting from "any" base to "any" other base, when "any" means
// * from 2-36. Works by going from base 1 to decimal to base 2. Includes
// * auxiliary method for determining whether a number is valid for a given base.
// *
// * @author Michael Rolland
// * @version 2017.10.10
// */
//public final class AnyBaseToAnyBase {
//    private AnyBaseToAnyBase() {
//    }
//
//    /**
//     * Smallest and largest base you want to accept as valid input
//     */
//    static final int MINIMUM_BASE = 2;
//
//    static final int MAXIMUM_BASE = 36;
//
//    public static void main(String[] args) {
//        Scanner in = new Scanner(System.in);
//        String n;
//        int b1;
//        int b2;
//        while (true) {
//            try {
//                System.out.print("Enter number: ");
//                n = in.next();
//                System.out.print("Enter beginning base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
//                b1 = in.nextInt();
//                if (b1 > MAXIMUM_BASE || b1 < MINIMUM_BASE) {
//                    System.out.println("Invalid base!");
//                    continue;
//                }
//                if (!validForBase(n, b1)) {
//                    System.out.println("The number is invalid for this base!");
//                    continue;
//                }
//                System.out.print("Enter end base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
//                b2 = in.nextInt();
//                if (b2 > MAXIMUM_BASE || b2 < MINIMUM_BASE) {
//                    System.out.println("Invalid base!");
//                    continue;
//                }
//                break;
//            } catch (InputMismatchException e) {
//                System.out.println("Invalid input.");
//                in.next();
//            }
//        }
//        System.out.println(base2base(n, b1, b2));
//        in.close();
//    }
//
//    /**
//     * Checks if a number (as a String) is valid for a given base.
//     */
//    public static boolean validForBase(String n, int base) {
//        char[] validDigits = {
//            '0',
//            '1',
//            '2',
//            '3',
//            '4',
//            '5',
//            '6',
//            '7',
//            '8',
//            '9',
//            'A',
//            'B',
//            'C',
//            'D',
//            'E',
//            'F',
//            'G',
//            'H',
//            'I',
//            'J',
//            'K',
//            'L',
//            'M',
//            'N',
//            'O',
//            'P',
//            'Q',
//            'R',
//            'S',
//            'T',
//            'U',
//            'V',
//            'W',
//            'X',
//            'Y',
//            'Z',
//        };
//        // digitsForBase contains all the valid digits for the base given
//        char[] digitsForBase = Arrays.copyOfRange(validDigits, 0, base);
//
//        // Convert character array into set for convenience of contains() method
//        HashSet<Character> digitsList = new HashSet<>();
//        for (int i = 0; i < digitsForBase.length; i++) {
//            digitsList.add(digitsForBase[i]);
//        }
//
//        // Check that every digit in n is within the list of valid digits for that base.
//        for (char c : n.toCharArray()) {
//            if (!digitsList.contains(c)) {
//                return false;
//            }
//        }
//
//        return true;
//    }
//
//    /**
//     * Method to convert any integer from base b1 to base b2. Works by
//     * converting from b1 to decimal, then decimal to b2.
//     *
//     * @param n The integer to be converted.
//     * @param b1 Beginning base.
//     * @param b2 End base.
//     * @return n in base b2.
//     */
//    public static String base2base(String n, int b1, int b2) {
//        // Declare variables: decimal value of n,
//        // character of base b1, character of base b2,
//        // and the string that will be returned.
//        int decimalValue = 0;
//        int charB2;
//        char charB1;
//        String output = "";
//        // Go through every character of n
//        for (int i = 0; i < n.length(); i++) {
//            // store the character in charB1
//            charB1 = n.charAt(i);
//            // if it is a non-number, convert it to a decimal value >9 and store it in charB2
//            if (charB1 >= 'A' && charB1 <= 'Z') {
//                charB2 = 10 + (charB1 - 'A');
//            } // Else, store the integer value in charB2
//            else {
//                charB2 = charB1 - '0';
//            }
//            // Convert the digit to decimal and add it to the
//            // decimalValue of n
//            decimalValue = decimalValue * b1 + charB2;
//        }
//
//        // Converting the decimal value to base b2:
//        // A number is converted from decimal to another base
//        // by continuously dividing by the base and recording
//        // the remainder until the quotient is zero. The number in the
//        // new base is the remainders, with the last remainder
//        // being the left-most digit.
//        if (0 == decimalValue) {
//            return "0";
//        }
//        // While the quotient is NOT zero:
//        while (decimalValue != 0) {
//            // If the remainder is a digit < 10, simply add it to
//            // the left side of the new number.
//            if (decimalValue % b2 < 10) {
//                output = decimalValue % b2 + output;
//            } // If the remainder is >= 10, add a character with the
//            // corresponding value to the new number. (A = 10, B = 11, C = 12, ...)
//            else {
//                output = (char) ((decimalValue % b2) + 55) + output;
//            }
//            // Divide by the new base again
//            decimalValue /= b2;
//        }
//        return output;
//    }
//}

/**
 * 类用于将“任何”基数转换为“任何”其他基数，其中“任何”意味着从 2 到 36。
 * 通过从基数 1 转换为十进制再转换为基数 2 来工作。包括用于确定给定基数的数字是否有效的辅助方法。
 *
 * @作者 Michael Rolland
 * @版本 2017.10.10
 */
public final class AnyBaseToAnyBase {
    private AnyBaseToAnyBase() {
    }

    /**
     * 您希望接受为有效输入的最小和最大基数
     */
    static final int MINIMUM_BASE = 2;
    static final int MAXIMUM_BASE = 36;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String n;
        int b1;
        int b2;
        while (true) {
            try {
                System.out.print("输入数字：");
                n = in.next();
                System.out.print("输入起始基数（在 " + MINIMUM_BASE + " 和 " + MAXIMUM_BASE + " 之间）：");
                b1 = in.nextInt();
                if (b1 > MAXIMUM_BASE || b1 < MINIMUM_BASE) {
                    System.out.println("无效的基数！");
                    continue;
                }
                if (!validForBase(n, b1)) {
                    System.out.println("该数字对此基数无效！");
                    continue;
                }
                System.out.print("输入结束基数（在 " + MINIMUM_BASE + " 和 " + MAXIMUM_BASE + " 之间）：");
                b2 = in.nextInt();
                if (b2 > MAXIMUM_BASE || b2 < MINIMUM_BASE) {
                    System.out.println("无效的基数！");
                    continue;
                }
                break;
            } catch (InputMismatchException e) {
                System.out.println("无效输入。");
                in.next();
            }
        }
        System.out.println(base2base(n, b1, b2));
        in.close();
    }



    /**
     * 检查一个数字（作为字符串）是否适用于给定的基数。
     */
    public static boolean validForBase(String n, int base) {
        char[] validDigits = {
                '0',
                '1',
                '2',
                '3',
                '4',
                '5',
                '6',
                '7',
                '8',
                '9',
                'A',
                'B',
                'C',
                'D',
                'E',
                'F',
                'G',
                'H',
                'I',
                'J',
                'K',
                'L',
                'M',
                'N',
                'O',
                'P',
                'Q',
                'R',
                'S',
                'T',
                'U',
                'V',
                'W',
                'X',
                'Y',
                'Z',
        };
        // digitsForBase 包含给定基数的所有有效数字
        char[] digitsForBase = Arrays.copyOfRange(validDigits, 0, base);

        // 将字符数组转换为集合，以方便使用 contains() 方法
        HashSet<Character> digitsList = new HashSet<>();
        for (char c : digitsForBase) {
            digitsList.add(c);
        }

        // 检查 n 中的每个数字是否都在该基数的有效数字列表中
        for (char c : n.toCharArray()) {
            if (!digitsList.contains(c)) {
                return false;
            }
        }

        return true;
    }

    /**
     * 将任何整数从基数 b1 转换为基数 b2 的方法。通过将 b1 转换为十进制，然后将十进制转换为 b2 来工作。
     *
     * @param n 要转换的整数。
     * @param b1 起始基数。
     * @param b2 结束基数。
     * @return n 的 b2 基数。
     */
    public static String base2base(String n, int b1, int b2) {
        // 声明变量：n 的十进制值，
        // b1 基数的字符，b2 基数的字符，
        // 以及将要返回的字符串。
        int decimalValue = 0;
        int charB2;
        char charB1;
        String output = "";
        // 遍历 n 的每个字符
        for (int i = 0; i < n.length(); i++) {
            // 将字符存储在 charB1 中
            charB1 = n.charAt(i);
            // 如果它是一个非数字字符，将其转换为大于 9 的十进制值并存储在 charB2 中
            if (charB1 >= 'A' && charB1 <= 'Z') {
                charB2 = 10 + (charB1 - 'A');
            } // 否则，将整数值存储在 charB2 中
            else {
                charB2 = charB1 - '0';
            }
            // 将数字转换为十进制并添加到 n 的十进制值中
            decimalValue = decimalValue * b1 + charB2;
        }

        // 将十进制值转换为 b2 基数：
        // 一个数字从十进制转换为另一个基数
        // 通过不断除以基数并记录
        // 余数，直到商为零。新基数中的数字是余数，
        // 最后一个余数是最左边的数字。
        if (0 == decimalValue) {
            return "0";
        }
        // 当商不为零时：
        while (decimalValue != 0) {
            // 如果余数是小于 10 的数字，简单地将其添加到
            // 新数字的左侧。
            if (decimalValue % b2 < 10) {
                output = decimalValue % b2 + output;
            } // 如果余数大于等于 10，添加一个字符与
            // 新数字的对应值。（A = 10, B = 11, C = 12, ...）
            else {
                output = (char) ((decimalValue % b2) + 55) + output;
            }
            // 再次除以新基数
            decimalValue /= b2;
        }
        return output;
    }

}

