/*
 *   Copyright (c) 1996-1999 David Parsons. All rights reserved.
 *   
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *  3. All advertising materials mentioning features or use of this
 *     software must display the following acknowledgement:
 *     
 *   This product includes software developed by David Parsons
 *   (orc@pell.chi.il.us)
 *
 *  4. My name may not be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *     
 *  THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``AS IS'' AND ANY
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
 *  PARSONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 *  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 *  THE POSSIBILITY OF SUCH DAMAGE.
 */

static const char rcsid[] = "$Id: s.configuration.c 1.20 02/06/16 10:24:44-07:00 root@egypt.pell.portland.or.us $";

/*
 * configuration asks various questions about what sort of installation
 * you're planning on doing.
 */

#include <stdio.h>

#include <ndialog.h>
#include <dialog.h>

#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>

#ifdef WITH_NCURSES
#   include <ncurses/curses.h>
#   include <ncurses/term.h>
#else
#   include <curses.h>
#endif

#include "media.h"
#include "util.h"
#include "pathnames.h"
#include "packages.h"

/*
 * standardpartitioning() asks if you're REALLY sure you want to do
 * a standard (`express', in Windows-ese) installation.
 *
 * parameters:
 *	method		-- WITHDOS or STANDARD
 *	space_required	-- how much disk space is needed to install all
 *			   the packages?
 *
 * returns:
 *	WITHDOS,
 *	STANDARD	-- everything fine, we can do the install.
 *	EOF		-- the user decided to back out and reconfigure.
 */
static int
standardpartitioning(int method, unsigned long space_required)
{
    char *msg;

    msg = (method == STANDARD)
		  ? "WARNING: This installation will OVERWRITE whatever\n"
		    "is currently on your first disk!  Are you sure you\n"
		    "want to do this?"
		  : "WARNING: This installation will OVERWRITE everything\n"
		    "on your first disk except for the C: partition! Are\n"
		    "you sure you want to do this?";

    if (dialog_yesno(INSTALLER, msg, -1, -1) == 0)
	if (dopartition(Disk[diskC].device, 1, method==WITHDOS) != 0)
	    return method;

    return EOF;
} /* standardpartitioning */



/*
 * editdisk() is a local for custompartitioning that calls cfdisk for
 * editing a single chosen disk
 */
static int
editdisk(void *obj, void* display)
{
    ListItem *list = getObjList(obj);
    //int     nrlist = getObjListSize(obj);
    int       curr = getObjCursor(obj);

    run(1, PATH_CFDISK, "cfdisk", list[curr].id, (char*)0);
    touchwin(curscr);
    wrefresh(curscr);
    return 1;
} /* editdisk */


/*
 * partition_other_disks() -- partition and label disks other than the bootdisk.
 * returns:
 *	1 -- success.
 *	0 -- backed out of this dialogue.
 */
static int
partition_other_disks(int autodisk)
{
    void *obj;
    int rc;

    /* after maybe partitioning the root partition, we ask about
     * partitioning any other disks we might find here.
     */
    while (1) {
	disklist = get_disk_list(autodisk ? diskC : EOF);

	if (LIAcount(disklist) == 0) {
	    delete_disk_list(disklist);
	    /* no other disks?  Okay to go */
	    return 1;
	}
	else {
	    char *msg = autodisk
		    ?  "If you wish to configure any disk partitions on the\n"
		       "other disks in your system, pick the disk from this\n"
		       "menu.  When you finish here, the system will ask you\n"
		       "where to put the partitions"
		    :  "To configure a disk, pick the disk from this menu;\n"
		       "You will need a Linux partition to install Linux on\n"
		       "and it is recommended that you set up at least one\n"
		       "partition for the system to use for virtual memory.";

	    const int nrlist = LIAcount(disklist);
	    const ListItem* list = LIAlist(disklist);

	    obj = newMenu(-1,0,-1,(nrlist>8)?8:nrlist, nrlist, list,
		0/*no prompt*/,
		"" /*no prefix, but we want to box the menu */,
		MENU_SELECTION|SHOW_IDS|NO_HOTKEYS,
		editdisk, "disks.html");

	    obj = ObjChain(obj,
		    newOKButton(-1, "DONE", 0, "disks.html"));

	    rc = MENU(obj, FORMSZ, INSTALLER, msg, 0);
	    deleteObjChain(obj);

	    if (rc == MENU_OK) {
		/* Now we ask where the partitions will be mounted */
		rc = mountpar(autodisk ? diskC : EOF);
		delete_disk_list(disklist);
		if (rc >= 0)
		    return 1;
	   }
	   else {
		delete_disk_list(disklist);
		if (rc == MENU_ESCAPE)
		    return 0;
	    }

	} /* .. if (|disklist| > 0) */
    }
} /* partition_other_disks */


/*
 * custompartitioning() handles disk partitioning for a CUSTOM
 * install.
 *
 * parameters:
 *	withdosC	-- there is a DOS partition on disk C:
 *	space_required	-- how much room do we need to install the system?
 *	space_wanted	-- how much room would we like to have for future expansion?
 *
 * returns:
 *	CUSTOM		-- the user is doing a custom installation
 *	CUSTOM_AUTOROOT	-- the user is doing a custom installation, but let
 *			   the installer partition the root disk.
 *	EOF		-- the user decided to back out and reconfigure.
 */
int
custompartitioning(int withdosC, unsigned long space_required, unsigned long space_wanted)
{
    int rc;			/* random return code */
    int autodisk = 0;		/* set nonzero if we put a default */
				/* partition map onto the root disk */

    while (1) {
	if (space_required <= diskCsize-SWAPMEGS) {
	    /* we might be able to automatically partition the root partition,
	     * so we might as well ask about it.
	     */
	    rc = ndialog_yesno(INSTALLER,
		withdosC
		    ? "You appear to have MS-DOS installed on the first disk.\n"
		      "If you'd like, I can install Linux onto the first disk\n"
		      "alongside the MS-DOS partition, or you can set up your\n"
		      "disk layout by hand.\n"
		      "\n"
		      "Shall I install your Linux system onto the first disk,\n"
		      "or do you want to tell me the disk layout?"
		    : "If you'd like, I can install Linux onto the first disk\n"
		      "on your system, overwriting whatever is already there.\n"
		      "If you have multiple operating systems on this machine\n"
		      "you will need to tell me where you want to install the\n"
		      "Linux system.\n"
		      "\n"
		      "Shall I install your Linux system onto the first disk,\n"
		      "or do you want to tell me the disk layout?",
		0, 0, "1:Install", "2:Tell me");

	    if (rc < 0)
		return EOF;
	    else if (rc == 0 && dopartition(Disk[diskC].device, 1, withdosC))
		autodisk = 1;
	}

	if (partition_other_disks(autodisk))
	    return autodisk ? CUSTOM_AUTOROOT : CUSTOM;
    } /* big while loop */
    return EOF;
} /* custompartitioning */


/*
 * askpackages() mark the packages we want to install
 *
 * parameters:
 *	withdosC	-- there is a dos partition on disk C:
 *	method		-- how we're going to install.
 *
 * returns:
 *	method		-- everything fine, we can do the install.
 *	EOF		-- the user decided to back out and retconfigure.
 */
int
askpackages(int withdosC, int method)
{
    int rc;
    long required = 0;
    long wanted = 0;

    while (1) {
	if (method == CUSTOM) {
	    rc = choosepackages(&wanted, &required);

	    if (rc != EOF) {
		rc = custompartitioning(withdosC, required, wanted*2);
		if (rc == EOF)
		    continue;
	    }
	    return rc;
	}
	takeallpackages(&wanted, &required);
	return standardpartitioning(method, required);
    }
} /* askpackages */


/*
 * howtoinstall() asks how the user wants to install the Linux system
 *
 * This is moderately sick and horrible.  We aren't using listItem.id
 * in menu[], so we pervert it into holding the (integer) return code
 * that we want to return for each menu selection.  If you are foolish
 * enough to create the Menu object with SHOW_IDS, the program will
 * obligingly explode.
 *
 * parameters:
 *	hasdosC		-- the C disk contains a MS-DOS/Windows partition,
 *			   so ask configuration questions accordingly.
 *
 * returns:
 *	WITHDOS,
 *	STANDARD,
 *	CUSTOM,
 *	CUSTOM_AUTOROOT	-- everything fine, we can do the install.
 *	EOF		-- the user decided to back out and retconfigure.
 */
int
howtoinstall(int hasdosC)
{
    static ListItem menu[3];
    int nrmenu = 0;

    char msg[80];			/* menu title for withdos install */
    char msg2[80];			/* menu title for standard install */
    int x;				/* a random index */
    void *chain;			/* ObjChain() holder */
    int rc;				/* our return code */

    /* If we found a CD on the system, we can ask about standard and/or
     * custom installations.  Otherwise we're stuck trying to do an
     * install via the network (or zip disk, or images written to a disk
     * partition.)
     */

    /* want to keep your icky Windows around?
     */
    if (hasdosC) {
	snprintf(msg, sizeof msg, "Standard, preserving C:");
	menu[nrmenu].item = msg;
	menu[nrmenu].id = (char*)WITHDOS;
	menu[nrmenu].selected = 0;
	nrmenu++;
    }
    /* If we're installing off the dos partition, we (obviously) can't
     * overwrite that partition
     */
    if (mType(mdesc) != M_DOS) {
	snprintf(msg2, sizeof msg2,
		 hasdosC ? "Standard, overwriting C:"
			 : "Standard", mName(mdesc));
	menu[nrmenu].item = msg2;
	menu[nrmenu].id   = (char*)STANDARD;
	menu[nrmenu].selected = 0;
	nrmenu++;
    }
    /* DIY! DIY!
     */
    menu[nrmenu].item = "Custom";
    menu[nrmenu].id   = (char*)CUSTOM;
    menu[nrmenu].selected = 0;
    nrmenu++;

    while (1) {
	/* build an object chain of a menu and a "Back" button, then feed it to
	 * MENU() for processing
	 */
	chain = ObjChain(0, newMenu(-1, 0, -1, -1,
				    nrmenu, menu,
				     0, "", 0, okaydone,
				     hasdosC ? "typesdos.html" : "types.html"));

	rc = MENU(chain, FORMSZ,
		  INSTALLER, "What sort of installation do you want to do?", 0);
	deleteObjChain(chain);

	switch (rc) {
	case MENU_ERROR:
	    Error("howtoinstall");
	    break;
	case MENU_OK:
	    for (x=0; x<nrmenu; x++)
		if (menu[x].selected) {
		    use_helpline("Use ESC to return to the previous screen");
		    if ((rc=askpackages(hasdosC, (int)(menu[x].id))) != EOF)
			return rc;
		    use_helpline("Use ESC to cancel the installation");
		}
		break;
	case MENU_ESCAPE:
	case MENU_CANCEL:
	    return EOF;
	}
    }
    /* NOTREACHED */
    return EOF;
} /* howtoinstall */
