/* Copyright (C) 2017 The authors of Py-ChemShell

   This file is part of Py-ChemShell.

   Py-ChemShell is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

   Py-ChemShell 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 Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with Py-ChemShell.  If not, see
   <http://www.gnu.org/licenses/>.  */

/* ChemShell C initialisation routines
   Called from the Fortran main program 
   In turn calls the python initialisation routines */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>


/* Functions implemented in parallel.c */

void chemsh_c_main(void) {

    int  i, j, arglen, maxlen=256;
    int  argc, debug = 0;
    int  ierror;
    int  nWorkgroups = 1;
    int  nProcsMM    = 0;
    int  ga_memory   = 300;
    char *argv[256], arg[256];
    char *abspath;

    char ch, source_file[20], target_file[20];
    FILE *target;

    int  chemsh_c_init_py(int, char **, int);
    void chemsh_c_register_interfaces(int *);
    int  chemsh_f_get_argc(void);
    void chemsh_f_get_argv(int *, int *, int *, char (*)[256]);
    int  chemsh_parallel_c_is_root(void);
    void chemsh_parallel_c_initialise(int, int, int, int);
    void chemsh_parallel_c_finalise(void);
    void chemsh_parallel_c_end_replicas(void);
    void chemsh_parallel_c_run_replicas(void);

    ierror = 0;
    
    /* Get command line arguments via Fortran */
    argc = chemsh_f_get_argc();
    for(i=0; i<argc; i++) {
        chemsh_f_get_argv(&i, &maxlen, &arglen, &arg);
        arg[arglen] = '\0';
        argv[i] = strdup(arg);
    }

    // get debugging level
    for(i=0; i<argc; i++) {
        if(!strcmp(argv[i], "-dbg")) {
            debug = atoi(argv[i+1]);
        }
    }

    for(i=0; i<argc; i++) {
        /* Intercept command-line request for task farming */
        if(!strcmp(argv[i], "-nwg")) {
            nWorkgroups = atoi(argv[i+1]);
        }
        else if(!strcmp(argv[i], "-npmm")) {
            nProcsMM = atoi(argv[i+1]);
        }
        else if(!strcmp(argv[i], "-gm")) {
            ga_memory = atoi(argv[i+1]);
        }

    }

    // open the files specified in command line before parallelism is initialised
    FILE **sources = (FILE **) calloc(argc, sizeof(FILE *));
    if(nWorkgroups > 1) {
        for(i=1; i<argc; i++) {
            sources[i] = fopen(argv[i], "r");
        }
    }

    // parallelism initialisation
    chemsh_parallel_c_initialise(nWorkgroups, nProcsMM, ga_memory, debug);

    // copy input files to all workgroup subdirectories
    if(nWorkgroups > 1) {
        for(i=1; i<argc; i++) {
            if(sources[i]) {
                if(chemsh_parallel_c_is_root()){
                    target = fopen(argv[i], "w");
                    while((j = getc(sources[i])) != EOF) {
                        putc(j, target);
                    }
                    fclose(target);
                }
                fclose(sources[i]);
            }
        }
    }

    // register the linked-in interfaces
    chemsh_c_register_interfaces(&debug);

    if(chemsh_parallel_c_is_root()){

        // start the Python interpreter
        ierror = chemsh_c_init_py(argc, argv, debug);

        // stop the replica processes on exit
        chemsh_parallel_c_end_replicas();

    } else {

        // start the replica processes
        chemsh_parallel_c_run_replicas();
    }

    /* force an error return code if appropriate */
    if(ierror) {
        chemsh_parallel_c_finalise();
        exit(ierror);
    } else {
        // message to mark a normal termination
        if(chemsh_parallel_c_is_root()) {
            printf("\n ChemShell exiting normally.\n\n");
        }
        // defer the finalisation until we print the termination message
        chemsh_parallel_c_finalise();
    }
}

