/**
 * 
 */
package edu.uprm.walsaip.vte.core.loader.terrain;

//import static java.lang.System.err;
import static java.lang.System.out;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import edu.uprm.walsaip.vte.core.datatypes.terrain.ElevationData;
import edu.uprm.walsaip.vte.core.datatypes.terrain.VTEInfo;
import edu.uprm.walsaip.vte.core.loader.FileLoaderInfo;
import edu.uprm.walsaip.vte.core.util.FileUtils;
import edu.uprm.walsaip.vte.core.util.file.FileReaderUtil;



/**
 * 
 * @author Ricardo Veguilla (veguilla@ece.uprm.edu)
 * 
 */
public class BTFileLoader implements TerrainFileLoader {
	protected static  String extensionList[] = { "bt" };
	
	public static final String ID = BTFileLoader.class.getSimpleName();	
	public static final String Type = TerrainFileLoader.ID;

	public static final FileLoaderInfo<BTFileLoader> MODULE_INFO = new FileLoaderInfo<BTFileLoader>() {
		
		protected void setInfo() {
			name = BTFileLoader.ID;
			description = "Binary terrain file";
			moduleClass = BTFileLoader.class;
			extensionList = BTFileLoader.extensionList;
			supported = true;
		}
	};
	
	
	public BTFileLoader() {
		super();
	}
	

	
	public void read(ElevationData data,VTEInfo info,File file) {
		//Display.NewMsg("Reading terrain file...");
		out.printf("Reading terrain file...");
		
		int width =0;
		int height = 0;
		
		FileReaderUtil fileReader = null;
		try {
			fileReader = FileUtils.getFileReaderUtil(file);
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		

		
		boolean dataIsFloat = false;
		boolean dataIsInt = false;
		boolean dataIsShort = false;
		short bytesPerPoint = 0;
		
	
		try {

			
			fileReader.position(0);
	
			byte version[] = new byte[10];
			for (int i = 0; i < 10; i++)
				version[0] = fileReader.readByte();
			
			
			
			
			width = fileReader.readInt(10);
			height =  fileReader.readInt(14);
			bytesPerPoint = fileReader.readShort(18);
			dataIsFloat = (fileReader.readShort(20) == 1);
			dataIsInt = (!dataIsFloat && bytesPerPoint == 4);
			dataIsShort = (!dataIsFloat && bytesPerPoint == 2);
	
			short horizontalUnits = fileReader.readShort(22);
			float scaleAdjustment = 0;
			switch (horizontalUnits) {
			case 0: scaleAdjustment = 111200 ; break;
			case 1: scaleAdjustment = 1; break;
			case 2: scaleAdjustment = 0.3048f;  break;
			case 3: scaleAdjustment =  1200/3937;  break;
			}
			
			
			
			short utmZone = fileReader.readShort(24);
			short datum = fileReader.readShort(26);
			double leftExtend = fileReader.readDouble(28);
			double rightExtend = fileReader.readDouble(36);
			float gridSpacingX = (float) (rightExtend-leftExtend)/width;
			
			double bottomExtend = fileReader.readDouble(44);
			double topExtend = fileReader.readDouble(52);
			
			float gridSpacingY = (float)(topExtend - bottomExtend)/height;
			
			boolean projectionRequired = (fileReader.readShort(60) != 0);
		
			float scale = fileReader.readFloat(62);
			if (scale == 0.0)
				scale = 1.0f;
	
			fileReader.position(256);
			
			if (true) {
			out.println("BT Version: "+new String(version));
			out.println("Dimensions: "+width +" "+ height);
			out.println("Bytes per point: "+bytesPerPoint);
					
			if (dataIsFloat)
				out.println("Data type: float");
			else if (dataIsInt)
				out.println("Data type: int");
			else
				out.println("Data type: short");

			switch (horizontalUnits) {
			case 0: out.println ("Horizontal units: Degrees"); break;
			case 1: out.println ("Horizontal units: Meters"); break;
			case 2: out.println ("Horizontal units: Feet (International, 0.3048 meters)"); break;
			case 3: out.println ("Horizontal units: Feet (U.S. Survey, 1200/3937 meters)"); break;
			}
			out.println("UTM zone: "+utmZone);			
			out.println("Geodetic Datum Code: "+datum);
			
		
			out.println("Left Extend: "+leftExtend);
			out.println("Right Extend: "+rightExtend);
			out.println("Bottom Extend: "+bottomExtend);			
			out.println("Top Extend: "+topExtend);
			
			out.println("Grid Spacing X: "+gridSpacingX);
			out.println("Grid Spacing Y: "+gridSpacingY);
			
			if (projectionRequired)
				out.println("Require External projection: No");
			else
				out.println("Require External projection: Yes");
		
			out.println("Scale (Vertical units in meters): "+ scale);
			
			out.println("Size of data:" + (fileReader.remaining()));
			}
		

	
	//	data = new ElevationData(width-1,height-1);
		data.setGridSpacingX(gridSpacingX);
		data.setGridSpacingY(gridSpacingY);
		 
		data.setFile(file);
		// data.setScale(((float)height)/32768f);
		
		float maxElevation = 0;
		float minElevation = Float.MAX_VALUE;
		float sampleElevation = 0;
		
		for (int x = 0; x < width; x++) {
			
			for (int y = height -1; y >= 0; y--) {
				
				if (dataIsFloat) {
					sampleElevation = fileReader.readFloat();
				}
				else if (dataIsInt) {
					sampleElevation = (float) fileReader.readInt();
				}
				else if (dataIsShort) {
					sampleElevation = (float) fileReader.readShort();
				}
				//maxElevation = Math.max(sampleElevation,maxElevation);
				//minElevation = Math.min(sampleElevation,minElevation);
				sampleElevation *= scaleAdjustment;
				if (sampleElevation > maxElevation)
					maxElevation = sampleElevation;
				else if (sampleElevation < minElevation)
					minElevation = sampleElevation;
				
				 data.putSample(x,y,0,sampleElevation*scale);
			
			}

		}
	
	//	fileBuffer = null;
		fileReader.close();
		
		if (false) { 
		out.println("Min Read Elevation: "+minElevation);
		out.println("Max Read Elevation: "+maxElevation);
		
		}
		
		
		
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		try {
			fileReader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
		//Display.println("done");
		out.println("done");
		
	}

	


	
	
}
