/***************************************************************************
 *   Copyright (C) 2004 by EVER Sp. z o.o.                                 *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <../config.h>
#endif

#include <iostream>
#include <cstdlib>

#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdarg.h>

#include "gldefs.h"
#include "common.h"
#include "conf.h"
#include "cshmem.h"
#include "clog.h"
#include "monitor.h"

using namespace std;

/*
 * function prototypes
 */
void cmd_display_mon_params();
void cmd_update_user_config();
void cmd_terminate();

/*
 * global variables 
 */
char *str_ext_config = NULL;	// full path and/or filename to user config file 
				// for use instead of default one
bool bModalApp = false;		// modal application, it means that no fork is being done at the beg.
bool bQuietInit = false;	// quiet mode. not messages at the beginning	
const int iShmSize = PS_SHM_SIZE;

/* main function - startup */
int main(int argc, char *argv[])
{
	int i;
	
	while ((i = getopt(argc, argv, "+c:phutvmq")) != EOF) {
		switch (i) {
			case 'q':	// quiet initialization
				bQuietInit = true;
				break;
				
			case 'p':
				cmd_display_mon_params();
				break;
				
			case 'c':	// user config file
				str_ext_config = strdup(optarg);
				break;
			
			case 'u':	// update configuration
				cmd_update_user_config();
				break;
				
			case 't': 	// terminate app
				cmd_terminate();
				break;
			
			case 'v':	// version
				printf("%s\n", VERSION_STRING);
				exit(EXIT_SUCCESS);
				break;
			
			case 'm':	// modal app, do not fork at the beginning
				bModalApp = true;
				break;
			
			case 'h':	// help message
			default:
				printf("%s\n", VERSION_STRING);
				printf("%s\n", TXT_INF_PROGRAMUSAGE);
				exit(EXIT_SUCCESS);
				break;
		}
	}
	
	if (!bQuietInit)
	    printf("%s\n", VERSION_STRING);
	
	if (!is_root()) {
		printf("It is necessary to have a superuser privileges.\n");
		exit(EXIT_SUCCESS);
	}
	
	if (str_ext_config==NULL)
		str_ext_config = strdup(APP_FILE_USERCONFIG);
	
	pid_t childpid; /* variable to store the child's pid */
	int status;     /* parent process: child's exit status */
	static int retval = 0;

	/* now create new process */
#ifndef _DEBUGMODE
	if (!bModalApp) {
	    childpid = fork();
	    if (childpid == 0) {/* fork() returns 0 to the child process */
		retval = service_start();
	    } else if (childpid<0) {
		console_report("Fork failure (%s)!", strerror(errno));
	    } else
		sleep(12);
	} else
	    retval = service_start();
#else /*_DEBUGMODE*/
	retval = service_start();
#endif/*_DEBUGMODE*/
	// cleanup functions
	if (str_ext_config!=NULL)
		free(str_ext_config);

	return EXIT_SUCCESS;
}


void cmd_display_mon_params()
{
	printf("%s\n", VERSION_STRING);

	CShMem *pMain = new CShMem;
	if (pMain->createkey(SHM_PATHNAME, SHM_PROJID)!=SHM_SUCCESS) {
		console_report("%s (%s)\n",TXT_ERR_SHAREMEMCREATE, strerror(errno));
	} else {
		if (pMain->open(iShmSize)==SHM_SUCCESS) {
			//console_report("SHM Opened: shmid=%d; sem_id=%d\n", pMain->shm_id, pMain->sem_id);
			sapp_config *pacfg = new sapp_config;
			sflow_ctl *pfctl = new sflow_ctl;
			if (pacfg!=NULL || pfctl!=NULL) {
			    pMain->read(pacfg, APPCFG_OFFSET, sizeof(sapp_config), true);
			    pMain->read(pfctl, AFLOWCTL_OFFSET, sizeof(sflow_ctl), true);
			    print_device_parameters(pacfg, pfctl);
			    delete pacfg;
			    delete pfctl;
			    pMain->close();
			} else {
			    console_report("Can't allocate memory!\n");
			}
		} else {
			console_report("Application is not started!\n");
		}
	}
	delete pMain;

	exit(EXIT_SUCCESS);
}

void cmd_update_user_config()
{
    if(!bQuietInit)
	printf("%s\n", VERSION_STRING);

    CShMem *pMain = new CShMem;
    if (pMain->createkey(SHM_PATHNAME, SHM_PROJID)!=SHM_SUCCESS) {
	console_report("%s (%s)\n",TXT_ERR_SHAREMEMCREATE, strerror(errno));
    } else {
	if (pMain->open(iShmSize)==SHM_SUCCESS) {
		// inform monitor that we would like to update config
		sflow_ctl *pfctl = new sflow_ctl;
		if (pfctl!=NULL) {
			int iret=pMain->read(pfctl, AFLOWCTL_OFFSET, sizeof(sflow_ctl), true);
			pfctl->bConfigUpdate=true;
			if (pMain->write(pfctl, AFLOWCTL_OFFSET, sizeof(sflow_ctl), true)!=SHM_SUCCESS)
				console_report("%s\n", TXT_ERR_UPDATECONFIG, -1);
			delete pfctl;
			pMain->close();
		} else {
			console_report("Can't allocate memory!\n");
		}
	} else {
		console_report("Application is not started!\n");
	}
    }
    delete pMain;
    exit(EXIT_SUCCESS);
}

void cmd_terminate()
{
    if (!bQuietInit)
	printf("%s\n", VERSION_STRING);

	CShMem *pMain = new CShMem;
	if (pMain->createkey(SHM_PATHNAME, SHM_PROJID)!=SHM_SUCCESS) {
		console_report("%s (%s)\n",TXT_ERR_SHAREMEMCREATE, strerror(errno));
	} else {
		if (pMain->open(iShmSize)==SHM_SUCCESS) {
			sflow_ctl *pfctl = new sflow_ctl;
			if (pfctl!=NULL) {
				int iret=pMain->read(pfctl, 0, sizeof(sflow_ctl), true);
				pfctl->bMonitorActive=false;
				if (pMain->write(pfctl, 0, sizeof(sflow_ctl), true)==SHM_SUCCESS)
					console_report("%s\n", TXT_ERR_SERVICESTOPPING);
				pMain->close();
				delete pfctl;
			} else {
				console_report("Can't allocate memory!\n");
			}
		} else {
			console_report("Application is not started!\n");
		}
	}
	delete pMain;

	exit(EXIT_SUCCESS);
}





