// ===========================================================
// Author: Yee Hsu                                     #1-8748
// Instru: Dr. J. Wong
// Date:   May 2, 2001
//
// File: SMVS.cpp
//
// The Server driver. The server first forks a process and
// executes com pd1. Then it continueously listens to
// Com (pd1) and Clients (pd2) and service them if there is
// a request. Clients are created when Com issues a command
// to execute a process. The Server loops indefinitely to
// service the two in such algorithm:
//
//      infinite loop ()
//          read from pipe1, service Com
//          read from pipe2, service Client
//      loop back
// ===========================================================

#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include "Pcib.h"
#include "List.h"
#include "Semaphore.h"
#include "Message.h"
#include "Server.h"
#include "Host.h"

/* ************************************************ */
/*                                                  */
/*              Server Main Driver                  */
/*                                                  */
/* ************************************************ */

void main()
{
    // declaration of all pipes
    int pipe1[2], pipe2[2], pipen[2];

    // create pipe channels for communications
    pipe(pipe1), pipe(pipe2);

    // set channels to be non-blocked
    fcntl(pipe1[0], F_SETFL, O_NONBLOCK);
    fcntl(pipe2[0], F_SETFL, O_NONBLOCK);

    if (fork() == 0)
    {
        // child executes Com pd1
        char pd1[10] = {"\0"};
        sprintf(pd1, "%d", pipe1[1]);
        execl("./Com", "Com", pd1, 0);
        exit(0);
    }
    else
    {
        Server s;       // create Server [ActiveList and Semaphore(s)]
        ComMsg m1;      // m1 - com     -> server
        RequestMsg m2;  // m2 - client  -> server
        ReplyMsg m3;    // m3 - server  -> client

        while (1)
        {
            // listen to com query from pipe1 and service if needed
            if (read(pipe1[0], &m1, sizeof(m1)) > 0)
            {
                if (!strcmp(m1.command, RUN))
                {
                    // create new pipe for process communication
                    pipe(pipen);

                    // fork and insert process to active list
                    int retv = fork();
                    if (retv == 0)
                    {
                        // child executes program
                        SetChannel(pipen[0], pipe2[1]);
                        RunCommand(m1);
                        exit(0);
                    }
                    else
                        s.Insert(retv, pipen[1], m1);
                }
                else if (!strcmp(m1.command, LS))
                {
                    // list information on server queues
                    s.LsCommand(m1);
                }
                else if (!strcmp(m1.command, EXIT))
                {
                    // finalize and terminate server
                    s.ExitCommand();
                    ClosePipes(pipe1, pipe2, pipen);
                    exit(0);
                }
            }

            // listen to client query from pipe2 and service if needed
            if (read(pipe2[0], &m2, sizeof(m2)) > 0)
            {
                m3 = s.SemAction(m2);
                UpdateLogFile(m1, m2);

                if (!(m2.purpose == WAIT_SEM && m3.returnValue == -1))
                {
                    if (m2.purpose != VS_EXIT)
                        write(pipen[1], &m3, sizeof(m3));
                }
            }
        }
    }
}