/*
 * Copyright (c) 2001-2003 Shiman Associates Inc. All Rights Reserved.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "mas_internal.h"
#include "assembler.h"
#include "scheduler.h"
#include "signal_handler.h"
#include "mas/mas_nanosleep_reality.h"
#include "mas_dpi.h"
#include "procstat.h"

#define MAS_LOGFILE_PREFIX "mas-" 
#define LOG_OPTIONS LINE_BUFFER

char *loglevel_string[] = {"errors", "warnings", "alerts", "informative", "debugging", "" };


/* Forward declaration */
char **CommandLineToArgv(char *commandline, int *argc);

int
start_logging( int loglevel, int log2stderr )
{
    int si, i;
    char outstr[256];
    char logfile[1024];
    int err;

    if ( !log2stderr )
    {
        masc_strlcpy( logfile, MAS_LOGDIR, sizeof logfile );
        masc_strlcat( logfile, "/", sizeof logfile );
        masc_strlcat( logfile, MAS_LOGFILE_PREFIX, sizeof logfile);
        masc_strlcat( logfile, "1.log", sizeof logfile );
        
        /* set up logging, crash finder on */
        fprintf(stderr, "Logging messages to file '%s'\n", logfile );
        err = masc_init_log_program( logfile, "Initializing MAS", LOG_OPTIONS );
        if (err < 0)
        {
            masc_init_log_program( "", "Initializing MAS", LOG_OPTIONS );
            masc_log_message(0, "Couldn't open log file %s.", logfile);
            masc_log_message(0, "Aborting.");
            return err;
        }
    }
    else
    {
        /* log to standard error */
        masc_init_log_program( "", "Initializing MAS", LOG_OPTIONS );
    }

    masc_log_verbosity( loglevel );

    masc_log_message( 0, "mas: Log level is %d, flags are %d.", loglevel, LOG_OPTIONS );
    si = max( 4, (( loglevel / 10 ) - 1) );
    outstr[0] = 0;
    for (i=0; i<=si; i++)
    {
        masc_strlcat( outstr, loglevel_string[i], sizeof outstr );
        masc_strlcat( outstr, " ", sizeof outstr );
    }
    masc_log_message( 0, "mas: Log includes: %s", outstr );

    return 0;
}

void
start_daemon( void )
{
    fprintf(stderr, "Running in the background.\n");

    /** With thanks to W. R. Stevens... */
    
    /* Decouple MAS from the caller. */
    switch ( fork() )
    {
    case -1:
        /* I can't fork.  I exit. */
        perror ("MAS: Could not fork()");
        perror ("MAS: Aborting.");
        exit(3);
        break;
    case 0:
        /* I am a child -- use the POSIX call to set the process group
         * to our PID. */
         if ( setsid() < 0)
         {
             /* But I cannot.  I exit */
             exit(4);
         }
         /* otherwise, I fall through */
         break;
    default:
        /* I am the parent - I exit. */
        exit(0);
    }

    /*** I'm the child now ****/
    
    /* Close the open file descriptors -- except for the logfile */
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
    errno = 0;
    
    /* Change the working directory */
    chdir("/");

    /* Reset the file creation mask */
    umask(0);

    /* Ignore SIGHUP */
    signal(SIGHUP, SIG_IGN);
}

int main(int argc, char* argv[])
{
    int i;
    int loglevel = MAS_VERBLVL_DEBUG;
    int print_help = 0;
    int err;
    int be_daemon = FALSE;
    int silent = FALSE;
    int flags;

    fprintf(stderr, "\n");
    fprintf(stderr, "Media Application Server  version %d.%d.%d\n", MAS_VERSION_MAJOR, MAS_VERSION_MINOR, MAS_VERSION_TEENY);

    /* Parse the command line parameters */
    for(i=1; i<argc; i++)
    {
	/* assume format is -X and we are checking X */
	switch(argv[i][1])
	{
        case 'l':
	    if(++i < argc)
                loglevel = atoi(argv[i]);
	    else
		print_help = 1;
            break;
        case 'd':
            be_daemon = TRUE;
            break;
        case 's':
            silent = TRUE;
            break;
        case 'h':
        case '?':
        default:
            print_help = 1;
            break;
	}
        if(print_help)
        {
            fprintf(stderr, "usage: mas [-h|-?] [-d] [-s] [-l level]\n");
            fprintf(stderr, "       -s: Run silent.  Do not load the default anx assemblage.\n");
            fprintf(stderr, "       -d: Run as a daemon.\n");
            fprintf(stderr, "       -l: Set the logging verbosity:\n");
            fprintf(stderr, "           0   quiet - emergencies only\n");
            fprintf(stderr, "           10  errors\n");
            fprintf(stderr, "           20  warnings\n");
            fprintf(stderr, "           30  alerts\n");
            fprintf(stderr, "           40  informative messages\n");
            fprintf(stderr, "           50  debug information\n");
            fprintf(stderr, "           255 all messages\n");
            fprintf(stderr, "\n");
            exit(2);
        }
    }

    /* Log to standard error if we're NOT a daemon.  Otherwise, use
       the log file. */
    err = start_logging( loglevel, !be_daemon );
    if ( err < 0 )
        exit(1);

    /* If we should be a daemon, then do it.  When we return from
       this, we'll be the child process. */
    if ( be_daemon ) start_daemon();

    /* Setup process name active/idle reporting. */
    procstat_init( argv[0], TRUE );
    procstat_update( "idle" );
    
    /* Set real time scheduling, if we can. */
    if (masc_set_real_time_priority( 0 ) < 0)
    {
	masc_log_message(MAS_VERBLVL_INFO, "mas: Running without real-time scheduling privledges.");
    }
    else
    {
	masc_log_message(MAS_VERBLVL_INFO, "mas: Server has real-time scheduling privledges.");
    }

    masc_log_message(MAS_VERBLVL_INFO, "mas: Scheduling priority is %d.", masc_get_real_time_priority());

    /* handle shutdown signals */
    install_shutdown_signal_handlers();

    /* invoke scheduler */
    flags = 0;
    if ( silent )
    {
        masc_log_message( MAS_VERBLVL_INFO, "mas: Running silent - not loading the default anx assemblage.");
    }
    else
    {
        flags |= LOAD_ANX_ASMG;
    }
    scheduler_main( flags );

    masc_log_message(0, "mas: finished");

    masc_exit_log_program();
    exit(0);
}
