package Cluedo.g1;

public class CardDistribution implements Cloneable {
	protected double[][] _hits;
	protected boolean[] _finalized;
	protected double[] _totals;
	protected double[] _averages;
	protected double[] _deviations;

    public CardDistribution( int n, int p ) {
		_hits = new double[p][n];
		_finalized = new boolean[p];
		_totals = new double[p];
		_averages = new double[p];
		_deviations = new double[p];
	}

	protected CardDistribution( double[][] hits, boolean[] finalized, 
		double[] totals, double[] averages, double[] deviations ) {
		_hits = new double[hits.length][hits[0].length];
		_finalized = new boolean[finalized.length];
		_totals = new double[totals.length];
		_averages = new double[averages.length];
		_deviations = new double[deviations.length];

		for( int i = 0; i < _hits.length; i++ ) {
			System.arraycopy( hits[i], 0, _hits[i], 0, hits[i].length );
		}
		
		System.arraycopy( finalized, 0, _finalized, 0, finalized.length );
		System.arraycopy( totals, 0, _totals, 0, totals.length );
		System.arraycopy( averages, 0, _averages, 0, averages.length );
		System.arraycopy( deviations, 0, _deviations, 0, deviations.length );
	}

	public Object clone() {
		return( new CardDistribution( _hits, _finalized, _totals, _averages, _deviations ) );
	}

	public void hit( int row, int[] cols, double increment ) {
		for( int i = 0; i < cols.length; i++ ) {
			_hits[row][cols[i]] += increment;
			_totals[row] += increment;
		}

		_finalized[row] = false;
	}

	public boolean any_non_zero_cols( int row ) {
		for( int i = 0; i < _hits[row].length; i++ ) {
			if( _hits[row][i] > 0 ) {
				return( true );
			}
		}

		return( false );
	}

	public void hit_all_cols( int row, double increment ) {
		for( int i = 0; i < _hits[row].length; i++ ) {
			_hits[row][i] += increment;
		}

		_finalized[row] = false;
	}

	public void zero_out( int row, int col ) {
		_totals[row] -= _hits[row][col];
		_hits[row][col] = 0;
		_finalized[row] = false;
	}

	public void zero_out_cols( int row, int[] cols ) {
		for( int i = 0; i < cols.length; i++ ) {
			zero_out( row, cols[i] );
		}
	}

	public int max_col( int row ) {
		int col = -1;
		double col_count = -1;

		for( int i = 0; i < _hits[row].length; i++ ) {
			if( _hits[row][i] > col_count ) {
				col = i;
				col_count = _hits[row][i];
			}
		}

		return( col );
	}

	public double count( int row, int col ) {
		return( _hits[row][col] );
	}

	public double total( int row ) {
		return( _totals[row] );
	}

	public double average( int row ) {
		if( !_finalized[row] ) {
			finalize( row );
		}

		return( _averages[row] );
	}

	public double standard_deviation( int row ) {
		if( !_finalized[row] ) {
			finalize( row );
		}

		return( _deviations[row] );
	}

	protected void finalize( int row ) {
		int non_zero_rows = 0;

		for( int i = 0; i < _hits[row].length; i++ ) {
			if( _hits[row][i] != 0.0 ) {
				non_zero_rows++;
			}
		}
		
		_averages[row] = _totals[row] / non_zero_rows;
		_deviations[row] = 0.0;

		for( int i = 0; i < _hits[row].length; i++ ) {
			if( _hits[row][i] != 0.0 ) {
				_deviations[row] += Math.pow( _hits[row][i] - _averages[row], 2 );
			}
		}

		_deviations[row] /= non_zero_rows;
		_finalized[row] = true;
	}
}
