/****************************************************************************
                   Microsoft RPC Version 2.0
           Copyright Microsoft Corp. 1992, 1993, 1994
                        Doctor Example

    FILE:       Doctorp.c

    PURPOSE:    Procedures that can be linked with the client side
                to form a standalone application, or linked with
                the server side to form a distributed RPC application

    DATA:       Pattern   - array of strings; input patterns and responses
                Substring - substrings within user input

    FUNCTIONS:  Analyze(*pszInOut) - top level function
                Match(*string, *pattern) - compare input to patterns
                Respond(*string, *response) - replace substrings in response
                Synonyms(*ps1, *ps2) - replace synonyms in user input

****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "doctor.h"     // header file generated by MIDL compiler

#define TRUE  1
#define FALSE 0


char *Pattern[] =
    {
    "0COMPUTER 1",
    "0COMPUTERS 1",
    "=DO 11S WORRY YOU?",    // string 11 = "computer" or "machine" 
    "=WHY DO YOU MENTION 11S?",
    "=WHAT DO YOU THINK 11S HAVE TO DO WITH YOUR PROBLEM?",
    "=WHAT DO YOU THINK ABOUT 11S?",

    "0RPC0",
    "=WHY DO YOU MENTION RPC?",
    "=DO YOU MENTION RPC BECAUSE YOU ARE FEELING REMOTE RIGHT NOW?",
    "=WHAT FEELINGS DO YOU HAVE ABOUT RPC?",

    "0SORRY0",
    "=PLEASE DON'T APOLOGIZE.",
    "=APOLOGIES ARE NOT NECESSARY.",
    "=WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE?",
    "=I'VE TOLD YOU THAT APOLOGIES ARE NOT REQUIRED.",
    "=APOLOGIES ARE NOT NECESSARY, PLEASE GO ON",

    "0I AM SAD1",
    "=I AM SORRY TO HEAR YOU ARE 14.",    // string 14 = "sad", "sick", etc.
    "=DO YOU THINK COMING HERE WILL HELP YOU NOT TO BE 14?",
    "=I'M SURE IT'S NOT PLEASANT TO BE 14.",
    "=CAN YOU EXPLAIN WHAT MADE YOU 14?",

    "0I AM HAPPY1",
    "=HOW HAVE I HELPED YOU TO BE 15?",    // string 15 = "happy", etc.
    "=HAS YOUR TREATMENT MADE YOU 15?",
    "=WHAT MAKES YOU 15 JUST NOW?",
    "=CAN YOU EXPLAIN WHY YOU ARE SUDDENLY 15?",

    "0NAME0",
    "=I AM NOT INTERESTED IN NAMES.",
    "=I'VE TOLD YOU BEFORE I DON'T CARE ABOUT NAMES.  PLEASE CONTINUE.",

    "0 FAMILY1",
    "=TELL ME MORE ABOUT YOUR 12.",    // string 12 = "mother", "brother", etc.
    "=WHO ELSE IN YOUR FAMILY?",
    "=YOUR 12?",
    "=WHAT ELSE COMES TO MIND WHEN YOU THINK OF YOUR 12?",

    "0I REMEMBER 1",
    "=DO YOU OFTEN THINK OF 1?",
    "=WHAT IN THE PRESENT SITUATION REMINDS YOU OF 1?",

    "0SAME0",
    "0ALIKE0",
    "0IS 0LIKE0",
    "=IN WHAT WAY?",
    "=WHAT RESEMBLANCE DO YOU SEE?",
    "=WHAT DOES THAT SIMILARITY SUGGEST TO YOU?",
    "=WHAT OTHER CONNECTIONS DO YOU SEE?",
    "=WHAT DO YOU SUPPOSE THAT RESEMBLANCE MEANS?",
    "=WHAT IS THE CONNECTION, DO YOU SUPPOSE?",
    "=COULD THERE REALLY BE SOME CONNECTION?",
    "=HOW?",

    "0I REMEMBER 1",
    "=DO YOU OFTEN THINK OF 1?",
    "=DOES THINKING OF 1 BRING ANYTHING ELSE TO MIND?",
    "=WHAT ELSE DO YOU REMEMBER?",
    "=WHY DO YOU REMEMBER 1 JUST NOW?",
    "=WHAT IN THE PRESENT SITUATION REMINDS YOU OF 1?",
    "=WHAT IS THE CONNECTION BETWEEN ME AND 1?",

    "0DO YOU REMEMBER 1",
    "=DID YOU THINK I WOULD FORGET 1?",
    "=WHY DO YOU THINK I SHOULD RECALL 1 NOW?",
    "=WHAT ABOUT 1?",
    "=YOU MENTIONED 1?",

    "1 IS MY PROBLEM0",
    "=1 13 YOUR PROBLEM?",    // string 13 = "is" or "are" 
    "=ARE YOU SURE 13 1 YOUR PROBLEM?",
    "=PERHAPS 13 1 NOT YOUR REAL PROBLEM.",
    "=YOU THINK YOU HAVE PROBLEMS?",
    "=DO YOU OFTEN THINK ABOUT 1?",

    "0PROBLEM0",
    "=PLEASE CONTINUE, THIS MAY BE INTERESTING.",
    "=HAVE YOU ANY OTHER PROBLEMS YOU WISH TO DISCUSS?",
    "=PERHAPS YOU'D RATHER CHANGE THE SUBJECT.",
    "=YOU SEEM A BIT UNEASY.",

    "0I DREAMT 1",
    "0I DREAMED 1",
    "=REALLY 1?",
    "=HAVE YOU EVER FANTASIZED 1 WHILE YOU WERE AWAKE?",
    "=HAVE YOU DREAMT 1 BEFORE?",
    "=WHAT DOES THAT DREAM SUGGEST TO YOU?",
    "=DO YOU DREAM OFTEN?",
    "=WHAT PERSONS APPEAR IN YOUR DREAMS?",
    "=DON'T YOU BELIEVE THAT DREAM HAS SOMETHING TO DO WITH YOUR PROBLEM?",
    "=DO YOU EVER WISH YOU COULD FLEE FROM REALITY?",

    "0DREAM0",
    "=WHAT DOES THAT DREAM SUGGEST TO YOU?",
    "=DO YOU DREAM OFTEN?",
    "=WHAT PERSONS APPEAR IN YOUR DREAMS?",
    "=DON'T YOU BELIEVE THAT DREAM HAS SOMETHING TO DO WITH YOUR PROBLEM?",
    "=DO YOU EVER WISH YOU COULD FLEE FROM REALITY?",

    "0IF 1 HAD 2",
    "=DO YOU THINK IT'S LIKELY THAT 1 MIGHT HAVE 2?",
    "=DO YOU WISH THAT 1 HAD 2?",
    "=REALLY, IF 1 HAD 2?",

    "0IF 1",
    "=DO YOU THINK IT'S LIKELY THAT 1?",
    "=DO YOU WISH THAT 1?",
    "=WHAT DO YOU THINK ABOUT 1?",
    "=REALLY, IF 1?",

    "WAS I 1",
    "=WHAT IF YOU WERE 1?",
    "=DO YOU THINK YOU WERE 1?",
    "=WERE YOU 1?",
    "=WHAT WOULD IT MEAN IF YOU WERE 1?",
    "=WHAT DOES \"1\" SUGGEST TO YOU?",
    "=WHY DO YOU ASK?",
    "=DOES THAT QUESTION INTERST YOU?",
    "=WHAT IS IT YOU REALLY WANT TO KNOW?",
    "=ARE SUCH QUESTIONS MUCH ON YOUR MIND?",
    "=WHAT ANSWER WOULD PLEASE YOU MOST?",
    "=WHAT DO YOU THINK?",
    "=WHAT COMES TO YOUR MIND WHEN YOU ASK THAT?",
    "=HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
    "=HAVE YOU ASKED ANYONE ELSE?",

    "0I WAS 1",
    "=WERE YOU REALLY?",
    "=WHY DO YOU TELL ME YOU WERE 1 NOW?",
    "=PERHAPS I ALREADY KNEW YOU WERE 1.",

    "WERE YOU 1",
    "=WOULD YOU LIKE TO BELIEVE THAT I WAS 1?",
    "=WHAT SUGGESTS THAT I WAS 1?",
    "=WHAT DO YOU THINK?",
    "=PERHAPS I WAS 1.",
    "=WHAT IF I HAD BEEN 1.",

    "0 MY 1",
    "MY 1",
    "=YOUR 1?",
    "=WHY DO YOU SAY YOUR 1?",
    "=DOES THAT SUGGEST ANYTHING ELSE WHICH BELONGS TO YOU?",
    "=IS IT IMPORTANT TO YOU THAT 1?",

    "0EVERYONE0",
    "0EVERYBODY0",
    "=REALLY, EVERYONE?",
    "=SURELY NOT EVERYONE.",
    "=CAN YOU THINK OF ANYONE IN PARTICULAR?",
    "=WHO, FOR EXAMPLE?",
    "=YOU ARE THINKING OF A VERY SPECIAL PERSON.",
    "=WHO, MAY I ASK?",
    "=SOMEONE SPECIAL, PERHAPS.",
    "=YOU HAVE A PARTICULAR PERSON IN MIND, DON'T YOU?",
    "=WHO DO YOU THINK YOU'RE TALKING ABOUT?",
    "=I SUSPECT YOU'RE EXAGGERATING A LITTLE.",

    "NO ONE0",
    "0 NO ONE0",
    "0NOBODY0",
    "=REALLY, NO ONE?",
    "=SURELY SOMEONE.",
    "=CAN YOU THINK OF ANYONE IN PARTICULAR?",
    "=WHO, FOR EXAMPLE?",
    "=YOU ARE THINKING OF A VERY SPECIAL PERSON.",
    "=WHO, MAY I ASK?",
    "=SOMEONE SPECIAL, PERHAPS.",
    "=YOU HAVE A PARTICULAR PERSON IN MIND, DON'T YOU?",
    "=WHO DO YOU THINK YOU'RE TALKING ABOUT?",
    "=I SUSPECT YOU'RE EXAGGERATING A LITTLE.",

    "0ALWAYS0",
    "=CAN YOU THINK OF A SPECIFIC EXAMPLE?",
    "=WHEN?",
    "=WHAT INCIDENT ARE YOU THINKING OF?",
    "=REALLY, ALWAYS?",
    "=WHAT IF THIS NEVER HAPPENED?",

    "0HOW 0",
    "0WHERE 0",
    "=WHY DO YOU ASK?",
    "=DOES THAT QUESTION INTERST YOU?",
    "=WHAT IS IT YOU REALLY WANT TO KNOW?",
    "=ARE SUCH QUESTIONS MUCH ON YOUR MIND?",
    "=WHAT ANWSER WOULD PLEASE YOU MOST?",
    "=WHAT DO YOU THINK?",
    "=WHAT COMES TO YOUR MIND WHEN YOU ASK THAT?",
    "=HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
    "=HAVE YOU ASKED ANYONE ELSE?",

    /* "there is no" strings must precede "there is" strings */
    "0THERE IS NO 1",
    "0THERE IS NOT 1",
    "=WHAT IF THERE WERE 1",
    "=DID YOU THINK THERE MIGHT BE 1",
    "=HOW 13 1 RELATED TO YOU?",
    /* these must follow "there is no" strings */
    "0THERE IS 1",
    "=13 THERE REALLY 1?", 
    "=HOW 13 1 RELATED TO YOU?",

    "0SEX 1",
    "=DO YOU REALLY WANT TO DISCUSS SEX?",
    "=DO YOU EVER DREAM ABOUT SEX?",
    "=WHY DO YOU MENTION SEX?",
    "=COULD SEX BE PART OF YOUR PROBLEM?",

    "0HECK1",    // checks for strong language
    "0DARN1",
    "=ARE SUCH OBSCENITIES FREQUENTLY ON YOUR MIND?",
    "=YOU ARE BEING A BIT CHILDISH.",
    "=REALLY NOW",
    "=DEAR ME",
    "=I REALLY SHOULDN'T TOLERATE SUCH LANGUAGE.",

    "0MY FRIEND 1",
    "=WHAT ELSE CAN YOU TELL ME ABOUT YOUR FRIEND?",
    "=WHAT MIGHT YOUR FRIEND HAVE TO DO WITH THE PROBLEM?",

    "0",    // last resort: match anything
    "=PLEASE GO ON.",
    "=I AM NOT SURE I UNDERSTAND YOU FULLY.",
    "=WHAT DOES THAT SUGGEST TO YOU?",
    "=DO YOU FEEL STRONGLY ABOUT DISCUSSING SUCH THINGS?",
    NULL    // special end of list character
};


int iLastIndex = 0;     // don't send same response twice in a row
                        // note: this requires 2 responses for each pattern

char Substring[20][STRSIZE] = {
  "", "", "", "", "", "", "", "", "", "",
  "REMEMBER",  /* 10 */
  "COMPUTER",  /* 11 */
  "FAMILY",    /* 12 */
  "IS",        /* 13 */
  "", "", "", "", "", ""        };


/* Compare user input to patterns */

int Match (char *str, char *pat)
{
    char * pStr;             // backup ptr to the user input string
    char * pPat;             // backup ptr to the pattern
    char *pSubstr = NULL;    // possible substrings within pattern
    int index = 0;           // index to substring

    while (TRUE) {  // exit routine from within this loop

        if (isdigit(*pat)) {  // replaceable pattern number
            index = atoi(pat);       // extract pattern number
            while (isdigit(*pat))    // skip number in pattern
                pat++;

            pSubstr = Substring[index]; // pointer to current substring

            if (*pat == '\0') {  // if end of pattern, everything will match
                strcpy(pSubstr, str);   // copy rest of input into substring
                return(TRUE);
            }

            else 
                while (*pat != *str) {  // match all to specific char in pattern
                    *pSubstr++ = *str++; // fill substring
                    if (*str == '\0')    // stuff left to match, but no input
                        return(FALSE);
                    *pSubstr = '\0';     // can overwrite if there's more...
                }

            pStr = str;  // keep track; it may still be *
            pPat = pat;  // keep track; it may still be *
        }  

        if (*str == *pat) {  // matches the specific pattern
            str++;  // skip to next character of input string
            pat++;  // skip to next character of pattern
            if ((*str == '\0') && (*pat == '\0'))  // both at end?
                return(TRUE);
        }  

        else if (pSubstr != NULL) {  // didn't match specific, so still * substring
            pat = pPat;              // restore ptr to input pattern
            while (pStr < str)       // catch up to current input character
                *pSubstr++ = *pStr++;
            while (*pat != *str) {   // match to next possible match in pattern
                *pSubstr++ = *str++; // fill substring with more characters
                if (*str == '\0')    // stuff left to match, but no input
                    return(FALSE);
            }
            *pSubstr = '\0';         // can overwrite if there's more...
            pStr = str;              // keep track; it may still be *
            pPat = pat;              // keep track; it may still be *
        }  

        else
            return(FALSE);           // no match

    }  // end while (TRUE) loop

}  // end function Match


/* Add possible substrings to the response string */

void Respond(char *str, char *finalstr)
{
    char copy[STRSIZE];  // copy of the substring to process token at a time
    char *token;
    char *word;
    int index;           // index to substring (string converted to number)
    int len = 0;         // index to output string for sprintf

    while (*str) {

        if (! isdigit(*str)) 
            len += sprintf(finalstr + len, "%c", *str++);

        else {  // check for pattern number

            index = atoi(str);     // extract pattern number
            while (isdigit(*str))  // skip number in pattern
                str++;

            strcpy(copy, Substring[index]);  // process substring
            token = strtok(copy, " ");       // skip blanks

            while (token) {
                word = token;

                if (! strcmp(token,"I") || ! strcmp(token,"ME")) 
                    word = "YOU";
                else if (! strcmp(token,"YOU")) 
                    word = "I";
                else if (! strcmp(token,"MY")) 
                    word = "YOUR";
                else if (! strcmp(token,"YOUR")) 
                    word = "MY";
                else if (! strcmp(token,"MINE")) 
                    word = "YOURS";
                else if (! strcmp(token,"YOURS")) 
                    word = "MINE";
                else if (! strcmp(token,"MYSELF")) 
                    word = "YOURSELF";
                else if (! strcmp(token,"YOURSELF")) 
                    word = "MYSELF";
                else if (! strcmp(token,"I'M")) 
                    word = "YOU'RE";
                else if (! strcmp(token,"YOU'RE")) 
                    word = "I'M";
                else if (! strcmp(token,"AM")) 
                    word = "ARE";
                else if (! strcmp(token,"WAS")) 
                    word = "WERE";

                len += sprintf(finalstr + len, "%s", word);

                // get next token from Substring
                if ((token = strtok(NULL, " ")) != NULL) 
                    len += sprintf(finalstr + len, " ");

            }  // end while token

        }  // end else (if isdigit)

    }  // end while str

    len += sprintf(finalstr + len, "\n");

}  // end function Respond


/* Replace synonyms in user input */

void Synonyms(char *input, char *output)
{
    char *ps1 = input;
    char *ps2 = output;
    char *token;
    char *word;

    static char *synonym10[] = {"RECALL", "RECOLLECT", ""};
    static char *synonym11[] = {"MACHINE", ""};
    static char *synonym12[] = {"MOTHER", "MOMMY", "FATHER", "DADDY", 
                                "SISTER", "BROTHER", "AUNT", "UNCLE", ""}; 
    static char *synonym13[] = {"ARE", "AM", ""};
    static char *synonym14[] = {"SAD", "UNHAPPY", "DEPRESSED", "SICK", ""};
    static char *synonym15[] = {"HAPPY", "ELATED", "GLAD", "BETTER", ""};

    short StrMember();

    // preprocessing...convert to uppercase and check for special chars

    while (*ps1) {
        *ps1 = toupper(*ps1);
        if (*ps1 == '.' || *ps1 == ',' || *ps1 == '!' ||
            *ps1 == '?' || *ps1 == ';' || *ps1 == ':' ||
            ! isprint(*ps1)) {
            *ps1 = '\0';
            break;
        }
        ps1++;
    } 

    // ok, it's preprocessed now...let's check for pattern matches

    ps1 = input;               // back to the beginning...
    strcpy(ps2, "");
    token = strtok(ps1, " ");  // search for tokens deliminated by space

    while (token) {

        word = token;

        if (StrMember(token, synonym10)) {
            word = "REMEMBER";  // use this synonym for pattern-matching
        }
        else if (StrMember(token, synonym11)) {
            strcpy(Substring[11], token);  // 11 is hardcoded into response
            word = "COMPUTER";  
        }
        else if (StrMember(token, synonym12)) {
            strcpy(Substring[12], token);  // 12
            word = "FAMILY";
        }
        else if (StrMember(token, synonym13)) {
            strcpy(Substring[13], token);  // 13
            word = "IS";
        }
        else if (StrMember(token, synonym14)) {
            strcpy(Substring[14], token);  // 14
            word = "SAD";
        }
        else if (StrMember(token, synonym15)) {
            strcpy(Substring[15], token);  // 15
            word = "HAPPY";
        }

        strcat(ps2, word);          // append the token to the output string
        strcat(ps2, " ");           // restore space
        token = strtok(NULL, " ");  // search for the next token

    }  // end while token

}  // end function Synonyms


short StrMember(char *str, char **list)
{
    while (strcmp(*list, "")) {    // not end of the list
        if (!strcmp(str, *list))
            return 1;
        else
            list++;
    }

    return 0;
} 


/* Top-level routine */

void Analyze(unsigned char *str)
{
    int i = 0;      // index to entry within Pattern
    int j;          // index to first possible response string
    int index;      // index of the actual response string used
    int count = 0;  // count of all possible response strings (must be > 2)
    char *response;
    char synstr[STRSIZE];

    Synonyms(str, synstr);

    while (Pattern[i] != NULL) {  // check against all patterns

        if (Pattern[i][0] != '=') {  // if a patient pattern

            if (Match(synstr, Pattern[i]) == TRUE) {

                // skip past patient input to doctor responses
                while (Pattern[i] && Pattern[i][0] != '=')
                    i++;      

                // count the number of possible responses, and
                // point index to beginning of doctor responses
                if (Pattern[i] && Pattern[i][0] == '=') {
                    count = 1; 
                    j = i++;  
                }

                // count all possible doctor responses
                while (Pattern[i] && Pattern[i][0] == '=') {
                    count++;  
                    i++;
                }

                // pick a different doctor response from last time
                do { 
                    index = j + (rand() % count);
                } while (index == iLastIndex);

                // process the doctor respose, and
                // keep track of the response used last
                response = &Pattern[index][1];
                iLastIndex = index;     
                Respond(response, str); 
                return;

            }  // end if match

        }  // end if patient pattern

        i++;  // next pattern

    }  // end while pattern

}  // end function Analyze


/* Shutdown the server by calling RPC API functions */

void Shutdown(void)
{
    RPC_STATUS status;

    printf("Calling RpcMgmtStopServerListening\n");
    status = RpcMgmtStopServerListening(NULL);
    printf("RpcMgmtStopServerListening returned: 0x%x\n", status);
    if (status) {
        exit(status);
    }

    printf("Calling RpcServerUnregisterIf\n");
    status = RpcServerUnregisterIf(NULL, NULL, FALSE);
    printf("RpcServerUnregisterIf returned 0x%x\n", status);
    if (status) {
        exit(status);
    }
}

/* end file doctorp.c */
