/* The class contains a 'execProduct' method that accepts two input tables as arguements 
 * and returns the corresponding 'normal product', 'since product' or 'until product'
 * of the two tables based on the type of product selected (indicated by an integer flag
 * submitted to the method as an argument).
 */

class  Product
{
	public static Table execProduct(Table A, Table B, int type)
	{
		Table R = new Table(); /* the resulting table */

		/* variables to hold the corresponding start and end time 
		 * values from the rows in each table.
		 */
		int st_A=99;
		int et_A=99;
		int st_B=99;
		int et_B=99;
		int st_R=99;
		int et_R=99;
		boolean perform = true;

		/* variables to hold the min and max time known to the
		 * temporal database system
		 */
		int min_time = UserInterface.getMinTime();
		int max_time = UserInterface.getMaxTime();
		
		/* Merge the column information of the two tables */
		mergeColData(R, A.getCol(), B.getCol());

		for (int i=0; i<A.getNoRowSet(); i++) /* go through each row in table A */
		{
			perform = true;

			/* fetch a row from table A */
			Row row_Ai = (Row) A.getRow(i);

			/* fetch the time values associated with the row Ai */
			st_A=row_Ai.getRow_st();
			et_A=row_Ai.getRow_et();

			switch (type)
			{
			case 1: /* Since */
				if (st_A==max_time && et_A==max_time)
					perform=false;
				break;

			case 2: /* Until */
				if (st_A==min_time && et_A==min_time)
					perform=false;
				break;

			default:
				perform=true;
				break;
			}
			
			if (perform)
			{

				for (int j=0; j<B.getNoRowSet(); j++) /* go through each row in table B */
				{
					perform=true;

					/* fetch a row from table B */
					Row row_Bj = (Row) B.getRow(j);

					/* fetch the time values associated with the row Bj */
					st_B=row_Bj.getRow_st();
					et_B=row_Bj.getRow_et();

					/* check if the two rows overlap by comparing their time values */
					if(AuxFuncs.overlap(st_A, et_A, st_B, et_B))
					{
						switch (type)
						{
						case 0: /* calculate the new time values for performing: A Times (Product) B */
							st_R=StrictMath.max(st_A, st_B);
							et_R=StrictMath.min(et_A, et_B);
							break;

						case 1: /* calculate the new time values for performing: A Since B */
							if (st_B==max_time && et_B==max_time)
								perform=false;
							else
							{
								st_R=StrictMath.max(st_A, st_B)+1;
								et_R=et_A+1;

								if (st_R>max_time)
									st_R=max_time;
								if (et_R>max_time)
									et_R=max_time;
							}
							break;

						case 2: /* calculate the new time values for performing: A Until B */
							if (st_B==min_time && et_B==min_time)
								perform=false;
							else
							{
								st_R=st_A-1;
								et_R=StrictMath.min(et_A, et_B)-1;

								if (st_R<min_time)
									st_R=min_time;
								if (et_R<min_time)
									et_R=min_time;
							}

							break;

						default:
							System.out.println("Error: Unknown \"type\" in class \"Product\" ");
							break;
						}

						if (perform)
						{
							Object[] rowVals_R = new Object[R.getNoCols()];
							int markpos = A.getNoCols(); /* the number of objects in a row from table A */

							/* merge the two rows by copying all objects from row Ai followed by copying 
							 * all objects from row Bj and preserving the object ordering.
							 */
							System.arraycopy(row_Ai.getRowValues(), 0, rowVals_R, 0, A.getNoCols());
							System.arraycopy(row_Bj.getRowValues(), 0, rowVals_R, markpos, B.getNoCols());

							/* place the merging of the two rows from table A and B to the output table R */
							R.putRow(rowVals_R, st_R, et_R);
						}

					} /* end of if statement */

				} /* end of the inner for loop relating to table B */

			} /* end of IF 'PERFORM' */

		} /* end of the outter for loop relating to table A */

		boolean coalFlag=UserInterface.getCoal();
		if ( (type==1 || type==2) && coalFlag )
		{
			AuxFuncs.coalesce(R);
		}


		return R;
	}

	/* Merges two sets of column infromation by concatanating one column
	 * information to the end of the other column information. The merge 
	 * result of columns is placed in the table supplied.
	 */
	public static void mergeColData(Table R, Column c1, Column c2)
	{
		int colNumber_R = c1.getColNumber() + c2.getColNumber();
		String[] colNames_R = new String[colNumber_R];
		int[] colTypes_R = new int[colNumber_R];
		int markpos = c1.getColNumber();

		/* join the column names */
		System.arraycopy(c1.colNames, 0, colNames_R, 0, c1.colNumber);
		System.arraycopy(c2.colNames, 0, colNames_R, markpos, c2.colNumber);

		/* join the column types */
		System.arraycopy(c1.colTypes, 0, colTypes_R, 0, c1.colNumber);
		System.arraycopy(c2.colTypes, 0, colTypes_R, markpos, c2.colNumber);

		/* place the joining results to output table R */
		R.putCol(colNumber_R, colNames_R, colTypes_R);
	}
}
