/*******************************************************************************
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 * 
 * Contact Info:
 * 	Bruce Donald
 * 	Duke University
 * 	Department of Computer Science
 * 	Levine Science Research Center (LSRC)
 * 	Durham
 * 	NC 27708-0129 
 * 	USA
 * 	brd@cs.duke.edu
 * 
 * Copyright (C) 2011 Jeffrey W. Martin and Bruce R. Donald
 * 
 * <signature of Bruce Donald>, April 2011
 * Bruce Donald, Professor of Computer Science
 ******************************************************************************/


package edu.duke.donaldLab.jdshot.search;

import java.io.Serializable;
import java.util.List;
import java.util.TreeMap;

import edu.duke.donaldLab.share.nmr.DistanceRestraint;
import edu.duke.donaldLab.share.protein.AtomAddressInternal;

public class Consistency implements Serializable
{
	/**************************
	 *   Definitions
	 **************************/
	
	private static final long serialVersionUID = 7349194528332988764L;
	// NOTE: using basic arrays here because ArrayList<Integer> is immutable! =(
	private int[] m_cells;
	private boolean[][] m_restraints;
	

	/**************************
	 *   Constructors
	 **************************/
	
	public Consistency( int numCells, List<DistanceRestraint<AtomAddressInternal>> restraints )
	{
		// init restraint consistency to all inconsistent
		m_restraints = new boolean[restraints.size()][];
		for( int i=0; i<restraints.size(); i++ )
		{
			DistanceRestraint<AtomAddressInternal> restraint = restraints.get( i );
			int numAssignments = restraint.getNumAssignments();
			
			m_restraints[i] = new boolean[numAssignments];
			for( int j=0; j<numAssignments; j++ )
			{
				m_restraints[i][j] = false;
			}
		}
		
		resizeCells( numCells );
	}
	
	
	/**************************
	 *   Accessors
	 **************************/
	
	public int[] getCells( )
	{
		return m_cells;
	}
	
	public boolean[][] getRestraints( )
	{
		return m_restraints;
	}
	
	
	/**************************
	 *   Methods
	 **************************/
	
	public void resizeCells( int numCells )
	{
		// init cell consistency to all consistent
		m_cells = new int[numCells];
		for( int i=0; i<numCells; i++ )
		{
			m_cells[i] = 0;
		}
	}
	
	public void reset( )
	{
		// init restraint consistency to all inconsistent
		for( int i=0; i<m_restraints.length; i++ )
		{
			for( int j=0; j<m_restraints[i].length; j++ )
			{
				m_restraints[i][j] = false;
			}
		}
		
		// init cell consistency to all consistent
		for( int i=0; i<m_cells.length; i++ )
		{
			m_cells[i] = 0;
		}
	}
	
	public void markRestraintConsistent( int i, int j )
	{
		m_restraints[i][j] = true;
	}
	
	public void markCellInconsistent( int i )
	{
		m_cells[i]++;
	}
	
	public int getNumInconsistentRestraints( )
	{
		int numInconsistentRestraints = 0;
		
		for( int i=0; i<m_restraints.length; i++ )
		{
			boolean isRestraintConsistent = false;
			
			for( int j=0; j<m_restraints[i].length; j++ )
			{
				if( m_restraints[i][j] )
				{
					isRestraintConsistent = true;
					break;
				}
			}
			
			if( !isRestraintConsistent )
			{
				numInconsistentRestraints++;
				
				// TEMP: show us the restraint
				//System.out.println( "inconsistent restraintIndex = " + i );
			}
		}
		
		return numInconsistentRestraints;
	}
	
	public void update( Consistency consistency, int startIndex )
	{
		// update cells
		for( int i=0; i<consistency.m_cells.length; i++ )
		{
			m_cells[startIndex + i] = consistency.getCells()[i];
		}
		
		// update restraints
		for( int i=0; i<consistency.m_restraints.length; i++ )
		{
			boolean[] assignments = consistency.m_restraints[i];
			for( int j=0; j<assignments.length; j++ )
			{
				m_restraints[i][j] = m_restraints[i][j] || assignments[j];
			}
		}
	}
	
	public void printStats( )
	{
		// find out the counts of cells in each different consistency
		TreeMap<Integer,Integer> cellStats = new TreeMap<Integer,Integer>();
		for( Integer count : m_cells )
		{
			Integer numCells = 0;
			if( cellStats.containsKey( count ) )
			{
				numCells = cellStats.get( count );
			}
			cellStats.put( count, numCells + 1 );
		}
		
		// print out the results
		for( Integer count : cellStats.keySet() )
		{
			System.out.println( "cells with " + count + " inconsistencies: " + cellStats.get( count ) );
		}
		
		// print the individual restraint consistency
		for( int i=0; i<m_restraints.length; i++ )
		{
			System.out.println( "restraint " + i );
			
			// for each assignment...
			for( int j=0; j<m_restraints[i].length; j++ )
			{
				System.out.println( "\tassignment " + j + " : " + ( m_restraints[i][j] ? "consistent" : "INCONSISTENT" ) );
			}
		}
	}
}
