/*This line lets emacs recognize this as -*- C -*- Code
 *-----------------------------------------------------------------------------
 *
 * Project:	Tcl Modules
 * Created:	91/10/23
 * Author:	John L. Furlani<john.furlani@East.Sun.COM>
 *
 * Description:
 *      The Tcl conflict and prereq commands.
 *	
 * $Log: cmdConflict.c,v $
 *
 *
 * Revision 1.5  1993/01/29  06:14:45  jlf
 * Changed the display rules (significantly) for prereq and conflict.
 * Now the lists are columnized for directories.
 *
 * Revision 1.4  1993/01/28  20:20:25  jlf
 * Fixed a bug in conflict which caused it to report a conflict
 * even with the currently loading modulefile.
 *
 * Revision 1.3  1993/01/20  17:48:34  jlf
 * Changed call to IsLoaded to have a NULL for the fourth argument.
 *
 * Revision 1.2  1993/01/20  03:35:40  jlf
 * Updated to use new version of IsLoaded().
 *
 * Revision 1.1  1992/11/05  23:29:22  jlf
 * Initial revision
 *
 *---------------------------------------------------------------------------*/
static char Id[] =
    "$Id: cmdConflict.c,v 2.0 1993/02/21 00:00:36 jlf Exp jlf $";

#include "global.h"
#include <termios.h>

static int
compute_maxwidth(char** list)
{
    int maxwidth = 0;
    while(*list) {
        int entry_len = strlen(*list++);

        if(entry_len > maxwidth) 
            maxwidth = entry_len;
    }

    return maxwidth;
}

static void 
print_spaced_file(char* name, int number, int maxwidth, int space)
{
  int filelen;

  chk4spch(name);  /* turn any weird characters into ? marks */

  filelen = strlen(name);

  fprintf(stderr, "%s", name);
  if(space) {
      while(filelen < maxwidth) {
          filelen++;
          putc(' ', stderr);
      }
  }
}

static int
print_aligned_files(char** list, int tcount, int maxwidth)
{
    int      i, j, cnt, columns, num_rows, ent;
    int      terminal_width = 80;
    struct   winsize window_size;

    if(tcount == 0) return 0;

    if(isatty(2))
        if(ioctl(2, TIOCGWINSZ, &window_size) != -1)
            terminal_width = (window_size.ws_col == 0 ? 80 : 
                              window_size.ws_col);

    /*
     * Subtract 8 from terminal_width to account for the tab at the beginning
     *    of each line.
     */
    if((columns = (terminal_width-8)/maxwidth) == 0)
        columns = 1;

    num_rows = ((tcount-1)/columns)+1;

    for(j=0; j<num_rows; j++) {
        fprintf(stderr, "\t");
        for(i=0; i<columns; i++) {
            ent = (num_rows * i) + j;
            if(ent < tcount)
                print_spaced_file(list[ent], ent+1, maxwidth, i!=columns-1);
        }
        fprintf(stderr, "\n");
    }

    return 1;
}


int
cmdConflict(ClientData client_data,
	    Tcl_Interp* interp,
	    int argc,
	    char* argv[])
{
    char*** savedlists;
    int*    savedlens;
    char** pathlist;
    char** modulelist;
    char*  modulepath = getenv("MODULEPATH");
    int    i, j, k, numpaths, nummodules, maxlen = 0, listcnt = 0;

    if(argc < 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " conflicting-modulefiles\"", (char *) NULL);
        return TCL_ERROR;
    }

    if(flags & (M_REMOVE | M_SWITCH)) {
        return TCL_OK;
    }

    if(! modulepath) {
        Tcl_AppendResult(interp, 
                         "MODULEPATH environment variable not set", NULL);
        return TCL_ERROR;
    }

    if(flags & M_DISPLAY) {
        fprintf(stderr, 
                "Conflicts are (i.e. NONE of these can be currently loaded):\n");
        if((savedlists = (char***)malloc(numpaths*sizeof(char**))) == NULL) {
            Tcl_AppendResult(interp, 
                             "The malloc() failed in cmdConflict().",
                             NULL);
            return TCL_ERROR;
        }
        if((savedlens = (int*)malloc(numpaths*sizeof(int))) == NULL) {
            Tcl_AppendResult(interp, 
                             "The 2nd malloc() failed in cmdConflict().",
                             NULL);
            return TCL_ERROR;
        }
    }

    for(i = 1; argv[i]; i++) {
        pathlist = SplitIntoList(interp, modulepath, &numpaths);

        for(j = 0; j < numpaths; j++) {
            if((modulelist = SortedDirList(interp, pathlist[j], 
                                           argv[i], &nummodules)) == NULL)
                continue;

            if(flags & M_DISPLAY) {
                int len;
                int del = 0;
                for(k=0; k<nummodules; k++) {
                    if(!strcmp(modulelist[k], current_module)) {
                        del = 1;
                        continue;
                    }
                    if((len = strlen(modulelist[k])) > maxlen) maxlen = len;
                    modulelist[k-del] = modulelist[k];
                }
                savedlens[listcnt]    = nummodules - del;
                savedlists[listcnt++] = modulelist;
                continue;
            }

            for(k = 0; k<nummodules; k++) {
                if(IsLoaded(interp, modulelist[k], NULL, NULL) &&
                   strcmp(current_module, modulelist[k])) {
                    Tcl_AppendResult(interp, "The modulefile '", 
                                     current_module,
                                     "' conflicts with the\n\t",
                                     "    currently loaded modulefile, '",
                                     modulelist[k], "'", NULL);
                    FreeList(pathlist, numpaths);
                    FreeList(modulelist, nummodules);
                    return TCL_ERROR;
                }
            }
            FreeList(modulelist, nummodules);
        }

        if(!(flags & M_DISPLAY)) FreeList(pathlist, numpaths);
    }

    if(flags & M_DISPLAY) {
        for(k=0; k<listcnt; k++) {
            print_aligned_files(savedlists[k], savedlens[k], maxlen+2);
            FreeList(savedlists[k], savedlens[k]);
        }
        free(savedlists);
        free(savedlens);
        fprintf(stderr, "\n");
    }

    return TCL_OK;
}

int
cmdPrereq(ClientData client_data,
	    Tcl_Interp* interp,
	    int argc,
	    char* argv[])
{
    char*** savedlists;
    int*    savedlens;
    char**  pathlist;
    char**  modulelist;
    char*   modulepath = getenv("MODULEPATH");
    char*   notloaded_flag = argv[1];
    int     i, j, k, numpaths, nummodules, maxlen = 0, listcnt = 0;
	      
    if(argc < 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " prerequsite-modules\"", (char *) NULL);
        return TCL_ERROR;
    }

    if(flags & M_REMOVE) {
        return TCL_OK;
    }

    if(flags & M_DISPLAY) {
        fprintf(stderr, 
                "Prequisites are (i.e. ONE of these must be loaded):\n");

        if((savedlists = (char***)malloc(1024*sizeof(char**))) == NULL) {
            Tcl_AppendResult(interp, 
                             "The malloc() failed in cmdPrereq().",
                             NULL);
            return TCL_ERROR;
        }
        if((savedlens = (int*)malloc(1024*sizeof(int))) == NULL) {
            Tcl_AppendResult(interp, 
                             "The 2nd malloc() failed in cmdPrereq().",
                             NULL);
            return TCL_ERROR;
        }
    }


    for(i = 1; argv[i] && notloaded_flag; i++) {
        pathlist = SplitIntoList(interp, modulepath, &numpaths);

        for(j = 0; j < numpaths && notloaded_flag; j++) {
            if((modulelist = SortedDirList(interp, 
                                           pathlist[j], 
                                           argv[i], &nummodules)) == NULL)
                continue;

            if(flags & M_DISPLAY) {
                int len;
                for(k=0; k<nummodules; k++) {
                    if((len = strlen(modulelist[k])) > maxlen) maxlen = len;
                }
                savedlens[listcnt]    = nummodules;
                savedlists[listcnt++] = modulelist;
                continue;
            }

            for(k = 0; k < nummodules && notloaded_flag; k++) {
                if(! IsLoaded(interp, modulelist[k], NULL, NULL)) {
                    notloaded_flag = argv[i];
                } else {
                    notloaded_flag = NULL;
                }
            }
            FreeList(modulelist, nummodules);
        }

        if(!(flags & M_DISPLAY)) FreeList(pathlist, numpaths);
    }

    if(flags & M_DISPLAY) {
        for(k=0; k<listcnt; k++) {
            print_aligned_files(savedlists[k], savedlens[k], maxlen+2);
            FreeList(savedlists[k], savedlens[k]);
        }
        free(savedlists);
        free(savedlens);
            
        fprintf(stderr, "\n");
        free(buf);
        return TCL_OK;
    }

    if(notloaded_flag) {
        Tcl_AppendResult(interp, "modulefile '", notloaded_flag, 
                         "' is a prerequisite for modulefile '", 
                         current_module, 
                         "'\n\t\tand '", notloaded_flag, 
                         "' is not currently loaded", NULL);
        return TCL_ERROR;
    }

    return TCL_OK;
}

