/*
 * CorbaHist1DAdapter.java
 *
 * Created on June 12, 2003, 5:54 PM
 */

package hep.aida.ref.remote.testRemote.converters;

//import hep.aida.dev.IConverter;
import hep.aida.IAnnotation;
import hep.aida.IAxis;
import hep.aida.IHistogram2D;
import hep.aida.IManagedObject;
import hep.aida.ref.Annotation;

import hep.aida.ref.histogram.Histogram2D;
import hep.aida.ref.remote.RemoteHistogram2D;

/**
 * Converts Hist1DData to RemoteHistogram1D
 * @author  serbo
 */
public final class TestHist2DConverter extends TestConverter {
    
    private static TestHist2DConverter converter = null;
    
    /** Creates a new instance of CorbaHist1DAdapter */
    public static TestHist2DConverter getInstance() {
        if (converter == null) converter = new TestHist2DConverter();
        return converter;
    }
    
    private TestHist2DConverter() {
        super();
        dataType = "IHistogram2D";
        aidaType = "IHistogram2D";
    }
    
    
    /**
     * Creates new instance of type "type".
     */
    public Object createAidaObject(String name) {
        RemoteHistogram2D result = new RemoteHistogram2D(name);        
        return result;
    }
    
    /**
     * Updates data contained by object.
     * Input must be IHistogram1D.
     */
    public boolean updateAidaObject(Object aidaObject, Object newData) {
        IHistogram2D data = null;
        if (newData instanceof IHistogram2D) {
            data = (IHistogram2D) newData;
        }
        
        if (!(aidaObject instanceof hep.aida.ref.remote.RemoteHistogram2D))
            throw new IllegalArgumentException("Not supported object type: "+aidaObject.getClass().getName());
        if (!(data instanceof IHistogram2D))
            throw new IllegalArgumentException("Not supported data type: "+(data == null ? "null" : newData.getClass().getName()));

        updateData((RemoteHistogram2D) aidaObject, data);
        return true;
    }
  
    /**
     * Returns IHistogram1D object
     */
    public Object extractData(Object aidaObject) {
        if (!(aidaObject instanceof hep.aida.IHistogram2D))
            throw new IllegalArgumentException("Not supported data type: "+aidaObject.getClass().getName());

        IHistogram2D data = null;
        synchronized (aidaObject) {
            data = createData((hep.aida.IHistogram2D) aidaObject);
        }
        
        return data;
    }
  
    
   /**
    * Update data in RemoteHistogram1d from IHistogram1D
    * and calls setDataValid(true) method.
    */ 
   public IManagedObject updateData(RemoteHistogram2D hist, IHistogram2D data)
   {
       hist.setFillable(true);
       
        IAnnotation localAnnotation = null;
        int inRangeEntries = 0; 
        int extraEntries = 0; 
        double equivalentBinEntries = 0.;
        double inRangeBinHeights = 0.;
        double extraBinHeights = 0.;
        double minBinHeights = 0.;
        double maxBinHeights = 0.;

        int[][] entries    = null;
        double[][] heights = null;
        double[][] errors  = null;
        double[][] rmss    = null;
        double[][] meansX  = null;
        double[][] rmssX   = null;
        double[][] meansY  = null;
        double[][] rmssY   = null;
        
        int[] binEntriesX = null;
        int[] binEntriesY = null;
        double[] binHeightsX = null;
        double[] binHeightsY = null;
        
        synchronized (data) { 
      // Check if X axis binning or edges are different
      IAxis lXAxis = hist.xAxis();      
      IAxis rXAxis = data.xAxis();  
      int nXBins = rXAxis.bins();
      if (lXAxis == null || lXAxis.bins() != nXBins || 
          lXAxis.lowerEdge() != rXAxis.lowerEdge() || lXAxis.upperEdge() != rXAxis.upperEdge()) {
          hist.setXAxis(nXBins, rXAxis.lowerEdge(), rXAxis.upperEdge()); 
      }
      
      // Check if Y axis binning or edges are different
      IAxis lYAxis = hist.yAxis();      
      IAxis rYAxis = data.yAxis();  
      int nYBins = rYAxis.bins();
      if (lYAxis == null || lXAxis.bins() != nYBins || 
          lYAxis.lowerEdge() != rYAxis.lowerEdge() || lYAxis.upperEdge() != rYAxis.upperEdge()) {
          hist.setYAxis(nYBins, rYAxis.lowerEdge(), rYAxis.upperEdge()); 
      }
      
      // Check and set Annotation
      if (data.annotation() != null && data.annotation().size() > 0) {
          boolean sticky = false;
          localAnnotation = hist.annotation();
          if (localAnnotation instanceof Annotation)  
              ((Annotation) localAnnotation).setFillable(true);
          for (int i=0; i<data.annotation().size(); i++) {
              String key = data.annotation().key(i);
              String newValue = data.annotation().value(key);
              String oldValue = null;
              try {
                  oldValue = localAnnotation.value(key);
              } catch (IllegalArgumentException e) {}
              if (oldValue == null) localAnnotation.addItem(key, newValue, sticky);
              else if (!newValue.equals(oldValue)) {
                  localAnnotation.setValue(key,  newValue);
                  localAnnotation.setSticky(key,  sticky);
              }
          }
          if (localAnnotation instanceof Annotation)  
              ((Annotation) localAnnotation).setFillable(false);          
      }
      
            // Get bin information
            if (nXBins > 0 && nYBins>0) {
                entries    = new int[nXBins+2][nYBins+2];
                heights = new double[nXBins+2][nYBins+2];
                errors  = new double[nXBins+2][nYBins+2];
                meansX  = new double[nXBins+2][nYBins+2];
                rmssX   = new double[nXBins+2][nYBins+2];
                meansY  = new double[nXBins+2][nYBins+2];
                rmssY   = new double[nXBins+2][nYBins+2];

                binEntriesX = new int[nXBins+2];
                binEntriesY = new int[nYBins+2];
                binHeightsX = new double[nXBins+2];
                binHeightsY = new double[nYBins+2];

                int ii = 0;
                int jj = 0;
                for (int i=0; i<nXBins+2; i++) {
                for (int j=0; j<nYBins+2; j++) {
                    ii = convertToAIDAIndex(nXBins, i);
                    jj = convertToAIDAIndex(nYBins, j);
                    
                    heights[i][j] = data.binHeight(ii, jj);
                    errors[i][j]  = data.binError(ii, jj);
                    entries[i][j] = data.binEntries(ii, jj);
                    meansX[i][j]  = data.binMeanX(ii, jj);
                    meansY[i][j]  = data.binMeanY(ii, jj);
                    if (data instanceof Histogram2D) {
                        rmssX[i][j]   = ((Histogram2D) data).binRmsX(ii, jj);
                        rmssY[i][j]   = ((Histogram2D) data).binRmsY(ii, jj);
                    }
                }}
        
                // Go along X Axis
                for ( int i=0; i<nXBins+2; i++) {
                    ii = convertToAIDAIndex(nXBins, i);
                    binEntriesX[i] = data.binEntriesX(ii);
                    binHeightsX[i] = data.binHeightX(ii);
                } 
                
                // Go along Y Axis
                for ( int j=0; j<nYBins+2; j++) {
                    jj = convertToAIDAIndex(nYBins, j);
                    binEntriesY[j] = data.binEntriesX(jj);
                    binHeightsY[j] = data.binHeightX(jj);
                }          
                
                inRangeEntries = data.entries();
                extraEntries = data.extraEntries();
                equivalentBinEntries = data.equivalentBinEntries();
                inRangeBinHeights = data.sumBinHeights();
                extraBinHeights = data.sumExtraBinHeights();
                minBinHeights = data.minBinHeight();
                maxBinHeights = data.maxBinHeight();
            }      
      }
      
      // Set bin information
      
      synchronized (hist) {
        
        // Set arrays
        hist.setHeights(heights);
        hist.setErrors(errors);
        hist.setEntries(entries);
        hist.setBinMeansX(meansX);
        hist.setBinRmssX(rmssX);
        hist.setBinMeansY(meansY);
        hist.setBinRmssY(rmssY);
        
        hist.setBinEntriesX(binEntriesX);
        hist.setBinEntriesY(binEntriesY);
        hist.setBinHeightsX(binHeightsX);
        hist.setBinHeightsX(binHeightsY);
        
        // Setting single numbers
        hist.setMeanX(data.meanX());
        hist.setRmsX(data.rmsX());
        hist.setMeanY(data.meanY());
        hist.setRmsY(data.rmsY());
        
        hist.setInRangeEntries(inRangeEntries);
        hist.setExtraEntries(extraEntries);
        hist.setEquivalentBinEntries(equivalentBinEntries);
        hist.setInRangeBinHeights(inRangeBinHeights);
        hist.setExtraBinHeights(extraBinHeights);
        hist.setMinBinHeights(minBinHeights);
        hist.setMaxBinHeights(maxBinHeights);
                
        hist.setFillable(false);
        hist.setDataValid(true);
      }
      return hist;
   }
   
   /**
    * Create Hist1DData structure from an IHistogram1D
    */
    public IHistogram2D createData(IHistogram2D hist) {
        IHistogram2D data = hist;

        return data;
    } 
    
    private int convertToAIDAIndex(int nBins, int index) {
        int mi;
        if ( index == 0 )
            mi = IAxis.UNDERFLOW_BIN;
        else if ( index == nBins+1 )
            mi = IAxis.OVERFLOW_BIN;
        else
            mi = index - 1;
        return mi;
    }
}