/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.awk.builtin.stat;

import java.util.Arrays;

import net.morilib.awk.builtin.AwkQuaternaryArgs;
import net.morilib.awk.io.AwkFiles;
import net.morilib.awk.namespace.AwkNamespace;
import net.morilib.awk.value.AwkArray;
import net.morilib.awk.value.AwkInteger;
import net.morilib.awk.value.AwkValue;

/**
 * 関数stat.histogramの記述です。
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/04/13
 */
public class Histogram extends AwkQuaternaryArgs {

	public Histogram() {
		super("histogram");
	}

	@Override
	public AwkValue apply(AwkNamespace ns, AwkFiles o, AwkValue a1,
			AwkValue a2, AwkValue a3, AwkValue a4) {
		AwkArray ar = new AwkArray();
		double min, max, stp, x;
		long[] bin;

		min = a2.toFloat();
		max = a3.toFloat();
		stp = a4.toFloat();
		if(min >= max) {
			throw new AwkStatisticsException("Illegal range");
		} else if(stp <= 0) {
			throw new AwkStatisticsException("Illegal step");
		} else if(((max - min) / stp) + 2 > Integer.MAX_VALUE) {
			throw new AwkStatisticsException("Too much bins");
		}

		bin = new long[(int)Math.ceil((max - min) / stp) + 2];
		Arrays.fill(bin, 0l);
		for(AwkValue v : a1.values()) {
			if(!v.isRealValue()) {
				// do nothing
			} else if((x = v.toFloat()) < min) {
				bin[0]++;
			} else if(x > max) {
				bin[bin.length - 1]++;
			} else {
				bin[(int)((x - min) / stp) + 1]++;
			}
		}

		for(int i = 0; i < bin.length; i++) {
			ar.putArray(i + "", AwkInteger.valueOf(bin[i]));
		}
		return ar;
	}

}
