/*
 * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
 *
 * Author:     Iceyer <me@iceyer.net>
 *
 * Maintainer: Iceyer <me@iceyer.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>     /* for DEBUG */
#include <stdlib.h>    /* for exit */
#include <getopt.h>
#include <string.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "license_file.h"
#include "license_key.h"

extern struct license_file *created_license_file(
    const char *username,
    const char *authorization_code,
    const char *product,
    const char *copyright,
    const char *edition,
    const char *version,
    const char *machine_code,
    u64  validity_begin,
    u64  validity_end,
    u64 licenses_number,
    const char* private_key_file);

/*
// signature edition
./license_issuer -t key -c Y2016CR0001 -e Y2016E0001 -v 15 -n 100 -f ~/desktop.key

./license_issuer -t key -c Y2016CR0001 -e Y2016E0001 -v 15 -n 1
GRWCLEHT6QNR68JLQJTF

// signature edition product
./license_issuer -u 深度测试 \
              -a TESTCODE \
              -p 深度操作系统桌面版软件V15（标准） \
              -m b949-9f57-de38-8548 \
              -b 1459468800 \
              -d 1661974400 \
              -t file \
              -c Y2016CR0001 \
              -e Y2016E0001 \
              -v 15 \
              -k ./license_rsa \
              -f ~/b949-9f57-de38-8548.key

./license_issuer -u 深度测试 \
                 -a TESTCODE \
                 -p 深度操作系统桌面版软件V15（标准） \
                 -m b949-9f57-de38-8548 \
                 -b 1459468800 \
                 -d 1661974400 \
                 -t file \
                 -c Y2016CR0002 \
                 -e Y2016E0002 \
                 -v 15 \
                 -k ./license_rsa \
                 -f ~/b949-9f57-de38-8548-server.key

./license_issuer -u 深度测试 \
              -a ACBVLYHFML \
              -p 深度操作系统桌面版软件V15（标准） \
              -n 100 \
              -b 1459468800 \
              -d 1661974400 \
              -t file \
              -c Y2016CR0001 \
              -e Y2016E0001 \
              -v 15 \
              -k ./license_rsa \
              -f ~/volume-100.key
*/

bool debug = false;

#define DEBUG(format, ...)  if (debug) printf(format, ##__VA_ARGS__);

int main(int argc, char **argv)
{
    int c;
    char username[4096];
    char authorization_code[4096];
    char product[4096];
    char file[4096];
    char machine_code[4096];
    char copyright[4096];
    char edition[4096];
    char version[4096];
    char rsa_private_key[4096];
    char authorization_type_str[4096];

    time_t validity_begin;
    time_t validity_end;
    u64 licenses_number = 0;
    int authorization_type;
    int fp;

    while (1) {
        int this_option_optind = optind ? optind : 1;
        int option_index = 0;
        static struct option long_options[] = {
            {"authorization_type",  required_argument, 0, 't'},
            {"username",            required_argument, 0, 'u'},
            {"authorization_code",  required_argument, 0, 'a'},
            {"product",             required_argument, 0, 'p'},
            {"copyright",           required_argument, 0, 'c'},
            {"edition",             required_argument, 0, 'e'},
            {"version",             required_argument, 0, 'v'},
            {"validity_begin",      required_argument, 0, 'b'},
            {"validity_end",        required_argument, 0, 'd'},
            {"licenses_number",     required_argument, 0, 'n'},
            {"machine_code",        required_argument, 0, 'm'},
            {"file",                required_argument, 0, 'f'},
            {"rsa_private_key",     required_argument, 0, 'k'},
            {0, 0, 0, 0}
        };

        c = getopt_long(argc, argv, "it:u:a:p:c:e:v:b:d:n:m:f:k:",
                        long_options, &option_index);
        if (c == -1)
            break;

        DEBUG("get c %d \n", c);
        switch (c) {
        case 0:
            DEBUG("option %s", long_options[option_index].name);
            if (optarg)
                DEBUG(" with arg %s", optarg);
            DEBUG("\n");
            break;
        case 'u':
            DEBUG("option username with value '%s'\n", optarg);
            strncpy(username, optarg, ARRAY_SIZE(username));
            break;
        case 'a':
            DEBUG("option authorization_code with value '%s'\n", optarg);
            strncpy(authorization_code, optarg, ARRAY_SIZE(authorization_code));
            break;
        case 'p':
            DEBUG("option product with value '%s'\n", optarg);
            strncpy(product, optarg, ARRAY_SIZE(product));
            break;
        case 'c':
            DEBUG("option copyright with value '%s'\n", optarg);
            strncpy(copyright, optarg, ARRAY_SIZE(copyright));
            break;
        case 'e':
            DEBUG("option edition with value '%s'\n", optarg);
            strncpy(edition, optarg, ARRAY_SIZE(edition));
            break;
        case 'v':
            DEBUG("option version with value '%s'\n", optarg);
            strncpy(version, optarg, ARRAY_SIZE(version));
            break;
        case 'm':
            DEBUG("option machine_code with value '%s'\n", optarg);
            strncpy(machine_code, optarg, ARRAY_SIZE(machine_code));
            break;
        case 'b':
            validity_begin = (time_t) strtoll(optarg, NULL, 10);
            DEBUG("option validity_begin with value %s", ctime(&validity_begin));
            break;
        case 'd':
            validity_end = (time_t) strtoll(optarg, NULL, 10);
            DEBUG("option validity_end with value %s", ctime(&validity_end));
            break;
        case 'n':
            licenses_number = (u64) strtoll(optarg, NULL, 10);
            DEBUG("option licenses_number with value %ld", licenses_number);
            break;
        case 'f':
            DEBUG("option file with value '%s'\n", optarg);
            strncpy(file, optarg, ARRAY_SIZE(file));
            break;
        case 'k':
            DEBUG("option rsa_private_key with value '%s'\n", optarg);
            strncpy(rsa_private_key, optarg, ARRAY_SIZE(rsa_private_key));
            break;
        case 't':
            DEBUG("option authorization_type_str with value '%s'\n", optarg);
            strncpy(authorization_type_str, optarg, ARRAY_SIZE(authorization_type_str));
            break;

        case '?':
            break;

        default:
            DEBUG("?? getopt returned character code 0%o ??\n", c);
        }
    }

    //parse authorization_type_str
    fp = open(file, O_CREAT | O_RDWR, 0644);
    if (0 == strcmp(authorization_type_str, "file")) {
        struct license_file *lf = created_license_file(
                                      username,
                                      authorization_code,
                                      product,
                                      copyright,
                                      edition,
                                      version,
                                      machine_code,
                                      validity_begin,
                                      validity_end,
                                      licenses_number,
                                      rsa_private_key
                                  );

        write(fp, lf, LICENSE_FILE_SIZE);
        free(lf);
        goto main_exit;

    }

    if (0 == strcmp(authorization_type_str, "key")) {
        for (int i = 0; i < licenses_number; ++i) {
            char key[32] = {0};
            char format_key[40] = {0};
            generate_activation_key(copyright, edition, version, key);

            for (int j = 0; j < 4; ++j) {
                strncpy(&format_key[j*6], &key[j*5], 5);
                strncpy(&format_key[j*6+5], "-", 1);
            }
            format_key[23]=0;
            printf("%s\n", key);
            printf("%s\n", format_key);
            write(fp, format_key, 23);
            write(fp, "\r\n", 1);
        }
        goto main_exit;
    }

    printf("Must set authorization type\n");
main_exit:
    close(fp);
    exit(EXIT_SUCCESS);
}
