content: /*
   * Created on Aug 20, 2005
   *
   * TODO To change the template for this generated file go to
   * Window - Preferences - Java - Code Style - Code Templates
   */
  package stage4;
  
  import java.io.IOException;
  import java.io.RandomAccessFile;
  
  import stage3.*;
  import stage3.InfoSet.*;
  import _misc.Constants;
  import stage4.DoConvertSolsForRndAccess.*;
  
  /**
   * @author Adam
   *
   * TODO To change the template for this generated type comment go to
   * Window - Preferences - Java - Code Style - Code Templates
   */
  public class WeightResolver {
  	
  	public static final String ROOT_INPUT_DIR = Constants.DATA_FILE_REPOSITORY + 
  			"stage3" + Constants.dirSep;
  	
  	private static final int MAX_SIMULT_FILES_OPEN = 1;
  	
  	private static CompareInfoStrings cmpInfoStrings = 
  			new DoConvertSolsForRndAccess.CompareInfoStrings();
  	
  	private static WeightResolver instance = null;
  	public static WeightResolver getWeightResolver() throws IOException {
  		if(instance == null) {
  			instance = new WeightResolver();
  		}
  		return instance;
  	}
  	
  	private String subtreeDir = "";
  	
  	public void setSubtreeName(String subtreeName) {
  		subtreeDir = subtreeName + Constants.dirSep;
  	}
  	
  	public float getWeight(InfoString x, boolean isP1) throws IOException {
  		int shortName;
  		try {
  			shortName = getShortName(x, isP1); // level of indirection
  		} catch (RuntimeException rte) {
  			// note: this happens when we are asked for a move that is illegal
  			//  such as raise after there have already been three raises in this
  			//  betting round.
  			// you might want to disable this if/when debugging.
  			return 0;
  		}
  		if(shortName < 0) {
  			throw new RuntimeException();
  		}
  		return getWeightOfShortName(shortName, isP1);
  	}
  	
  	public static void main(String[] args) throws IOException {
  		WeightResolver yo = getWeightResolver();
  		
  //		InfoString isTst = new InfoString(new byte[] {
  //				-79, 48, 41, 42, 43, 44, 53, -48, 72, 73, 82, -14, 104, 105, 106, 99});
  //		yo.setSubtreeName("g");
  //		System.out.println(yo.getShortName(isTst, true));
  //		System.out.println(yo.getWeight(isTst, true));
  		
  
  		InfoString isTst2 = new InfoString(new byte[] {
  				-111, 0});
  		yo.setSubtreeName("root");
  		System.out.println(yo.getShortName(isTst2, true));
  		System.out.println(yo.getWeightOfShortName(22552, true));
  		System.out.println(yo.getWeight(isTst2, true));
  	}
  	
  	private float getWeightOfShortName(int x, boolean isP1) throws IOException {
  		String player = (isP1 ? "p1" : "p2");
  		
  		// first, look up short name in name map
  		String inName = ROOT_INPUT_DIR + subtreeDir + "game." + player + ".sol.bin";
  		RandomAccessFile in = new RandomAccessFile(inName, "r");
  		if(in.readShort() != Constants.vidSolutionList) {
  			throw new RuntimeException();
  		}
  		short tmp = in.readShort();
  		int listSize = in.readShort();
  		listSize <<= 16;
  		listSize |= tmp & 0xFFFF;
  		
  		// binary search
  		int ixLow = 0;
  		int ixHigh = listSize - 1;
  		final int bytesPerRecord = 8;
  		while(true) {
  			if(ixLow > ixHigh) {
  				throw new RuntimeException("not in file -- if LP solver doesn't write out " +
  						"zero answers then you should return 0 here");
  			}
  			
  			// seek to halfway between ixLow and ixHigh
  			int ixMiddle = ixLow + Math.round((float)(ixHigh - ixLow) / 2);
  			int seekAddr = Constants.FILE_HEADER_LENGTH_BYTES + bytesPerRecord * ixMiddle;
  			in.seek(seekAddr);
  			
  			// determine if we're too high, too low, or right on
  			int record = in.readInt();
  			if(x == record) {
  				// a match!
  				return in.readFloat();
  			} else if(x < record) {
  				ixHigh = ixMiddle - 1;
  			} else {
  				ixLow = ixMiddle + 1;
  			}
  		}
  	}
  	
  	private int getShortName(InfoString x, boolean isP1) throws IOException {
  		String player = (isP1 ? "p1" : "p2");
  		
  		// first, look up short name in name map
  		String inName = ROOT_INPUT_DIR + subtreeDir + "nameMap." + player + ".bin";
  		RandomAccessFile in = new RandomAccessFile(inName, "r");
  		if(in.readShort() != Constants.vidNameList) {
  			throw new RuntimeException();
  		}
  		short tmp = in.readShort();
  		int listSize = in.readShort();
  		listSize <<= 16;
  		listSize |= tmp & 0xFFFF;
  		int maxLongNameLength = in.readShort();
  		
  		// binary search
  		int ixLow = 0;
  		int ixHigh = listSize - 1;
  		final int bytesPerRecord = maxLongNameLength + 4;
  		while(true) {
  			if(ixLow > ixHigh) {
  				throw new RuntimeException("not in file");
  			}
  			
  			// seek to halfway between ixLow and ixHigh
  			int ixMiddle = ixLow + Math.round((float)(ixHigh - ixLow) / 2);
  			int seekAddr = Constants.FILE_HEADER_LENGTH_BYTES + bytesPerRecord * ixMiddle;
  			in.seek(seekAddr);
  			
  			// determine if we're too high, too low, or right on
  			byte[] record = null;
  			for(int i = maxLongNameLength - 1; i >= 0 ; i--) {
  				byte byt = in.readByte();
  				if(record == null) {
  					if(byt != InfoToken.reservedToken) {
  						record = new byte[i+1];
  						record[i] = byt;
  					}
  				} else {
  					// big endian
  					record[i] = byt;
  				}
  			}
  			if(record == null) {
  				throw new RuntimeException();
  			}
  			InfoString iSRecord = new InfoString(record);
  			int cmp = cmpInfoStrings.compare(x, iSRecord);
  			if(cmp == 0) {
  				// a match!
  				return in.readInt();
  			} else if(cmp < 0) {
  				ixHigh = ixMiddle - 1;
  			} else {
  				ixLow = ixMiddle + 1;
  			}
  		}
  	}	
  }
  