package skyview.data;

import static java.lang.Math.sqrt;
import nom.tam.fits.Header;
import skyview.executive.Settings;
import skyview.geometry.DepthSampler;
import skyview.geometry.Sampler;
import skyview.process.Processor;
import skyview.survey.Image;

/**
 * Compute compound polarization parameters from the basic I,Q,U.
 *
 * @author tmcglynn
 */
public class PolarData extends Processor {

    Compute c;
    String stokes;

    public PolarData() {
        stokes = Settings.get("Stokes").toUpperCase();
        if (stokes.equals("PI")) {
            c = new PolarPI();
        } else if (stokes.equals("PA")) {
            c = new PolarPA();
        } else if (stokes.equals("PI/I")) {
            c = new PolarFrac();
        } else {
            throw new IllegalArgumentException("Error in stokes parameter in PolarData: " + stokes);
        }
    }

    public void process(Image[] inputs, Image output, int[] source, Sampler samp, DepthSampler dsamp) {
        for (int p=0; p<output.getWidth()*output.getHeight(); p += 1) {
            double i= Double.NaN,q,u;
            if (inputs.length == 3) {
                i = inputs[0].getData(p);
                q = inputs[1].getData(p);
                u = inputs[2].getData(p);
            } else {
                q = inputs[0].getData(p);
                u = inputs[1].getData(p);
            }
            output.setData(p, c.value(i,q,u));
        }
    }

    public void updateHeader(Header header) {
        try {
            header.insertComment("");
            header.insertComment("Data combined with PolarData: Stokes=" + stokes);
            header.insertComment("");
        } catch (Exception e) {
            System.err.println("Error updating header in PolarData");
        }
    }

    public boolean updatesOutput() {
        return false;
    }

    public String getName() {
        return "PolarData";
    }

    public String getDescription() {
        return "Combines Polarized data after smoothing or other operations";
    }

    interface Compute {

        public abstract double value(double i, double q, double u);
    }

    class PolarPI implements Compute {

        public double value(double i, double q, double u) {
            return sqrt(q * q + u * u);
        }
    }

    class PolarPA implements Compute {

        public double value(double i, double q, double u) {
            return 0.5 * Math.atan2(q, -u);
        }
    }

    class PolarFrac implements Compute {

        public double value(double i, double q, double u) {
            return sqrt(q * q + u * u) / i;
        }
    }
}
