/*
 * 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.ArrayList;
import java.util.Collection;
import java.util.List;

import net.morilib.awk.builtin.AwkRand;
import net.morilib.awk.stat.dist.ContinuousDistribution;
import net.morilib.awk.stat.dist.DiscreteDistribution;
import net.morilib.awk.value.AwkArray;
import net.morilib.awk.value.AwkFloat;
import net.morilib.awk.value.AwkInteger;
import net.morilib.awk.value.AwkValue;

/**
 * 統計に関するユーティリティメソッドです。
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/04/14
 */
public final class AwkStatUtils {

	/**
	 * 1から始まる添字のawkium配列をdoubleの配列に変換します。
	 * 
	 * @param a awkium値
	 * @return 配列
	 */
	public static double[] toDoubleArray(AwkValue a) {
		List<Double> v;
		double[] x;
		int j = 0;

		v = new ArrayList<Double>();
		for(int i = 1; a.referArray(i + "").isRealValue(); i++) {
			v.add(a.referArray(i + "").toFloat());
		}
		x = new double[v.size()];  j = 0;
		for(double d : v)  x[j++] = d;
		return x;
	}

	/**
	 * awkium配列をdoubleの配列に変換します。<br />
	 * 配列の添字は気にしません。
	 * 
	 * @param a awkium値
	 * @return 配列
	 */
	public static double[] toDoubleValues(AwkValue a) {
		Collection<AwkValue> z;
		List<Double> v;
		double[] x;
		int j = 0;

		z = a.values();
		v = new ArrayList<Double>();
		for(AwkValue b : z) {
			if(b.isRealValue())  v.add(b.toFloat());
		}
		x = new double[v.size()];  j = 0;
		for(double d : v)  x[j++] = d;
		return x;
	}

	/**
	 * 乱数を生成します。
	 * 
	 * @param dist 確率分布
	 * @return
	 */
	public static AwkValue generateRandom(
			ContinuousDistribution dist) {
		double x;

		x = AwkRand.RANDOM.nextDouble1Closed();
		x = dist.invCdf(x);
		return AwkFloat.valueOf(x);
	}

	/**
	 * 乱数系列を生成します。
	 * 
	 * @param dist 確率分布
	 * @param n    生成個数
	 * @return
	 */
	public static AwkValue generateRandoms(
			ContinuousDistribution dist, int n) {
		AwkArray r = new AwkArray();
		double x;

		for(int i = 0; i < n; i++) {
			x = AwkRand.RANDOM.nextDouble1Closed();
			x = dist.invCdf(x);
			r.putArray((i + 1) + "", AwkFloat.valueOf(x));
		}
		return r;
	}

	/**
	 * 乱数を生成します。
	 * 
	 * @param dist 離散確率分布
	 * @return
	 */
	public static AwkValue generateRandom(
			DiscreteDistribution dist) {
		double x;

		x = AwkRand.RANDOM.nextDouble1Closed();
		return AwkInteger.valueOf(dist.invCdf(x));
	}

	/**
	 * 乱数系列を生成します。
	 * 
	 * @param dist 離散確率分布
	 * @param n    生成個数
	 * @return
	 */
	public static AwkValue generateRandoms(
			DiscreteDistribution dist, int n) {
		AwkArray r = new AwkArray();
		double x;

		for(int i = 1; i <= n; i++) {
			x = AwkRand.RANDOM.nextDouble1Closed();
			r.putArray(i + "", AwkInteger.valueOf(dist.invCdf(x)));
		}
		return r;
	}

}
