/*
 * Beloch fold validator
 * Fred Pickel
 * Greater Ny Regional
 */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <ctype.h>
#include <math.h>

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;

#define EPS (1.0e-6)
#define DEPS (.01)
#define DMAGEPS (1.0e-10)
#define MAX_N	1000
#define MAX_FACT	(1.0e8)

double px, py, ma, mb, mc, qx, qy, na, nb, nc;
double mx0, my0, nx0, ny0;	// points on m, n

double ka, kb, kc;	// fold line
double kt;	// signed distance along line M from (mx0,my0)
double kx, ky;	// pt on fold line
double scale;


/* Begin additions for validator output */
char *szResultFile, *szJudgeInFile, *szStudentOutFile;

int bSentXML = 0;
char szErr[1024];
#ifdef WIN32
#define	snprintf	_snprintf
#endif
void GenXML(const char *szMsg1, const char *szMsg2)
{
	FILE *fp;

	if(szResultFile != NULL && *szResultFile != '\0'){
		fp = fopen(szResultFile, "wt");
		if(fp != NULL){
			fprintf(fp, "<?xml version=\"1.0\"?>\n");
			fprintf(fp, "<result outcome=\"%s\" security=\"%s\">%s</result>\n", szMsg1, szResultFile, szMsg2 == NULL ? "" : szMsg2);
			bSentXML = 1;
			fclose(fp);
		} else {
			fprintf(stdout, "Can't open result file %s\n", szResultFile);
		}
	} else {
		fprintf(stdout, "No result file: %s - %s\n", szMsg1, szMsg2 == NULL ? "" : szMsg2);
	}
}

int Normalize()
{
	double d;
	d = ma*px + mb*py + mc;
	if(fabs(d) < EPS) {	// P on M
		return -1;
	}
	d = na*qx + nb*qy + nc;
	if(fabs(d) < EPS) {	// Q on N
		return -1;
	}

	d = fabs(px - qx) + fabs(py - qy);
	if(d < EPS) {	// P == Q
		return -4;
	}

	d = ma*ma + mb *mb;	// invalid M
	if(fabs(d) < EPS) {
		return -2;
	}
	d = 1.0/sqrt(d);
	ma *= d; mb *= d; mc *= d;
	d = px*ma + py*mb + mc;
	mx0 = px - d*ma;
	my0 = py - d*mb;

	d = na*na + nb *nb;
	if(fabs(d) < EPS) {	// invalid N
		return -2;
	}
	d = 1.0/sqrt(d);
	na *= d; nb *= d; nc *= d;
	d = qx*na + qy*nb + nc;
	nx0 = qx - d*na;
	ny0 = qy - d*nb;
	
	d = ma*nb - na*mb;
	if(fabs(d) < EPS) {	// M || N
		return -3;
	}
	return 0;
}

// normalize k, compute reflections of P, Q in K and plug into M and N equations
double FoldErr()
{
	double qx1, qy1, dot, kdot, ret;

	kdot = ka*ka + kb*kb;
	dot = (qx)*ka + (qy)*kb + kc;
	qx1 = qx - 2.0*dot*ka/kdot;
	qy1 = qy - 2.0*dot*kb/kdot;
	ret = fabs(na*qx1 + nb*qy1 + nc);

	dot = (px)*ka + (py)*kb + kc;
	qx1 = px - 2.0*dot*ka/kdot;
	qy1 = py - 2.0*dot*kb/kdot;
	ret += fabs(ma*qx1 + mb*qy1 + mc);
	return ret;
}


char inbuf[256];
FILE *judgefp, *studfp, *infile;

int main(int argc, char **argv) 
{
	int nprob, curprob, index, ret, studind;
	double dret;

	if(argc < 5) {
        snprintf(&(szErr[0]), sizeof(szErr)-1,
                "USAGE: %s prob_in_file judge_file stud_file result_file", argv[0]);
        GenXML("Other - Contact Staff", &(szErr[0]));
		return -1;
	}
	szResultFile = argv[4];
	szJudgeInFile = argv[1];
	szStudentOutFile = argv[3];
	if((judgefp = fopen(szJudgeInFile, "r")) == (FILE *)NULL) {
        snprintf(&(szErr[0]), sizeof(szErr)-1,
                "Can not open Judge input file %s", szJudgeInFile);
        GenXML("Other - Contact Staff", &(szErr[0]));
		return -2;
	}
	if((studfp = fopen(szStudentOutFile, "r")) == (FILE *)NULL) {
        snprintf(&(szErr[0]), sizeof(szErr)-1,
                "Can not open student submission output file %s", szStudentOutFile);
        GenXML("Other - Contact Staff", &(szErr[0]));
		return -3;
	}
	if(fgets(&(inbuf[0]), 255, judgefp) == NULL)
	{
		snprintf(&(szErr[0]), sizeof(szErr)-1,
			"Failed to read judge input %s", szJudgeInFile);
		GenXML("Other - Contact Staff", &(szErr[0]));
		return -6;
	}
	if(sscanf(&(inbuf[0]), "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
		&px, &py, &ma, &mb, &mc, &qx, &qy, &na, &nb, &nc) != 10){
		snprintf(&(szErr[0]), sizeof(szErr)-1,
			"Scan of data (%s) from judge input %s failed",
			&(inbuf[0]), szJudgeInFile);
		GenXML("Other - Contact Staff", &(szErr[0]));
		return -7;
	}
	if((ret = Normalize()) != 0) {
		snprintf(&(szErr[0]), sizeof(szErr)-1,
			"Invalid input (err %d) for judge input %s",
			ret, szJudgeInFile);
		GenXML("Other - Contact Staff", &(szErr[0]));
		return -9;
	}
	if(fgets(&(inbuf[0]), 255, studfp) == NULL)
	{
		snprintf(&(szErr[0]), sizeof(szErr)-1, "Read failed on student problem data");
		GenXML("Wrong Answer", &(szErr[0]));
		return -12;
	}
	if(sscanf(&(inbuf[0]), "%lf %lf %lf", &ka, &kb, &kc) != 3) {
		snprintf(&(szErr[0]), sizeof(szErr)-1, "Scan failed on student answer");
		GenXML("Wrong Answer", &(szErr[0]));
		return -13;
	}
	if((dret = FoldErr()) > DEPS) {
		snprintf(&(szErr[0]), sizeof(szErr)-1, "Points too far %0.5lf off lines", dret);
		GenXML("Wrong Answer", &(szErr[0]));
		return -15;
	}
	if(!bSentXML){
		GenXML("Accepted", "");
	}
	return 0;
}
