import java.io.*;
import java.util.*;

public class LimitedCShift {
	public HashMap<String, Double> limshift = new HashMap<String, Double>(); 

    //    private static String   
	
	public LimitedCShift() {		
	    // loadLimitedCShift (); // changed because of '-dir' option
	}

	public void loadLimitedCShift () {		
                // System.out.println("SHIFTX2_DIR: "+ShiftXp.SHIFTX2_DIR);

		String filename = ShiftXp.SHIFTX2_DIR + "/lib/limitedcshift.dat";
		String objFilename = ShiftXp.SHIFTX2_DIR + "/lib/limitedcshift.osf";
		
		File f = new File(objFilename);
		if (f.exists()) {
			System.out.println("Loading limited cshifts ....");
			readHashObjectFile(objFilename); 
		} else {
			f = new File(filename);
			if(!f.exists()){
				System.err.println("Missing [limitedcshift.dat] file");
				System.exit(-1);
			}

			try{
				System.out.println("Making limited cshifts objectStream file....");
				
				BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filename))));
				String line;
				String[] fields;
				
				while(br.ready()){
					line = br.readLine();
					fields = line.split(",");
					// iupac, atomname, randomCoil
					limshift.put((fields[0].trim() +':'+ fields[1].trim()+":U"), Double.parseDouble(fields[2].trim()));
					limshift.put((fields[0].trim() +':'+ fields[1].trim()+":L"), Double.parseDouble(fields[3].trim()));
				}
				br.close();
				
				// save object into object file format for speed up
				saveObjectFile(objFilename, limshift);

			} catch(IOException ex){
				ex.printStackTrace();
			}
		}

	}	

	public static void main(String[] args) {
	     LimitedCShift lcs = new LimitedCShift();
	     lcs.loadLimitedCShift();

	     System.out.println("######: " + lcs.getUpperLimit("A:CA")); 
	     System.out.println("######: " + lcs.checkLimitedCShiftBound("A","CA",73.567)); 
	}
	
	public void saveObjectFile(String fname, Object obj) {
		try	{
			FileOutputStream fos = new FileOutputStream( fname );
			ObjectOutputStream oos = new ObjectOutputStream( fos );
			oos.writeObject(obj);
			oos.close();		
		} catch (Exception e) {
			// If something unexpected happened, print exception information and quit 
			e.printStackTrace();
			System.exit(1);
		}
	}
	
	@SuppressWarnings({"unchecked"})
	public void readHashObjectFile(String fname) {		
		try	{
			// Deserialization - ObjectOutputStream
			ObjectInputStream ohs = new ObjectInputStream(new BufferedInputStream(new FileInputStream(fname)));			 
			limshift = (HashMap<String, Double>) ohs.readObject();
			ohs.close();
		} catch (Exception e) {
			// If something unexpected happened, print exception information and quit 
			e.printStackTrace();
			System.exit(1);
		}
	}	

        // key : iupac:atomname
	public double getUpperLimit(String key) {
		return limshift.get(key+":U");
	}

	public double getLowerLimit(String key) {
		return limshift.get(key+":L");
	}

        public double checkLimitedCShiftBound(String iupac, String atomname, double shift) {

		if ( atomname.equals("HA") )    {
    			if (shift < 2.0)  return (2.0);
        		if (shift > 6.3)  return (6.3);
		}

		if ( atomname.equals("CA") )    {
	  		if (shift < 41.0) return(41.0);  
	    		if (shift > 72.0) return(72.0);
	    	}

		if ( atomname.equals("C") )   	{
			if (shift < 165.0)  return(165.0);
    			if (shift > 185.0)  return(185.0);
    		}

    		if ( atomname.equals("N") )     { 
          		if (shift < 95.0)   return(95.0);
	        	if (shift > 135.0)  return(135.0);
		}

		if ( atomname.equals("H") )      {
      			if (shift < 4.0)  return(4.0);
            		if (shift > 12.0) return(12.0);
	    	}

		// The other cases : use shift limitation hash map
		Double ulim = limshift.get(iupac+':'+atomname+":U");
		Double llim = limshift.get(iupac+':'+atomname+":L");
		
		/*
                if ( ulim == null ) 
		     System.out.println("ulim is null: " + iupac + ":" + atomname);   
                if ( llim == null ) 
		     System.out.println("llim is null: " + iupac + ":" + atomname);   
		*/

		if (ulim != null && shift > ulim)  return(ulim);
		if (llim != null && shift < llim)  return(llim);

		return shift;
	}
		
}
