/**
 * Copyright (C) 2010-14 pvmanager developers. See COPYRIGHT.TXT
 * All rights reserved. Use is subject to license terms. See LICENSE.TXT
 */
package org.epics.pvmanager.graphene;

import org.epics.graphene.Cell2DDataset;
import org.epics.graphene.Range;
import org.epics.graphene.RangeUtil;
import org.epics.graphene.Statistics;
import org.epics.graphene.StatisticsUtil;
import org.epics.util.array.ArrayDouble;
import org.epics.util.array.ListNumber;
import org.epics.vtype.VNumberArray;

/**
 *
 * @author carcassi
 */
class Cell2DDatasetFromVNumberArray implements Cell2DDataset {
    private Statistics statistics;
    private final ListNumber xBoundaries;
    private final ListNumber yBoundaries;
    private final Range xRange;
    private final Range yRange;
    private final Range displayRange;

    private final int xCount;
    private final int yCount;
    private final VNumberArray data;
    private final ListNumber values;

    public Cell2DDatasetFromVNumberArray(VNumberArray data) {
        this.data = data;
        this.values = data.getData();
        if (data.getSizes().size() == 1) {
            this.xBoundaries = data.getDimensionDisplay().get(0).getCellBoundaries();
            this.yBoundaries = new ArrayDouble(0, 1);
        } else if (data.getSizes().size() == 2) {
            this.xBoundaries = data.getDimensionDisplay().get(1).getCellBoundaries();
            this.yBoundaries = data.getDimensionDisplay().get(0).getCellBoundaries();
        } else {
            throw new IllegalArgumentException("Array is 3D or more");
        }
        
        this.xRange = RangeUtil.range(xBoundaries.getDouble(0), xBoundaries.getDouble(xBoundaries.size() - 1));
        this.yRange = RangeUtil.range(yBoundaries.getDouble(0), yBoundaries.getDouble(yBoundaries.size() - 1));
        this.xCount = xBoundaries.size() - 1;
        this.yCount = yBoundaries.size() - 1;
        this.displayRange = RangeUtil.range(data.getLowerDisplayLimit(), data.getUpperDisplayLimit());
    }

    @Override
    public double getValue(int x, int y) {
        return values.getDouble(y * xCount + x);
    }

    @Override
    public Statistics getStatistics() {
        if (statistics == null) {
            statistics =  StatisticsUtil.lazyStatisticsOf(values);
        }
        return statistics;
    }

    @Override
    public Range getDisplayRange() {
        return displayRange;
    }

    @Override
    public ListNumber getXBoundaries() {
        return xBoundaries;
    }

    @Override
    public Range getXRange() {
        return xRange;
    }

    @Override
    public int getXCount() {
        return xCount;
    }

    @Override
    public ListNumber getYBoundaries() {
        return yBoundaries;
    }

    @Override
    public Range getYRange() {
        return yRange;
    }

    @Override
    public int getYCount() {
        return yCount;
    }
    
}

@@ -410,16 +410,92 @@
 Double;%0A
+import org.epics.util.array.ArrayInt;%0Aimport org.epics.util.array.ListByte;%0A
 import o
@@ -562,16 +562,62 @@
 erArray;
+%0Aimport org.epics.vtype.ndarray.Array2DDouble;
 %0A%0A/**%0A *
@@ -1059,16 +1059,62 @@
  values;
+%0A    %0A    private final Array2DDouble array2D;
 %0A%0A    pu
@@ -1416,16 +1416,158 @@
 (0, 1);%0A
+            this.array2D = new Array2DDouble(new ArrayInt(1, xBoundaries.size() - 1), false, data.getDimensionDisplay().get(0).isReversed());%0A
         
@@ -1772,32 +1772,191 @@
 llBoundaries();%0A
+            this.array2D = new Array2DDouble(data.getSizes(), data.getDimensionDisplay().get(1).isReversed(), data.getDimensionDisplay().get(0).isReversed());%0A
         %7D else %7B
@@ -2374,44 +2374,90 @@
     
-this.displayRange = RangeUtil.range(
+// TODO: better way to handle if display limits are not set?%0A        double low = 
 data
@@ -2479,17 +2479,39 @@
 yLimit()
-,
+;%0A        double high =
  data.ge
@@ -2530,16 +2530,345 @@
 yLimit()
+;%0A        if (values instanceof ListByte) %7B%0A            if (low == high) %7B%0A                low = Byte.MIN_VALUE;%0A                high = Byte.MAX_VALUE;%0A            %7D%0A            low = Math.max(Byte.MIN_VALUE, low);%0A            high = Math.min(Byte.MAX_VALUE, high);%0A        %7D%0A        this.displayRange = RangeUtil.range(low, high
 );%0A    %7D
@@ -2962,22 +2962,30 @@
 ble(
-y * xCount + x
+array2D.getIndex(x, y)
 );%0A 

update to current SNAPSHOT