import nom.tam.fits.*;
import nom.tam.util.*;

import java.io.*;


public class SquareArrayScan extends LabocaScan {

	public SquareArrayScan() { 
		instrumentName = "square";
		rcpFile=null;
		pixelDataFile=null;
		channelTemplate = new SquareArrayPixel(-1);
	}
	
	public void getChannelGroups() throws Exception {
		cableChannels = LabocaPixel.getChannelGroups(channel, LabocaPixel.class.getField("cable"), LabocaPixel.FLAG_DEAD); 
	}
	
	public void readPar(BinaryTableHDU hdu) throws IOException, FitsException, HeaderCardException {
		super.readPar(hdu);
		instrumentGain = 1.0;
	}
	
	public static void writeScans(SquareArrayScan[] scan, String fileName) throws IOException, FitsException, HeaderCardException {
		Fits fits = new Fits();
		
		fits.addHDU(getHeaderHDU());
		fits.addHDU(getScanInfoHDU(scan));
		fits.addHDU(scan[0].getParHDU());
		
		for(int i=0; i<scan.length; i++) scan[i].writeScan(fits);
	}
	
	public void writeScan(Fits fits) throws IOException, FitsException, HeaderCardException {
		try {
			fits.addHDU(getDataParHDU());
			fits.addHDU(getDataHDU());
			fits.addHDU(getMonitorHDU());
		}
		catch(Exception e) {
			System.err.println(" ERROR: " + e.getMessage());
			e.printStackTrace();
		}

	}
	

	public static BasicHDU getScanInfoHDU(SquareArrayScan[] scans) throws IOException, FitsException, HeaderCardException {
		Header header = new Header();
		Cursor cursor = header.iterator();
		LabocaScan scan = scans[0];
		
		cursor.add(new HeaderCard("EXTNAME", "SCAN-MBFITS", ""));
		cursor.add(new HeaderCard("CTYPE1", "RA---" + scan.map.projection.getFitsID(), "Right ascention"));
		cursor.add(new HeaderCard("CRVAL1", scan.equatorial.canonicalLatitude() / Unit.deg, "Right ascention"));
		cursor.add(new HeaderCard("CTYPE2", "DEC--" + scan.map.projection.getFitsID(), "Right ascention"));
		cursor.add(new HeaderCard("CRVAL2", scan.equatorial.canonicalLongitude() / Unit.deg, "Declination"));
		cursor.add(new HeaderCard("OBJECT", scan.sourceName, "The target name."));
		cursor.add(new HeaderCard("NOBS", scans.length, "The number of subscans"));
		
		cursor.add(new HeaderCard("SITELONG", LabocaFrame.longitude, ""));
		cursor.add(new HeaderCard("SITELAT", LabocaFrame.latitude, ""));
		
		cursor.add(new HeaderCard("WOBUSED", scan.isChopped, ""));
		cursor.add(new HeaderCard("WOBTHROW", scan.chopperThrow / Unit.deg, ""));
		
		return Fits.makeHDU(header);
	}

	public BinaryTableHDU getParHDU() throws IOException, FitsException, HeaderCardException {
		double[] xOffset = new double[channels];
		double[] yOffset = new double[channels];
		for(int c=0; c<channels; c++) {
			xOffset[c] = channel[c].position.x / Unit.deg;
			yOffset[c] = channel[c].position.y / Unit.deg;
		}
		
		Object[] row = new Object[7];
		for(int i=0; i<row.length; i++) row[i] = new double[1];
			
		row[5] = xOffset;
		row[6] = yOffset;
		row[7] = new double[] {referenceChannel+1};
		Object[] table = new Object[] { row };
		
		BinaryTableHDU hdu = (BinaryTableHDU) Fits.makeHDU(table);
		Header header = hdu.getHeader();
		Cursor cursor = header.iterator();
		
		cursor.add(new HeaderCard("EXTNAME", "PAR-MBFITS", ""));
		cursor.add(new HeaderCard("FEGAIN", instrumentGain, "The hardware gain"));
		
		return hdu;
	}
	
	public BasicHDU getDataHDU() throws IOException, FitsException, HeaderCardException {
		Object[] table = new Object[frames];
		for(int t=0; t<frames; t++) {
			LabocaFrame exposure = frame[t];
			Object[] row = new Object[2];
			
			float[][] data = new float[channels][1];
			for(int c=0; c<data.length; c++) data[c][0] = exposure.data[c];

			row[0] = new double[] { t * integrationTime }; // MJD
			row[1] = data;

			table[t] = row;
		}
		
		BinaryTableHDU hdu = (BinaryTableHDU) Fits.makeHDU(table);
		Header header = hdu.getHeader();
		Cursor cursor = header.iterator();
		cursor.add(new HeaderCard("EXTNAME", "ARRAYDATA-MBFITS", ""));
		
		return hdu;
	}
	
	public BinaryTableHDU getDataParHDU()  throws IOException, FitsException, HeaderCardException {
		Object table[][] = new Object[frames][10];
		
		for(int t=0; t<frames; t++) {
			LabocaFrame exposure = frame[t];
			Object[] row = table[t];
			row[0] = new double[] { t * integrationTime };
			row[1] = new double[] { integrationTime };
			row[2] = new double[] { exposure.RA / Unit.deg };
			row[3] = new double[] { exposure.DEC / Unit.deg };
			row[4] = new double[] { exposure.AZ / Unit.deg };
			row[5] = new double[] { exposure.EL / Unit.deg };
			row[6] = new double[] { exposure.dX / Unit.deg };
			row[7] = new double[] { exposure.dY / Unit.deg };
			row[8] = new double[] { exposure.chopperPosition / Unit.deg };
			row[9] = new int[] { exposure.chopperPhase };			
		}
		
		
		BinaryTableHDU hdu = (BinaryTableHDU) Fits.makeHDU(table);
		Header header = hdu.getHeader();
		Cursor cursor = header.iterator();

		cursor.add(new HeaderCard("EXTNAME", "DATAPAR-MBFITS", ""));
		
		cursor.add(new HeaderCard("TTYPE1", "MJD", "Column header."));
		cursor.add(new HeaderCard("TTYPE2", "INTEGTIM", "Column header."));
		cursor.add(new HeaderCard("TTYPE3", "BASLONG", "Column header."));
		cursor.add(new HeaderCard("TTYPE4", "BASLAT", "Column header."));
		cursor.add(new HeaderCard("TTYPE5", "AZIMUTH", "Column header."));
		cursor.add(new HeaderCard("TTYPE6", "ELEVATIO", "Column header."));
		cursor.add(new HeaderCard("TTYPE7", "LONGOFF", "Column header."));
		cursor.add(new HeaderCard("TTYPE8", "LATOFF", "Column header."));
		cursor.add(new HeaderCard("TTYPE9", "WOBDISLN", "Column header."));
		cursor.add(new HeaderCard("TTYPE10", "PHASE", "Column header."));
		
		cursor.add(new HeaderCard("PHASE1", 1, "Phase number."));
		cursor.add(new HeaderCard("PHASE2", 2, "Phase number."));
		cursor.add(new HeaderCard("WON", onPhase, "Chopped on-phase number."));
		cursor.add(new HeaderCard("WOFF", offPhase, "Chopped off-phase number."));
		
		return hdu;
	}

	public BasicHDU getMonitorHDU() throws IOException, FitsException, HeaderCardException {
		Header header = new Header();
		Cursor cursor = header.iterator();
		
		cursor.add(new HeaderCard("EXTNAME", "MONITOR-MBFITS", ""));
		
		return Fits.makeHDU(header);
	}
	
	public static BasicHDU getHeaderHDU() throws IOException, FitsException, HeaderCardException {
		Header header = new Header();
		Cursor cursor = header.iterator();
		
		cursor.add(new HeaderCard("EXTNAME", "MBFITS", ""));
		
		return Fits.makeHDU(header);
	}
	
}
