/*
 * Practica 1.
 *
 * Practicas Metodologia de la Programacion.
 * Curso 2008 - 2009
 *
 * Vicente Lujan Mansilla
 * Lorena Margareto Bisquert
 */

#include <stdlib.h>
#include <iostream>
#include <assert.h>
#include <vector>
#include "Complejo.h"

using namespace std;

/**
 * Vector de complejos
 * Tipo de datos usado para calcular el producto escalar.
 */
typedef vector<Complejo> vectorC;

void definirVector (vectorC &v, int tam)
{
	/**
	 * Contador de los bucles.
	 */
	int i;

	/**
	 * Datos que forman el numero complejo en su forma polar.
	 */
	float modulo, argumento;

	/**
	 * Complejo que forma el vector.
	 */
	Complejo numeroC;


	for (i=0; i<tam; i++)
	{		
		cout << "Introduce el complejo " << i+1 << " del vector de " << tam << " elementos.\n";
		cout << "Modulo: ";
		cin >> modulo;
		cout << "Argumento: ";
		cin >> argumento;

		numeroC.set(modulo, argumento); //Asigna nuevos valores al modulo y el argumento del complejo
		v.push_back(numeroC); //Insertar el complejo en el vector
	}
}

/**
 * Calcula el producto escalar de dos vectores de complejos.
 *
 * @param v1 Primer vector de complejos.
 * @param v2 Segundo vector de complejos.
 * @param tam Tamanyo de ambos vectores de complejos.
 * @return Complejo Resultado del producto escalar de los dos vectores 
 * de complejos.
 */
Complejo productoEscalar (vectorC v1, vectorC v2, int tam)
{
	/**
	 * Contador del bucle.
	 */
	int i;

	/**
	 * Complejo que almacena la suma del producto escalar de ambos vectores.
	 */
	Complejo res;


	for (i=0; i<tam; i++) 
			res = res + (v1[i] * v2[i]); 

	return res;
}

/**
 * Calcula el producto escalar de dos vectores de complejos mediante 
 * una funcion lineal no final.
 *
 * @param v1 Primer vector de complejos.
 * @param v2 Segundo vector de complejos.
 * @param tam Tamanyo de ambos vectores de complejos.
 * @return Complejo Resultado del producto escalar de los dos vectores 
 * de complejos.
 */
Complejo funcionLinealNoFinal (vectorC v1, vectorC v2, int tam)
{
	/**
	 * Contador del bucle.
	 */
	int i = tam; //Pre

	/**
	 * Complejo que almacena la suma del producto escalar de ambos vectores.
	 */
	Complejo p;
	
	//Garantiza que la funcion de cota es natural	
	assert (tam >= 0); 
	
	if (i == 0)
	  p.setRec(0, 0); //Asigna 0 al modulo y argumento del complejo

	else
	{
	  p = funcionLinealNoFinal (v1, v2, i-1); 
	  p = p + (v1[i] * v2[i]); 
	}
	
	assert (p == productoEscalar (v1, v2, i)); //Post
	
	return p;
}

/**
 * Calcula el producto escalar de dos vectores de complejos mediante una 
 * funcion recursiva final.
 *
 * @param v1 Primer vector de complejos.
 * @param v2 Segundo vector de complejos.
 * @param tam Tamanyo de ambos vectores de complejos.
 * @param w Complejo que pasa el resultado parcial a la siguiente 
 * llamada de la funcion.
 * @return Complejo Resultado del producto escalar de los dos vectores 
 * de complejos.
 */
Complejo funcionRecursivaFinal (vectorC v1, vectorC v2, int tam, Complejo w)
{
	/**
	 * Contador del bucle.
	 */
	int i = tam; //Pre

	/**
	 * Complejo que almacena la suma del producto escalar de ambos vectores.
	 */
	Complejo p;
	
	//Garantiza que la funcion de cota es natural
	assert (tam >= 0); 	
	
	if (i == 0)
		p = w;
	else
		p = funcionRecursivaFinal (v1, v2, i-1, (v1[i] * v2[i]) + w); 
	
	assert (p == productoEscalar (v1, v2, i) + w); //Post
	
	return p;
}

/**
 * Calcula el producto escalar de dos vectores de complejos mediante una 
 * funcion recursiva final
 * con postcondicion constante.
 *
 * @param v1 Primer vector de complejos.
 * @param v2 Segundo vector de complejos.
 * @param tam Tamanyo de ambos vectores de complejos.
 * @param w Complejo que pasa el resultado parcial a la siguiente 
 * llamada de la funcion.
 * @param aux Tamaņo auxiliar que se pasa para comprobar la funcion.
 * @return Complejo Resultado del producto escalar de los dos vectores de 
 * complejos.
 */
Complejo funcionRecursivaFinalPC (vectorC v1, vectorC v2, int tam, Complejo w, int aux)
{
	/**
	 * Contador del bucle.
	 */
	int i = tam; //Pre

	/**
	 * Complejo que almacena la suma del producto escalar de ambos vectores.
	 */
	Complejo p;
	
	//Garantiza que la funcion de cota es natural
	assert (tam >= 0); 	
	
	if (i == 0)
		p = w;
	else
		p = funcionRecursivaFinalPC (v1, v2, i-1, (v1[i] * v2[i]) + w, aux);


	assert (p == productoEscalar (v1, v2, aux) ); //Post

	return p;
}

/**
 * Calcula el producto escalar de dos vectores de complejos mediante 
 * una funcion iterativa.
 *
 * @param v1 Primer vector de complejos.
 * @param v2 Segundo vector de complejos.
 * @param tam Tamanyo de ambos vectores de complejos.
 * @return Complejo Resultado del producto escalar de los dos vectores 
 * de complejos.
 */
Complejo funcionIterativa (vectorC v1, vectorC v2, int tam)
{
	/**
	 * Contador del bucle.
	 */
	int i = tam; //Pre
	/**
	 * Complejo que pasa el resultado parcial a la 
	 * siguiente llamada de la funcion.
	 */
	Complejo w;

	w.setRec(0, 0);

	/**
	 * Complejo que almacena la suma del producto escalar de ambos vectores.
	 */
	Complejo p;

	//Garantiza que la funcion de cota es natural
	assert (tam >= 0); 
	
    	//Invariante de la iteracion
	assert (productoEscalar (v1, v2, tam) + w == productoEscalar (v1, v2, tam));
	
	while (i >= 0)
	{
		w = w + (v1[i] * v2[i]);
		i--;
	}

	p = w;

	assert (p == productoEscalar (v1, v2, tam)); //Post

	return p;
}


int main()
{	
	/**
	 * Almacena la opcion elegida por el usuario en el menu del programa.
	 */
	int opcion;

	/**
	 * Tamaņo de los vectores de complejos.
	 */
	int tam;

	/**
	 * Dos vectores que almacenan numeros complejos.
	 */
	vectorC v1, v2;
	
	/**
	 * Almacenan resultados o se usan como parametros auxiliares.
	 */	
	Complejo w, res;
	
	/**
	 * Se utiliza como parametro auxiliar.
	 */
	int aux;

	system("clear");
	cout << "-----------------------------------------------------------\n";
	cout << "-                CALCULO DEL PRODUCTO ESCALAR             -\n";
	cout << "-             DE DOS VECTORES DE NUMEROS COMPLEJOS        -\n";
	cout << "-----------------------------------------------------------\n";
	cout << "- Indica el numero de elementos que quieres introducir: ";
	cin >> tam;
	
	aux = tam;
	
	system("sleep 1");
	system("clear");
	cout << "---------------------------------------------\n";
	cout << "-         Primer vector de complejos        -\n";
	cout << "---------------------------------------------\n";
	definirVector(v1, tam);

    	system("sleep 1"); 
	system("clear");
	cout << "----------------------------------------------\n";
	cout << "-         Segundo vector de complejos        -\n";
	cout << "----------------------------------------------\n";
	definirVector(v2, tam);
    	system("sleep 1"); 

	do
	{
		system("clear");
		cout << "-----------------------------------------------------\n";
		cout << "-            CALCULO DEL PRODUCTO ESCALAR            \n";
		cout << "-         DE DOS VECTORES DE NUMEROS COMPLEJOS       \n";
		cout << "-----------------------------------------------------\n";
		cout << "- Elige un metodo para calcular el producto escalar:-\n";
		cout << "- 1. Recursiva lineal no final                      -\n";
		cout << "- 2. Recursiva final                                -\n";
		cout << "- 3. Recursiva final con postcondicion constante    -\n";
		cout << "- 4. Funcion iterativa                              -\n";
		cout << "- 5. Salir del programa                             -\n";
		cout << "---------------------------------------------------- \n";
		cout << "- Introduce una opcion: ";
	   
		cin >> opcion;

        	cout << endl << endl;

		switch (opcion)
		{
			case 1:
				res = funcionLinealNoFinal(v1, v2, tam);
				break;
			case 2:
				res = funcionRecursivaFinal(v1, v2, tam, w);
				break;
			case 3:
				res = funcionRecursivaFinalPC(v1, v2, tam, w, aux);
				break;
			case 4:
				res = funcionIterativa(v1, v2, tam);
				break;
			case 5:
				break;
			default:
				cout << "ERROR: Escoje una opcion correcta.\n";
		}
		if (opcion != 5)
		{
			cout << " El resultado del producto escalar de ambos vectores es ";
			res.print();
			cout << endl;
			/*Para la ejecucion del programa hasta que el usuario pulsa una tecla.*/
			getchar();
			getchar();

		}
	}
	while(opcion != 5);
	
	return 0;

}






		





