/*
 * Copyright (c) 1991 Paul J. Drongowski.
 * Copyright (c) 1992 Joe Dellinger.
 * Copyright (c) 2005 Eric S. Raymond.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/*
 * Return-Path: <pjd@cadillac.siemens.com>
 * Received: from cadillac.siemens.com by montebello.soest.hawaii.edu
 * (4.1/montebello-MX-1.9) id AA01487; Mon, 10 Aug 92 03:21:41 HST Received:
 * from kevin.siemens.com by cadillac.siemens.com (4.1/SMI-4.0) id AA25847; Mon,
 * 10 Aug 92 09:21:37 EDT Date: Mon, 10 Aug 92 09:21:37 EDT From:
 * pjd@cadillac.siemens.com (paul j. drongowski) Message-Id:
 * <9208101321.AA25847@cadillac.siemens.com> To: joe@montebello.soest.hawaii.edu
 * Status: RO
 */

/*
 * This copy is slightly hacked by Joe Dellinger, August 1992
 * And some more... November 1992
 *
 * Partially re-written by "murray@vs6.scri.fsu.edu"
 * to use better grammar and to avoid some nonsensical
 * responses (like claiming to be a person who's been licensed
 * longer than they've been alive!), Jan 1994
 *
 * Those improvements merged with others by Joe Dellinger, Oct 1994
 */

/*
 * Generate QSO
 */

/*
 * When run, this program generates a single QSO. The form of the
 * QSO is similar to QSO's one would expect to hear at a code test.
 * It begins with a series of V's (commented out in this version),
 * callsigns of the receiver and
 * sender, followed by a few sentences about weather, name,
 * occupation, etc. The QSO ends with the callsigns of the receiver
 * and sender.
 *
 * All output is produced using "printf." This should make the
 * program easy to port. Output can be piped into another program
 * such as sparc-morse on the Sun or it can be redirected into
 * a file (without viewing the contents of course!)
 *
 * The program design is similar to a "random poetry generator"
 * or "mad-libs." Each QSO form is generated by its own C function,
 * such as "PutForm1." Each function calls other C functions to
 * produce the sentences in the QSO. The sentence forms are
 * selected somewhat randomly as well as any blanks to be filled.
 * Words and phrases are selected from several lists such as
 * "Transceiver," "Antenna," "Job," etc. Sometimes this scheme is
 * clever as in the formation of city names. Sometimes it is
 * stupidly simple-minded and grammatical agreement is lost.
 * By the way, the callsigns are real and were picked from
 * rec.radio.amateur.misc on USENET.
 *
 * The program was constructed in C for Sun workstations,
 * well befor C99.  This explains some archaisms in the code.
 *
 * Known problems and caveats? Hey, it`s software! All Morse
 * training programs handle the procedural signs (e.g., AR, SK)
 * differently. The function "PutQSO" currently prints "+ %"
 * for the AR and SK at the end of the QSO. These may be ignored,
 * mapped into something else, or just plain cause your training
 * program to roll over and play dead. I don`t know. This is a
 * cheap hack.
 *
 * And speaking of cheap... The program will not generate all
 * characters and pro-signs that are found on an "official" code
 * test. This program is for practice only and should be supplemented
 * with lots of random code.
 *
 * Always have fun!
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>

#include "qso.h"

int their_age; /* PERSON'S AGE, SO THEY AREN'T LICENSED MORE
                * THAN THEIR AGE */

extern const char *Transceiver[];
extern const char *Antenna[];
extern const char *UpFeet[];
extern const char *Weather1[];
extern const char *Weather2[];
extern const char *Power[];
extern const char *Job[];
extern const char *Name[];
extern const char *CallSign[];
extern const char *License[];
extern const char *City[];
extern const char *NewCity[];
extern const char *CityHeights[];
extern const char *New[];
extern const char *Heights[];
extern const char *State[];
extern const char *Frqmisc[];
extern const char *Callmisc[];
extern const char *NumMisc[];
extern const char *Miscellaneous[];
extern const char *RST[];

int NXCVR;
int NANTENNA;
int NUPFEET;
int NWX1;
int NWX2;
int NPOWER;
int NJOB;
int NNAME;
int NCALLSIGN;
const char *Sender, *Receiver;
int NLICENSE;
int NCITY;
int NNEWCITY;
int NCITYHTS;
int NNEW;
int NHEIGHTS;
int NSTATE;
int NFRQMISC;
int NFRQCALLMISC;

char const *FrqCallmisc[] = {"QRW %s %d",  "QRZ %s %d",  "QSN %s %d",
                             "QSX %s %d",  "QRW %s %d?", "QRZ %s %d?",
                             "QSN %s %d?", "QSX %s %d?", 0};

int NCALLMISC;
int NNUMMISC;
int NMISC;
int NRST;

/*
 *************************************
 * Routines to put sentences/clauses *
 *************************************
 */

void PutMisc(void) { printf("%s\n", Choose(Miscellaneous, NMISC)); }

void PutThanks(void) {
	switch (Roll(6)) {
	case 2:
		printf("Thanks for your call.\n");
		break;

	case 3:
		printf("Tnx for ur call.\n");
		break;

	case 4:
		printf("Tnx for the call.\n");
		break;

	case 5:
		printf("Thanks for the call.\n");
		break;

	default:
		printf("Thanks %s for the call.\n", Choose(Name, NNAME));
		break;
	}
}

void PutName(void) {
	switch (Roll(6)) {
	case 2:
		printf("Name is %s.\n", Choose(Name, NNAME));
		break;

	case 4:
		printf("This is %s.\n", Choose(Name, NNAME));
		break;

	case 5:
		printf("%s here.\n", Choose(Name, NNAME));
		break;

	default:
		printf("My name is %s.\n", Choose(Name, NNAME));
		break;
	}
}

void PutJob(void) {
	switch (Roll(20)) {
	case 2:
	case 3:
		printf("My occupation is %s.\n", Choose(Job, NJOB));
		break;

	case 4:
	case 5:
		printf("I work as %s.\n", A_Or_An(Choose(Job, NJOB)));
		break;

	case 6:
		printf("I was %s, now unemployed.\n",
		       A_Or_An(Choose(Job, NJOB)));
		break;

	case 11:
	case 12:
		printf("Occupation is %s.\n", Choose(Job, NJOB));
		break;

	default:
		printf("I am %s.\n", A_Or_An(Choose(Job, NJOB)));
		break;
	}
}

void PutAge(void) {

	their_age = Roll(60) + 16;

	switch (Roll(5)) {
	case 3:
		printf("My age is %d.\n", their_age);
		break;

	case 4:
		printf("I am %d years old.\n", their_age);
		break;

	default:
		printf("Age is %d.\n", their_age);
		break;
	}
}

void PutLicense(void) {
	int get_years_licence;

	get_years_licence = Roll(License_Seed());
	if (get_years_licence < 2) {
		get_years_licence = 2;
	}

	switch (Roll(12)) {
	case 1:
		printf("I have %s class licence.\n",
		       A_Or_An(Choose(License, NLICENSE)));
		break;

	case 2:
		printf("I am %s license ham.\n",
		       A_Or_An(Choose(License, NLICENSE)));
		break;

	case 3:
		printf("I am %s licence ham.\n",
		       A_Or_An(Choose(License, NLICENSE)));
		break;

	case 4:
		printf("I have been licenced %d years as %s class.\n",
		       get_years_licence, Choose(License, NLICENSE));
		break;

	case 5:
		printf("I have %s class license.\n",
		       A_Or_An(Choose(License, NLICENSE)));
		break;

	case 6:
		printf("I am %s class ham.\n",
		       A_Or_An(Choose(License, NLICENSE)));
		break;

	case 7:
		printf("I have been licensed %d years as %s class.\n",
		       get_years_licence, Choose(License, NLICENSE));
		break;

	default:
		printf("I have been %s class ham for %d years.\n",
		       A_Or_An(Choose(License, NLICENSE)), get_years_licence);
		break;
	}
}

void PutTemperature(void) { printf("Temperature is %d.\n", Roll(80) + 10); }

void PutWeather1(void) {
	switch (Roll(17)) {
	case 2:
		printf("WX is %s.\n", Choose(Weather1, NWX1));
		PutTemperature();
		break;

	case 3:
		printf("Weather here is %s.\n", Choose(Weather1, NWX1));
		break;

	case 4:
		printf("Weather is %s.\n", Choose(Weather1, NWX1));
		break;

	case 5:
		printf("WX is %s.\n", Choose(Weather1, NWX1));
		break;

	case 6:
		PutTemperature();
		printf("Weather here is %s.\n", Choose(Weather1, NWX1));
		break;

	case 7:
		PutTemperature();
		printf("Weather is %s.\n", Choose(Weather1, NWX1));
		break;

	case 8:
		PutTemperature();
		printf("WX is %s.\n", Choose(Weather1, NWX1));
		break;

	case 9:
		printf("Weather here is %s and temperature is %d.\n",
		       Choose(Weather1, NWX1), Roll(80) + 10);
		break;

	case 10:
		printf("Weather is %s, temperature %d.\n",
		       Choose(Weather1, NWX1), Roll(80) + 10);
		break;

	case 11:
		printf("WX is %d degrees and %s.\n", Roll(80) + 10,
		       Choose(Weather1, NWX1));
		break;

	case 12:
		printf("The WX is %s and the temp is %d degrees.\n",
		       Choose(Weather1, NWX1), Roll(80) + 10);
		break;

	case 14:
		printf("Weather is %s.\n", Choose(Weather1, NWX1));
		PutTemperature();
		break;

	case 15:
		printf("Weather here is %s.\n", Choose(Weather1, NWX1));
		PutTemperature();
		break;

	default:
		printf("WX is %s and %d degrees.\n", Choose(Weather1, NWX1),
		       Roll(80) + 10);
	}
}

void PutWeather2(void) {

	switch (Roll(10)) {
	case 0:
		printf("It is %s.\n", Choose(Weather2, NWX2));
		break;

	case 1:
		printf("It is %s and %d degrees.\n", Choose(Weather2, NWX2),
		       Roll(80) + 10);
		break;

	case 2:
		printf("The WX is %s and the temp is %d degrees.\n",
		       Choose(Weather2, NWX2), Roll(80) + 10);
		break;

	case 3:
		printf("WX is %s and the temp is %d degrees.\n",
		       Choose(Weather2, NWX2), Roll(80) + 10);
		break;

	case 4:
		printf("It is %s today.\n", Choose(Weather2, NWX2));
		break;

	case 5:
		printf("It is %s and %d degrees.\n", Choose(Weather2, NWX2),
		       Roll(100) + 3);
		break;

	case 6:
		printf("The WX is %s and the temp is %d degrees.\n",
		       Choose(Weather2, NWX2), Roll(90) + 10);
		break;

	case 7:
		printf("WX is %s and the temp is %d degrees.\n",
		       Choose(Weather2, NWX2), Roll(80) + 10);
		break;

	default:
		printf("It is %s here.\n", Choose(Weather2, NWX2));
		break;
	}
}

void PutWeather(void) {
	switch (Roll(4)) {
	case 3:
		PutWeather1();
		break;

	default:
		PutWeather2();
		break;
	}
}

void PutCityState(void) {
	switch (Roll(6)) {
	case 4:
		printf("%s %s, ", Choose(CityHeights, NCITYHTS),
		       Choose(Heights, NHEIGHTS));
		break;

	case 5:
		printf("%s %s, ", Choose(New, NNEW), Choose(NewCity, NNEWCITY));
		break;

	default:
		printf("%s, ", Choose(City, NCITY));
		break;
	}
	printf("%s.\n", Choose(State, NSTATE));
}

void PutLocation(void) {

	switch (Roll(5)) {
	case 3:
		printf("My QTH is ");
		break;

	case 4:
		printf("My location is ");
		break;

	default:
		printf("QTH is ");
		break;
	}
	PutCityState();
}

void PutRig(void)

{
	switch (Roll(19)) {
	case 0:
	case 1:
		printf("My rig runs %s watts into %s up %s feet.\n",
		       Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;

	case 2:
	case 3:
		printf("Rig is a %s watt %s and antenna is %s.\n",
		       Choose(Power, NPOWER), Choose(Transceiver, NXCVR),
		       A_Or_An(Choose(Antenna, NANTENNA)));
		break;

	case 4:
	case 5:
		printf("My transceiver is %s.\n",
		       A_Or_An(Choose(Transceiver, NXCVR)));
		printf("It runs %s watts into %s.\n", Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)));
		break;

	case 6:
	case 7:
		printf("The rig is %s running %s watts.\n",
		       A_Or_An(Choose(Transceiver, NXCVR)),
		       Choose(Power, NPOWER));
		printf("Antenna is %s up %s m.\n",
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;

	case 8:
	case 9:
	case 10:
	case 11:
		printf("My rig runs %s watts into %s up %s meters.\n",
		       Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;

	case 12:
		printf("My rig runs %s watts into %s up %s feet, but\nthe "
		       "antenna has partly fallen.\n",
		       Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;

	case 13:
		printf("Rig is %s running %s watts into %s up %s ft.\n",
		       A_Or_An(Choose(Transceiver, NXCVR)),
		       Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;

	case 14:
		printf("My rig runs %s watts into %s up %s feet.\n",
		       Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;

	case 15:
		printf("Rig is %s watt %s and antenna is %s.\n",
		       A_Or_An(Choose(Power, NPOWER)),
		       Choose(Transceiver, NXCVR), Choose(Antenna, NANTENNA));
		break;

	case 16:
		printf("My transceiver is %s.\n",
		       A_Or_An(Choose(Transceiver, NXCVR)));
		printf("It runs %s watts into %s.\n", Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)));
		break;

	case 17:
		printf("The rig is %s running %s watts.\n",
		       A_Or_An(Choose(Transceiver, NXCVR)),
		       Choose(Power, NPOWER));
		printf("Antenna is %s up %s feet.\n",
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;

	default:
		printf("Rig is %s ", A_Or_An(Choose(Transceiver, NXCVR)));
		printf("running %s watts into %s up %s feet.\n",
		       Choose(Power, NPOWER),
		       A_Or_An(Choose(Antenna, NANTENNA)),
		       Choose(UpFeet, NUPFEET));
		break;
	}
}

void PutRST(void) {
	register const char *TheRST;

	TheRST = Choose(RST, NRST);

	switch (Roll(8)) {
	case 0:
		printf("UR RST %s=%s.\n", TheRST, TheRST);
		break;

	case 1:
		printf("RST is %s=%s.\n", TheRST, TheRST);
		break;

	case 2:
		printf("RST %s=%s.\n", TheRST, TheRST);
		break;

	case 3:
		printf("Your RST %s=%s.\n", TheRST, TheRST);
		break;

	case 4:
		printf("Your RST is %s=%s.\n", TheRST, TheRST);
		break;

	case 5:
		printf("Your signal is RST %s/%s.\n", TheRST, TheRST);
		break;

	case 6:
		printf("UR signal is RST %s,%s.\n", TheRST, TheRST);
		break;

	default:
		printf("Your RST is %s/%s.\n", TheRST, TheRST);
		break;
	}
}

void PutQ_And_Freq(void) {
	switch (Roll(8)) {
	case 2:
		printf(Frqmisc[Roll(NFRQMISC)], make_freq());
		printf("\n");
		break;

	case 3:
		printf(Callmisc[Roll(NFRQMISC)], Choose(CallSign, NCALLSIGN));
		printf("\n");
		break;

	case 4:
		printf(FrqCallmisc[Roll(NFRQCALLMISC)],
		       Choose(CallSign, NCALLSIGN), make_freq());
		printf("\n");
		break;

	case 5:
		printf(NumMisc[Roll(NNUMMISC)], Roll(3) + Roll(2) + 1);
		printf("\n");
		break;

	default:
		break;
	}
}

void PutFirstCallsign(void) {
	Sender = Choose(CallSign, NCALLSIGN);
	Receiver = Choose(CallSign, NCALLSIGN);
	printf("%s de %s\n", Receiver, Sender);
}

void PutLastCallsign(void) { printf("%s de %s\n", Receiver, Sender); }

int main(int argc, char **argv) {

	NXCVR = CountStrings(Transceiver);
	NANTENNA = CountStrings(Antenna);
	NUPFEET = CountStrings(UpFeet);
	NPOWER = CountStrings(Power);
	NRST = CountStrings(RST);
	NWX1 = CountStrings(Weather1);
	NWX2 = CountStrings(Weather2);
	NJOB = CountStrings(Job);
	NNAME = CountStrings(Name);
	NSTATE = CountStrings(State);
	NCITY = CountStrings(City);
	NCITYHTS = CountStrings(CityHeights);
	NNEW = CountStrings(New);
	NHEIGHTS = CountStrings(Heights);
	NNEWCITY = CountStrings(NewCity);
	NLICENSE = CountStrings(License);
	NMISC = CountStrings(Miscellaneous);
	NCALLSIGN = CountStrings(CallSign);
	NFRQMISC = CountStrings(Frqmisc);
	NFRQCALLMISC = CountStrings(FrqCallmisc);
	NCALLMISC = CountStrings(Callmisc);
	NNUMMISC = CountStrings(NumMisc);

	srand((long)time(0));

	PutQSO();

	return 0;
}
