#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void print_usage(const char *prog) {
    printf("IPBIG ipv4 address to bignum converter \n");
    printf("Usage:\n");
    printf("  %s <IPv4>                  → IPv4 → small decimal (always works with ping)\n", prog);
    printf("  %s <big_number>            → Big decimal → IPv4 (lower 32 bits)\n", prog);
    printf("  %s -s <digits> <IPv4>      → Large decimal (~<digits> digits) that works on UNIX/Linux\n", prog);
    printf("\nExamples:\n");
    printf("  %s 192.168.11.1\n", prog);
    printf("  %s -s 100 192.168.11.1\n", prog);
    printf("\nThe -s version inserts the exact number of zeros needed so that\n");
    printf("the huge number is mathematically congruent modulo 2^32 to the IP.\n");
    printf("UNIX/Linux ping will therefore resolve it correctly, no matter how large.\n");
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        print_usage(argv[0]);
        return 1;
    }

    srand((unsigned int)time(NULL));

    if (strcmp(argv[1], "-s") == 0) {
        if (argc != 4) {
            print_usage(argv[0]);
            return 1;
        }

        int target_digits = atoi(argv[2]);
        if (target_digits < 1 || target_digits > 2000) {
            printf("Error: digits must be between 1 and 2000.\n");
            return 1;
        }

        // Parse IPv4
        unsigned int a, b, c, d;
        if (sscanf(argv[3], "%u.%u.%u.%u", &a, &b, &c, &d) != 4 ||
            a > 255 || b > 255 || c > 255 || d > 255) {
            printf("Error: Invalid IPv4 address.\n");
            return 1;
        }

        unsigned long long ip_val = ((unsigned long long)a << 24) |
                                    ((unsigned long long)b << 16) |
                                    ((unsigned long long)c << 8)  | d;

        char ip_str[32];
        snprintf(ip_str, sizeof(ip_str), "%llu", ip_val);
        int k = strlen(ip_str);          // digits in the small IP value (1..10)

        if (target_digits <= k) {
            printf("%s\n", ip_str);
            return 0;
        }

        int p = 32 - k;                  // number of zeros we must insert to force divisibility by 2^(32-k)
        int random_digits = target_digits - k - p;

        if (random_digits < 1) {
            // Not enough room for the required zeros + at least 1 random digit
            printf("%s\n", ip_str);
            return 0;
        }

        // Generate random high digits (first digit never 0)
        printf("%d", 1 + (rand() % 9));
        for (int i = 1; i < random_digits; i++) {
            printf("%d", rand() % 10);
        }

        // Insert exactly the required zeros (this makes the math work)
        for (int i = 0; i < p; i++) {
            printf("0");
        }

        // Append the exact decimal of the IP value
        printf("%s\n", ip_str);

        return 0;
    }

    // Normal mode (no -s)
    char *input = argv[1];

    if (strchr(input, '.') != NULL) {
        // IPv4 → small decimal
        unsigned int a, b, c, d;
        if (sscanf(input, "%u.%u.%u.%u", &a, &b, &c, &d) != 4 ||
            a > 255 || b > 255 || c > 255 || d > 255) {
            printf("Error: Invalid IPv4.\n");
            return 1;
        }

        unsigned long long val = ((unsigned long long)a << 24) |
                                 ((unsigned long long)b << 16) |
                                 ((unsigned long long)c << 8)  | d;

        printf("%llu\n", val);
    }
    else {
        // Big decimal → IPv4 (safe digit-by-digit mod 2^32)
        unsigned long long mod = 0;
        for (char *p = input; *p; ++p) {
            if (*p >= '0' && *p <= '9') {
                mod = (mod * 10 + (*p - '0')) & 0xFFFFFFFFULL;
            }
        }

        unsigned int val = (unsigned int)mod;

        printf("%u.%u.%u.%u\n",
               (val >> 24) & 0xFF,
               (val >> 16) & 0xFF,
               (val >> 8)  & 0xFF,
               val & 0xFF);
    }

    return 0;
}


