#include <windows.h> 
#include <stdio.h>
#include <string.h>
#include "math.h"

#define BUFSIZE 1024 
 
void pa (double e[4], double* t, double* t2);
void p3 (double x, double y, double *z, double* t, double* t2);

VOID main(VOID) 
{ 
	/* Buffer de armazenamento de dados a serem enviados via pipe */
	char chBuf[BUFSIZE]; 
	/* Tempo total de processamento */
	long totalTime;
	/* Número de bytes escritos no pipe */
	DWORD dwWritten; 
	/* Handle do pipe */
	HANDLE hStdout, hStdin; 
	/* Estruturas de tempo deste processo */
	FILETIME ftCreation,
		ftExit,
        ftKernel,
        ftUser;
	/* Estrutura com o tempo de execução deste processo a nível do kernel */
	SYSTEMTIME stKernel;
	/* Estrutura com o tempo de execução deste processo a nível do usuário */
	SYSTEMTIME stUser;
	/* Handle do processo corrente */
	HANDLE hProcess = GetCurrentProcess();

	/* Variáveis do benchmark */
	long iterations = 10000;
    double		x1, x2, x3, x4, x, y, z, t, t1, t2;
    double 		e1[4];
    long		ii, j, k, l, n1, n2, n3, n4, n6, n7, n8, n9, n10, n11;

	for(int i = 0; i < 1; i++) {

		/* inicializa constantes */ 
		t = 0.499975;
		t1 = 0.50025;
		t2 = 2.0;

		/* seta os pesos dos módulos */ 
		n1 = 0 * iterations;
		n2 = 12 * iterations;
		n3 = 14 * iterations;
		n4 = 345 * iterations;
		n6 = 210 * iterations;
		n7 = 32 * iterations;
		n8 = 899 * iterations;
		n9 = 616 * iterations;
		n10 = 0 * iterations;
		n11 = 93 * iterations;

		/* MODULo 1:  simple identifiers */ 
		x1 = 1.0;
		x2 = -1.0;
		x3 = -1.0;
		x4 = -1.0;
		ii = 1;
		while (ii < (n1 + 1))
		{
			x1 = (x1 + x2 + x3 - x4) * t;
			x2 = (x1 + x2 - x3 - x4) * t;
			x3 = (x1 - x2 + x3 + x4) * t;
			x4 = (-x1 + x2 + x3 + x4) * t;
			++ii;
		}

		/* MODULo 2:  elementos de array */ 
		e1[0] = 1.0;
		e1[1] = -1.0;
		e1[2] = -1.0;
		e1[3] = -1.0;
		ii = 1;
		while (ii < (n2 + 1))
		{
			e1[0] = (e1[0] + e1[1] + e1[2] - e1[3]) * t;
			e1[1] = (e1[0] + e1[1] - e1[2] + e1[3]) * t;
			e1[2] = (e1[0] - e1[1] + e1[2] + e1[3]) * t;
			e1[3] = (-e1[0] + e1[1] + e1[2] + e1[3]) * t;
			++ii;
		}

		/* MODUL0 3:  arrays como parâmetros */ 
		ii = 1;
		while (ii < (n3 + 1))
		{
			pa (e1, &t, &t2);
			++ii;
		}

		/* MODULO 4:  jumps condicionais */ 
		j = 1;
		ii = 1;
		while (ii < (n4 + 1))
		{
			if (j == 1)
				j = 2;
			else
				j = 3;
			if (j > 2)
				j = 0;
			else
				j = 1;
			if (j < 1)
				j = 1;
			else
				j = 0;
			++ii;
		}

		/* MODULO 6:  arithmética com inteiros */ 
		j = 1;
		k = 2;
		l = 3;
		ii = 1;
		while (ii < (n6 + 1))
		{
			j = j * (k - j) * (l - k);
			k = l * k - (l - j) * k;
			l = (l - k) * (k + j);
			e1[l - 2] = j + k + l;
			e1[k - 2] = j * k * l;
			++ii;
		}

		/* MODULO 7:  funções trigonométricas */ 
		x = y = 0.5;
		ii = 1;
		while (ii < (n7 + 1))
		{
			x =
				t * atan (t2 * sin (x) * cos (x) / (cos (x + y) + cos (x - y) - 1.0));
			y =
				t * atan (t2 * sin (y) * cos (y) / (cos (x + y) + cos (x - y) - 1.0));
			++ii; 
		}

		/* MODULO 8:  chamadas a procedimentos */ 
		x = y = z = 1.0;
		ii = 1;
		while (ii < (n8 + 1))
		{
			p3 (x, y, &z, &t, &t2);
			++ii;
		}

		/* MODULO 9:  referência a arrays */ 
		j = 1;
		k = 2;
		l = 3;
		e1[0] = 1.0;
		e1[1] = 2.0;
		e1[2] = 3.0;
		ii = 1;
		while (ii < (n9 + 1))
		{
			e1[j] = e1[k];
			e1[k] = e1[l];
			e1[l] = e1[j];
			++ii;
		}

		/* MODULO 10:  aritmética com inteiros */ 
		j = 2;
		k = 3;
		ii = 1;
		while (ii < (n10 + 1))
		{
			j = j + k;
			k = j + k;
			j = k - j;
			k = k - j - j;
			++ii;
		}

		/* MODULO 11:  funções padrão */ 
		x = 0.75;
		ii = 1;
		while (ii < (n11 + 1))
		{
			x = sqrt (exp (log (x) / t1));
			++ii;
		}    
	}

	/* Obtém o tempo de execução deste processo */
	GetProcessTimes(hProcess, &ftCreation, &ftExit, &ftKernel, &ftUser);

	/* Transforma o tempo para estruturas com tempo compatíveis ao do sistema */
	FileTimeToSystemTime(&ftKernel, &stKernel);
	FileTimeToSystemTime(&ftUser, &stUser);

	/* Calcula o tempo de execução em milisegundos */
	totalTime = ((stKernel.wSecond+stUser.wSecond) * 1000) +
		(stKernel.wMilliseconds+stUser.wMilliseconds);
	
	/* Envia o resultado para o processo pai através do pipe */
	hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
	hStdin = GetStdHandle(STD_INPUT_HANDLE); 
	if (hStdout == INVALID_HANDLE_VALUE)  
		ExitProcess(1); 

	itoa(totalTime, chBuf, 10);
	WriteFile(hStdout, chBuf, strlen(chBuf)*sizeof(char), &dwWritten, NULL); 
}

void pa (double e[4], double* t, double* t2) 
{
  register int j;
  j = 0;
lab:e[0] = (e[0] + e[1] + e[2] - e[3]) * *t;
  e[1] = (e[0] + e[1] - e[2] + e[3]) * *t;
  e[2] = (e[0] - e[1] + e[2] + e[3]) * *t;
  e[3] = (-e[0] + e[1] + e[2] + e[3]) / *t2;
  j += 1;
  if (j < 6)
    goto lab;
}

void p3 (double x, double y, double *z, double* t, double* t2) 
{
  x = *t * (x + y);
  y = *t * (x + y);
  *z = (x + y) / *t2;
}