/*
 * RemoteHistogram1D.java
 *
 * Created on May 28, 2003, 5:38 PM
 */

package hep.aida.ref.remote;

import hep.aida.IAnnotation;
import hep.aida.IHistogram2D;
import hep.aida.IManagedObject;
import hep.aida.IAxis;
import hep.aida.dev.IDevMutableStore;
import hep.aida.ref.Annotation;
import hep.aida.ref.ManagedObject;
import hep.aida.ref.ReadOnlyException;
import hep.aida.ref.histogram.FixedAxis;
import hep.aida.ref.histogram.UnfillableHistogramException;
import hep.aida.ref.event.IsObservable;
import hep.aida.ref.event.HistogramEvent;

/**
 * This is implementation of IHistogram2D that can not be modified
 * by the user. This is a simple implementation that does not guarantee
 * internal consistency. So extra care should be taken when setting
 * data for this class.
 * This Class is designed to work with the IDevMutableStore, but can
 * work with other Stores - overwrite makeSureDataIsValid() method.
 * Note: use "putTitle" method, AIDA's "setTitle" is disabled.
 * Don't forget to call "setDataValid" after you fill new data, as
 * only this method fires events to notify AIDAListeners about change.
 *
 * Also please note that in our current AIDA implementation:
 *  UNDERFLOW_BIN = -2, OVERFLOW_BIN = -1, bins = [0, nBins-1]
 * But we keep them here as:
 *  UNDERFLOW_BIN = 0, OVERFLOW_BIN = nBins+1, bins = [1, nBins]
 * 
 * @author  serbo
 */
public class RemoteHistogram2D extends RemoteManagedObject implements IHistogram2D {
    
    private Annotation annotation = null;
    private IAxis xAxis = null;
    private IAxis yAxis = null;
    
    private double[][] heights = null;
    private double[][] errors = null;
    private int[][] entries = null;
    //private double[][] means = null;
    //private double[][] rmss = null;

    private double[][] binMeansX = null;
    private double[][] binRmssX = null;
    private double[][] binMeansY = null;
    private double[][] binRmssY = null;
    
    private int[] binEntriesX;
    private int[] binEntriesY;
    private double[] binHeightsX;
    private double[] binHeightsY;
    
    private double meanX = 0;
    private double rmsX = 0;
    private double meanY = 0;
    private double rmsY = 0;
    private int inRangeEntries = 0;
    private int extraEntries = 0;
    private double equivalentBinEntries = 0;
    private double inRangeBinHeights = 0;
    private double extraBinHeights = 0;
    private double minBinHeights = 0;
    private double maxBinHeights = 0;
    
    
    /** Creates a new instance of RemoteHistogram1D */
    public RemoteHistogram2D(String name) {
        this(null, name);
    }
    
    public RemoteHistogram2D(IDevMutableStore store, String name) {
        super(name);
        aidaType = "IHistogram2D";
        this.store = store;
        annotation = new Annotation(); 
        annotation.setFillable(true);
        annotation.addItem(Annotation.titleKey,name,true);
        annotation.setFillable(false);
        dataIsValid = false;
        xAxis = new FixedAxis(50, 0, 1);
        yAxis = new FixedAxis(50, 0, 1);
    }
    
    public RemoteHistogram2D(IDevMutableStore store, String name, String title) {
        super(name);
        aidaType = "IHistogram2D";
        this.store = store;
        annotation = new Annotation();
        annotation.setFillable(true);
        annotation.addItem(Annotation.titleKey,title,true);
        annotation.setFillable(false);
        dataIsValid = false;
        xAxis = new FixedAxis(50, 0, 1);
        yAxis = new FixedAxis(50, 0, 1);
    }
    
    
    // AIDAObservable methods
    protected java.util.EventObject createEvent()
    {
       return new HistogramEvent(this);
    }

    
    // Service methods
    
    private int convertAIDAIndex(IAxis axis, int index) {
        int mi;
        if ( index == IAxis.UNDERFLOW_BIN )
            mi = 0;
        else if ( index == IAxis.OVERFLOW_BIN )
            mi = axis.bins()+1;
        else
            mi = index + 1;
        return mi;
    }
    
    public void setAnnotation(Annotation a) { annotation = a; }
    
    public void setXAxis(int bins, double min, double max) {
        xAxis = new FixedAxis(bins, min, max);
    }
    public void setYAxis(int bins, double min, double max) {
        yAxis = new FixedAxis(bins, min, max);
    }

    public void setRmsX(double rms) {
        this.rmsX = rms;
    }
    public void setRmsY(double rms) {
        this.rmsY = rms;
    }
    
    public void setMeanX(double mean) {
        this.meanX = mean;
    }
    public void setMeanY(double mean) {
        this.meanY = mean;
    }
    
    
    public void setHeights(double[][] h) {
        if (h == null || h.length == 0) {
            heights = null;
            inRangeBinHeights = Double.NaN;
            extraBinHeights = Double.NaN;
            minBinHeights = Double.NaN;
            maxBinHeights = Double.NaN;
            return;
        }
        heights = h;
    }

    public void setEntries(int[][] h) {
        if (h == null || h.length == 0) {
            entries = null;
            inRangeEntries = Integer.MIN_VALUE;
            extraEntries = Integer.MIN_VALUE;
            equivalentBinEntries = Double.NaN;
            return;
        }
        entries = h;
    }

    public void setErrors(double[][] h) {
        if (h == null || h.length == 0) {
            errors = null;
            return;
        }
        errors = h;
    }

    public void setBinMeansX(double[][] h) {
        if (h == null || h.length == 0) {
            binMeansX = null;
            return;
        }
        binMeansX = h;
    }

    public void setBinRmssX(double[][] h) {
        if (h == null || h.length == 0) {
            binRmssX = null;
            return;
        }
        binRmssX = h;
    }

    public void setBinMeansY(double[][] h) {
        if (h == null || h.length == 0) {
            binMeansY = null;
            return;
        }
        binMeansY = h;
    }

    public void setBinRmssY(double[][] h) {
        if (h == null || h.length == 0) {
            binRmssY = null;
            return;
        }
        binRmssY = h;
    }

    public void setBinEntriesX(int[] h) {
        if (h == null || h.length == 0) {
            binEntriesX = null;
            return;
        }
        binEntriesX = h;
    }
    public void setBinEntriesY(int[] h) {
        if (h == null || h.length == 0) {
            binEntriesY = null;
            return;
        }
        binEntriesY = h;
    }
    public void setBinHeightsX(double[] h) {
        if (h == null || h.length == 0) {
            binHeightsX = null;
            return;
        }
        binHeightsX = h;
    }
    public void setBinHeightsY(double[] h) {
        if (h == null || h.length == 0) {
            binHeightsY = null;
            return;
        }
        binHeightsY = h;
    }
    
    public void setInRangeEntries(int d) { inRangeEntries = d; }
    public void setExtraEntries(int d) { extraEntries = d; }
    public void setEquivalentBinEntries( double d) { equivalentBinEntries = d; }
    public void setInRangeBinHeights(double d) { inRangeBinHeights = d; }
    public void setExtraBinHeights(double d) { extraBinHeights = d; }
    public void setMinBinHeights(double d) { minBinHeights = d; }
    public void setMaxBinHeights(double d) { maxBinHeights = d; }
    
    
    // IBaseHistogram methods
    
    public hep.aida.IAnnotation annotation() {
        makeSureDataIsValid();
        return annotation;
    }
    
    public int dimension() {
        //makeSureDataIsValid();
        return 2;
    }
    
    public int entries() {
        makeSureDataIsValid();
        return inRangeEntries;
    }
    
    public void reset() throws java.lang.RuntimeException {
        throw new ReadOnlyException();
    }
    
    public String title() {
        makeSureDataIsValid();
        return annotation.value(Annotation.titleKey);
    }
    
    public void setTitle(String title) throws java.lang.IllegalArgumentException {
        if (!fillable) throw new ReadOnlyException();
        annotation.setFillable(true);
        annotation.setValue(Annotation.titleKey,title);        
        annotation.setFillable(false);
    }
        

    
    // IHistogram methods
    
    public int allEntries() {
        if (entries == null) return Integer.MIN_VALUE;
        return (entries() + extraEntries());
    }
    
    public double equivalentBinEntries() {
        makeSureDataIsValid();
        return equivalentBinEntries;
    }
    
    public int extraEntries() {
        makeSureDataIsValid();
        return extraEntries;
    }
    
    public double maxBinHeight() {
        makeSureDataIsValid();
        return maxBinHeights;
    }
    
    public double minBinHeight() {
        makeSureDataIsValid();
        return minBinHeights;
    }

    public void scale(double param) throws java.lang.IllegalArgumentException {
        throw new ReadOnlyException();
    }
    
    public double sumAllBinHeights() {
        makeSureDataIsValid();
        if (heights == null) return Double.NaN;
        return (sumBinHeights() + sumExtraBinHeights());
    }
    
    public double sumBinHeights() {
        makeSureDataIsValid();
        if (heights == null) return Double.NaN;
        return inRangeBinHeights;
    }
    
    public double sumExtraBinHeights() {
        makeSureDataIsValid();
        if (heights == null) return Double.NaN;
        return extraBinHeights;
    }
        

    
    // IHistogram2D methods
    
    public void add(hep.aida.IHistogram2D iHistogram2D) throws java.lang.IllegalArgumentException {
        throw new ReadOnlyException();
    }
    
    public int binEntries(int param1, int param2) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (entries == null) return Integer.MIN_VALUE;
        return entries[convertAIDAIndex(xAxis, param1)][convertAIDAIndex(yAxis, param2)];
    }
    
    public int binEntriesX(int param) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binEntriesX == null) return Integer.MIN_VALUE;
        return binEntriesX[convertAIDAIndex(xAxis, param)];
    }
    
    public int binEntriesY(int param) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binEntriesY == null) return Integer.MIN_VALUE;
        return binEntriesY[convertAIDAIndex(yAxis, param)];
    }
    
    public double binError(int param1, int param2) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (errors == null) return Double.NaN;
        return errors[convertAIDAIndex(xAxis, param1)][convertAIDAIndex(yAxis, param2)];
    }
    
    public double binHeight(int param1, int param2) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (heights == null) return Double.NaN;
        return heights[convertAIDAIndex(xAxis, param1)][convertAIDAIndex(yAxis, param2)];
    }
    
    public double binHeightX(int param) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binHeightsX == null) return Double.NaN;
        return binHeightsX[convertAIDAIndex(xAxis, param)];
    }
    
    public double binHeightY(int param) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binHeightsY == null) return Double.NaN;
        return binHeightsY[convertAIDAIndex(yAxis, param)];
    }
    
    public double binMeanX(int param1, int param2) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binMeansX == null) return Double.NaN;
        return binMeansX[convertAIDAIndex(xAxis, param1)][convertAIDAIndex(yAxis, param2)];
    }
    
    public double binMeanY(int param1, int param2) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binMeansY == null) return Double.NaN;
        return binMeansY[convertAIDAIndex(xAxis, param1)][convertAIDAIndex(yAxis, param2)];
    }
    
    public double binRmsX(int param1, int param2) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binRmssX == null) return Double.NaN;
        return binRmssX[convertAIDAIndex(xAxis, param1)][convertAIDAIndex(yAxis, param2)];
    }
    
    public double binRmsY(int param1, int param2) throws java.lang.IllegalArgumentException {
        makeSureDataIsValid();
        if (binRmssY == null) return Double.NaN;
        return binRmssY[convertAIDAIndex(xAxis, param1)][convertAIDAIndex(yAxis, param2)];
    }
    
    public int coordToIndexX(double param) {
        makeSureDataIsValid();
        return xAxis.coordToIndex(param);
    }
    
    public int coordToIndexY(double param) {
        makeSureDataIsValid();
        return xAxis.coordToIndex(param);
    }
    
    public void fill(double param, double param1) throws java.lang.IllegalArgumentException {
        throw new ReadOnlyException();
    }
    
    public void fill(double param, double param1, double param2) throws java.lang.IllegalArgumentException {
        throw new ReadOnlyException();
    }
    
    public double meanX() {
        makeSureDataIsValid();
        return meanX;
    }
    
    public double meanY() {
        makeSureDataIsValid();
        return meanY;
    }
    
    public double rmsX() {
        makeSureDataIsValid();
        return rmsX;
    }
    
    public double rmsY() {
        makeSureDataIsValid();
        return rmsY;
    }
    
    public hep.aida.IAxis xAxis() {
        makeSureDataIsValid();
        return xAxis;
    }
    
    public hep.aida.IAxis yAxis() {
        makeSureDataIsValid();
        return yAxis;
    }
    
}
