#!/usr/bin/icmake -qt /tmp/icmstart

#define SKEL  "/usr/share/icmake"

string g_skelpath = SKEL;
string g_skelfile = "icmstart.rc";
string g_program;
string g_destdir;
string g_defaultcommand = "";

int g_confirminstall = 0;
int g_skeletons = 1;
int g_replace = 0;
int g_debug = 0;
int g_askreplace = 1;

void usage()
{
    printf("Usage: ", g_program, " [Options] dir [program|library]\n"
        "Where:\n"
        "   Options:\n"
        "     -d: debug: do not execute any commands, but show commands\n"
        "         that would have been executed\n"
        "     -I: do NOT install the skeleton files, if any.\n"
        "     -r: replace already existing files/directories\n"
        "     -s skelpath: Read the skeleton information from the directory\n"
        "        or file `skelpath'.\n"
        "        By default the skeleton files are located in " SKEL "\n"
        "        using skeleton file " SKEL "/icmstart.rc\n"
        "\n"
        "   dir: the directory to contain CLASSES, icmconf and the "
                                                        "skeleton files\n"
        "   program |\n"
        "   library: [optional] default command passed to the icmbuild "
                                                                    "script\n"
        "\n");

    exit(1);
}

void die(string s)
{
    printf(g_program, ": ", s, "\n");
    exit(1);
}

int isFile(string s)
{
    return (int)stat(P_NOCHECK, s)[0] & S_IFREG;
}

void syscall(string command)
{
    if (g_debug)
        printf(command, "\n");
    else
        system(command);
}

void arguments(int argc, list argv)
{
    int cmdidx = 1;
    string arg;
    list icm;
    string skelpath = SKEL;
    int length;

    icm = getenv("ICM");                // ICM environment var defined?

    if ((int)icm[0] == 1)                
        skelpath = icm[1];              // then re-assign skelpath

    while (cmdidx < argc)
    {
        arg = argv[cmdidx];

        if (arg[0] != "-")              // no (more) options
            break;

        if (arg[1] == "d")              // -d: debug
            g_debug = 1;
        else if (arg[1] == "I")         // -I: no skeletons
            g_skeletons = 0;
        else if (arg[1] == "r")         // -r: replace existing file(s)
        {
            g_askreplace = 0;
            g_replace = 1;
        }
        else if (arg[1] == "s")         // -s: re-assign g_skelpath
        {
            arg = substr(arg, 2, 999);  // get all beyond -s

            if (arg == "")              // or get then next argument
            {
                if (cmdidx == argc)
                    die("-s lacks skeleton dir specification");

                arg = argv[++cmdidx];
            }
            skelpath = arg;             // reassign skelpath
        }
        else
            printf("[Warning] ignoring unkown option ", arg, "\n");

        ++cmdidx;
    }

    if (isFile(skelpath))
    {
        g_skelpath = get_path(skelpath);
        g_skelfile = substr(g_skelpath, strlen(g_skelpath), 999);
    }
    else
        g_skelpath = skelpath;

    for (length = strlen(g_skelpath); length-- && g_skelpath[length] == "/"; )
        ;
    g_skelpath = substr(g_skelpath, 0, length + 1) + "/";

    if (!isFile(g_skelpath + g_skelfile))
        die("Can't find configuration file `" + g_skelpath + g_skelfile + "'");

    syscall("mkdir -p " + argv[cmdidx]);     // install the target dir

    g_destdir = argv[cmdidx];
    if (!g_debug)
        g_destdir = chdir(g_destdir);

    if (++cmdidx < argc)
    {
        arg = argv[cmdidx];
        if (arg == "program" || arg == "library")
            g_defaultcommand = "#define DEFCOM \"" + arg + "\"\n";
        else
            printf("Ignored initial command `", arg, "' for icmbuild\n");
    }
}

int replace(string target)
{
    string ret;

    while (g_askreplace)
    {
        printf("`", target, "' exists.\n"
               "Replace [?akNy] ? ");
        ret = getch();

        if (ret == "a")
        {
            g_replace = 1;
            g_askreplace = 0;
            break;
        }

        if (ret == "k")
        {
            g_askreplace = 0;
            break;
        }

        if (ret == "y")
            return 1;

        if (ret == "n" || ret == "\n")
            return 0;

        printf("Press `a' to replace all,\n"
               "      `k' to keep all current versions\n"
               "      `n' to keep current version (default)\n"
               "      `?' shows this help\n");
    }
    return g_replace;
}

int install(string target)
{
    return (int)(!exists(target) || replace(target));
}

int install_file(string source)
{
    string skeleton;

    if (source[0] == "/")
        skeleton = source;
    else
        skeleton = g_skelpath + source;

    if (!exists(skeleton))
    {
        printf("[Warning] Can't find `" + skeleton + "'\n");
        return 0;
    }
    
    if (install(g_destdir + source))
    {
        syscall("tar cf - -C " + g_skelpath + " " + source + " | "
               "tar xf - -C " + g_destdir);
        return 1;
    }

    return 0;
}

void install_std()
{
    install_file("CLASSES");
    if (install_file("icmconf") && g_defaultcommand != "")
        fprintf("icmconf", g_defaultcommand);
}

int confirminstall(string target)
{
    if (g_confirminstall)
    {
        printf("Install `", target, "' [yN] ? ");
        return getch() == "y";
    }

    return 1;
}

void installLine(string line)
{
    int idx;
    list fields;
    string entry;

    fields = strtok(line, " \t\n");
    entry = fields[0];

    if (sizeof(fields) == 0 || entry[0] == "#")
        return;

    g_confirminstall = entry == "?";

    for (idx = g_confirminstall; idx < sizeof(fields); ++idx)
    {
        entry = fields[idx];

        if (!g_replace && !g_askreplace && exists(g_destdir + entry))
            return;

        if (!confirminstall(entry))
            return;

        install_file(entry);
    }
}

void install_rc()
{
    string rcfile;
    list line;

    rcfile = g_skelpath + g_skelfile;

    if (!exists(rcfile))
    {
        printf("[Warning] Can't find `" + rcfile + "\n");
        return;
    }

    while (1)
    {
        line = fgets(rcfile, (int)line[1]);
        if (!line)
            break;
        installLine(line[0]);
    }
}

int main(int argc, list argv)
{
    echo(OFF);

    g_program = get_base(argv[0]);

    if (argc == 1)
        usage();

    arguments(argc, argv);

    install_std();              // install CLASSES and icmconf
    install_rc();               // install .rc file elements

    printf("Done. Don't forget to inspect the #defines in\n"
            "'", g_destdir, "icmconf'\n");

    return 0;
}
