/* Copyright (c) 1997 The Regents of the University of California.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

#include "m_imp.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

#ifdef NT
#include <windows.h>
#include <winbase.h>
#endif

void sys_announce(void);
void pd_init(void);
int sys_argparse(int argc, char **argv);
int sys_startgui(void);
int m_scheduler(void);

int sys_debuglevel;
t_symbol *sys_progdir;
t_symbol *sys_openfile = &s_;

typedef struct _fontinfo
{
    int fi_fontsize;
    int fi_width;
    int fi_height;
} t_fontinfo;

static t_fontinfo sys_fontlist[] = {
    {8, 0, 0}, {10, 0, 0}, {12, 0, 0}, {14, 0, 0}, {16, 0, 0}, {24, 0, 0}};
#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))

t_fontinfo *sys_findfont(int fontsize)
{
    int i;
    t_fontinfo *fi;
    for (i = 0, fi = sys_fontlist; i < (NFONT-1); i++, fi++)
    	if (fontsize < fi[1].fi_fontsize) return (fi);
    return (sys_fontlist + (NFONT-1));
}

int sys_nearestfontsize(int fontsize)
{
    return (sys_findfont(fontsize)->fi_fontsize);
}

int sys_fontwidth(int fontsize)
{
    return (sys_findfont(fontsize)->fi_width);
}

int sys_fontheight(int fontsize)
{
    return (sys_findfont(fontsize)->fi_height);
}

int sys_defaultfont;

static char *sys_config = 0;
static int srate = 44100;

static void openit(t_symbol *dir)
{
    char bigbuf[MAXPDSTRING];
    char *filewas = sys_openfile->s_name, *dirwas = dir->s_name;
    char *fileafter;
    if (*filewas == '/')
    {
    	strncpy(bigbuf, filewas, MAXPDSTRING);
    	bigbuf[MAXPDSTRING-1] = 0;
    }
    else
    {
    	int nleft;
    	strncpy(bigbuf, dirwas, MAXPDSTRING-1);
    	bigbuf[MAXPDSTRING-2] = 0;
    	nleft = MAXPDSTRING - 1 - strlen(bigbuf);
    	strcat(bigbuf, "/");
    	if (nleft > 0)
    	{
    	    strncat(bigbuf, filewas, nleft);
    	    bigbuf[MAXPDSTRING-1] = 0;
    	}
    }
    fileafter = strrchr(bigbuf, '/');
    *fileafter = 0;
    fileafter++;
    glob_evalfile(0, gensym(fileafter), gensym(bigbuf));
}

/* this is called from the gui process; until then we don't know the cwd. */
void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
{
    t_symbol *dir;
    if (argc != 1 + 2 * NFONT) bug("glob_initfromgui");
    dir = atom_getsymbolarg(0, argc, argv);
    sys_fontlist[0].fi_width =  atom_getintarg(1, argc, argv);
    sys_fontlist[0].fi_height = atom_getintarg(2, argc, argv);
    sys_fontlist[1].fi_width =  atom_getintarg(3, argc, argv);
    sys_fontlist[1].fi_height = atom_getintarg(4, argc, argv);
    sys_fontlist[2].fi_width =  atom_getintarg(5, argc, argv);
    sys_fontlist[2].fi_height = atom_getintarg(6, argc, argv);
    sys_fontlist[3].fi_width =  atom_getintarg(7, argc, argv);
    sys_fontlist[3].fi_height = atom_getintarg(8, argc, argv);
    sys_fontlist[4].fi_width =  atom_getintarg(9, argc, argv);
    sys_fontlist[4].fi_height = atom_getintarg(10, argc, argv);
    sys_fontlist[5].fi_width =  atom_getintarg(11, argc, argv);
    sys_fontlist[5].fi_height = atom_getintarg(12, argc, argv);
    if (sys_openfile != &s_) openit(dir);
}

/* this is called from main() in s_entry.c */
int sys_main(int argc, char **argv)
{
    sys_announce();
    pd_init();    	    	    	    	/* start the message system */
    if (sys_argparse(argc, argv)) return (1);	/* parse cmd line */
    if (sys_startgui()) return(1);  	    	/* turn on the gui */
    if (sys_init_sysdep(sys_config, srate)) 	/* open audio and MIDI */
    	return (1);
    else return (m_scheduler());   	    	/* run scheduler until quits */
}

extern char glob_datestamp[];
void sys_announce(void)
{
    fprintf(stderr, "Pd version 0.23\n%s", glob_datestamp);
}

static char usagemessage[] = 
"pd: flags are:\n\
-r <srate>   -- set sample rate\n\
-adc         -- audio input only\n\
-dac         -- audio output only\n\
-ada         -- audio input and output (the default)\n\
-nosound     -- no audio i/o\n\
-audiobuf    -- specify size of audio buffer in msec\n\
-open <file> -- open a file on startup (sorry, only one file)\n\
-lib <file>  -- load a library (multiple libraries allowed)\n\
-font        -- set default font size in points\n\
-d <n>       -- set debug level\n";

static char ntmessage[] =
"-listdev         -- list audio and MIDI devices and exit\n\
-soundindev <n>   -- specify audio input device number\n\
-soundoutdev <n>  -- specify audio output device number\n\
-midiindev <n>    -- specify MIDI input device number\n\
-midioutdev <n>   -- specify MIDI output device number\n";

int sys_argparse(int argc, char **argv)
{
    char sbuf[MAXPDSTRING], *sp;
    char *lastslash; 
    FILE *pipef;

#ifdef NT
    char buffer[MAXPDSTRING];
    GetModuleFileName(NULL, buffer, sizeof(buffer));
    for (sp = buffer; *sp != '\0'; sp++)
	if (*sp == '\\') *sp = '/';
    argv[0] = buffer;
#endif

    lastslash = strrchr(argv[0], '/');
    if (lastslash)
    {
    	*lastslash = 0;
    	lastslash = strrchr(argv[0], '/');
    	if (lastslash)
    	{
    	    if (lastslash > argv[0] + (MAXPDSTRING-1))
    	    	lastslash = argv[0] + (MAXPDSTRING-1);
    	    strncpy(sbuf, argv[0], lastslash-argv[0]);
    	    sbuf[lastslash-argv[0]] = 0;
    	    sys_progdir = gensym(sbuf);
    	}
    	else sys_progdir = gensym("..");
    }
    else sys_progdir = gensym(".");

    argc--; argv++;
    while ((argc > 0) && **argv == '-')
    {
    	if (!strcmp(*argv, "-r") && argc > 1 &&
    	    sscanf(argv[1], "%d", &srate) >= 1)
    	{
    	    argc -= 2;
    	    argv += 2;
    	}
    	else if (!strcmp(*argv, "-adc"))
    	{
    	    sys_config = "a";
    	    argc--; argv++;
    	}
    	else if (!strcmp(*argv, "-dac"))
    	{
    	    sys_config = "d";
    	    argc--; argv++;
    	}
     	else if (!strcmp(*argv, "-ada"))
    	{
    	    sys_config = "b";
    	    argc--; argv++;
    	}
    	else if (!strcmp(*argv, "-nosound"))
    	{
    	    sys_config = "n";
    	    argc--; argv++;
    	}
    	else if (!strcmp(*argv, "-audiobuf"))
    	{
    	    sys_audiobuf(atoi(argv[1]));
    	    argc -= 2; argv += 2;
    	}
#ifdef __linux__
    	else if (!strcmp(*argv, "-frags"))
    	{
    	    sys_linuxfrags(atoi(argv[1]));
    	    argc -= 2; argv += 2;
    	}
    	else if (!strcmp(*argv, "-fragsize"))
    	{
    	    sys_linuxfragsize(atoi(argv[1]));
    	    argc -= 2; argv += 2;
    	}
#endif
    	else if (!strcmp(*argv, "-open") && argc > 1)
    	{
    	    sys_openfile = gensym(argv[1]);
    	    argc -= 2;
    	    argv += 2;
    	}
        else if (!strcmp(*argv, "-lib") && argc > 1)
        {
            char *loadlib = strtok(argv[1], " :");          
            while(loadlib)
            {
                if (!sys_loademup(loadlib, ".")) return(1);
                loadlib = strtok(NULL, " :");
            }
            argc -= 2;
            argv += 2;
        }
    	else if (!strcmp(*argv, "-font") && argc > 1)
    	{
    	    sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
    	    argc -= 2;
    	    argv += 2;
    	}
    	else if (!strcmp(*argv, "-d") && argc > 1 &&
    	    sscanf(argv[1], "%d", &sys_debuglevel) >= 1)
    	{
    	    argc -= 2;
    	    argv += 2;
    	}
#ifdef NT
    	else if (!strcmp(*argv, "-listdev"))
    	{
    	    nt_listdevs();
    	    argc--; argv++;
    	}
    	else if (!strcmp(*argv, "-soundindev"))
    	{
    	    nt_soundindev(atoi(argv[1]));
    	    argc -= 2; argv += 2;
    	}
    	else if (!strcmp(*argv, "-soundoutdev"))
    	{
    	    nt_soundoutdev(atoi(argv[1]));
    	    argc -= 2; argv += 2;
    	}
    	else if (!strcmp(*argv, "-midiindev"))
    	{
    	    nt_midiindev(atoi(argv[1]));
    	    argc -= 2; argv += 2;
    	}
    	else if (!strcmp(*argv, "-midioutdev"))
    	{
    	    nt_midioutdev(atoi(argv[1]));
    	    argc -= 2; argv += 2;
    	}
#endif /* NT */
    	else
    	{
    	    fprintf(stderr, "%s", usagemessage);
#ifdef NT
    	    fprintf(stderr, "%s", ntmessage);
#endif /* NT */
    	    return (1);
    	}
    }
    if (!sys_defaultfont) sys_defaultfont = 8;
    if (argc > 1) fprintf(stderr, "pd: extra args dropped\n");
    if (argc > 0) sys_openfile = gensym(argv[0]);
    return (0);
}

int sys_getblksize(void)
{
    return (DACBLKSIZE);
}
