// 例によって某所からの移植
// 何となく気が向いたので、クラス化してみる
// →（メソッド名/変数名がカブるのも怖い）

// つかいかた ※全てクラスメソッドなので「クラス名.メソッド名」でコール可能
// var result = Caluclate.calcRound(10000.045, 2);

function Calculate() {
	this.initialize.apply(this, arguments);
}
Calculate = {

	// 四捨五入を行う
	// 引数 value 四捨五入を行う値
	//		keta 桁数 潤ｵ -2:10の位, -1:1の位,0:小数点第一位, 1:小数点第二位 潤ｵ
	//			(※marumeとは桁数の扱いが異なるので注意！)
	calcRound: function(value, keta) {
		var scale = this.getScale(keta);
		return this.marumeRound(eval(value),scale);
	},

	// まるめ(切捨)を行う
	// 引数 value まるめ(切捨)を行う値
	//		scale 桁合わせ用スケール
	marumeKirisute: function(value,scale){
		var temp = value;
		value = Math.abs(value);
		value = Math.floor(eval(value)*scale);
		if(temp < 0){
			value *= -1;
		}
		return (value/scale);
	},

    // まるめ(切上)を行う
	// 引数 value まるめ(切上)を行う値
	//		scale 桁合わせ用スケール
	marumeKiriage: function(value,scale){
		var temp = value;
		value = Math.abs(value);
		value = Math.ceil(eval(value)*scale);
		if(temp < 0){
			value *= -1;
		}
		return (value/scale);
	},

    // まるめ(四捨五入)を行う
	// 引数 value まるめ(四捨五入)を行う値
	//		scale 桁合わせ用スケール
	marumeRound: function(value,scale){
		var temp = value;
		value = Math.abs(value);
		value = Math.round(eval(value)*scale);
		if(temp < 0){
			value *= -1;
		}
		return (value/scale);
	},

    // スケール算出(まるめ処理に使用)
	// 引数 keta 桁数
	//		return スケール
	getScale: function(keta){
		var scale=1;
		if(keta < 0){
			for(var i=keta; i<0; i++)scale /= 10;
		} else {
			for(var i=0; i<keta; i++)scale *= 10;
		}
		return scale;
	},

    // まるめ処理
	// 引数 value まるめ処理を行う値
	//		keta 桁数 潤ｵ -2:10の位, -1:1の位,1:小数点第一位, 2:小数点第二位 潤ｵ
	//		syori 処理NO(1:四捨五入 2:切上げ 3:切捨て)
	//		return 結果
	marume: function(value,keta,syoriNo){
		var ans = 0.0;
		var scale = 1;
		if(keta >= 0)keta -= 1;

		// 誤差修正処理
		value = this.errorCorrect(value);
		// 桁合わせ用スケール
		scale = this.getScale(keta);

		ans = value;

		switch (eval(syoriNo)) {
		case  1:
	            ans = this.marumeRound(eval(value),eval(scale));
	            break;
	    case  2:
	            ans = this.marumeKiriage(eval(value),eval(scale));
	            break;
	    case  3:
	            ans = this.marumeKirisute(eval(value),eval(scale));
	            break;
	    default:
	            break;
	    }
	    // 誤差修正処理
	    ans = this.errorCorrect(ans);

    	return ans;
	},

    // 消費税額取得
	// 引数 value 税抜金額
	//		rate 税率
	//		rateFlg  内税外税フラグ(1:外税 2:内税)
	//		hasuuFlg 端数調整フラグ(1:四捨五入 2:切上げ 3:切捨て)
	//      keta 桁数 潤ｵ -2:10の位, -1:1の位,1:小数点第一位, 2:小数点第二位 潤ｵ
	//		return 計算後の消費税額
	getSyouhizeigaku: function(value,rate,rateFlg,hasuuFlg,keta){
		var syouhizeigaku = 0;

		// 誤差修正処理
		value = this.errorCorrect(value);

		rate /= 100;
		if(rateFlg == 1){
			syouhizeigaku = this.marume(value*rate,keta,hasuuFlg);
		} else if(rateFlg == 2) {
			syouhizeigaku = this.marume(eval(value/(1+eval(rate))*eval(rate)),keta,eval(hasuuFlg));
		}
		syouhizeigaku = this.errorCorrect(syouhizeigaku);
		return syouhizeigaku;
	},

    // 本体金額取得
	// 引数 value 税抜金額
	//		rate 税率
	//		rateFlg  内税外税フラグ(1:外税 2:内税)
	//		hasuuFlg 端数調整フラグ(1:四捨五入 2:切上げ 3:切捨て)
	//      keta 桁数 潤ｵ -2:10の位, -1:1の位,1:小数点第一位, 2:小数点第二位 潤ｵ
	//		return 計算後の本体金額
	getHontaigaku: function(value,rate,rateFlg,hasuuFlg,keta){
		var hontaigaku = 0;

		// 誤差修正処理
		value = this.errorCorrect(value);

		if(rateFlg == 1){
			hontaigaku = value;
		} else if(rateFlg == 2) {
			hontaigaku = value - this.getSyouhizeigaku(value,rate,rateFlg,eval(hasuuFlg),keta);
		}
		hontaigaku = this.errorCorrect(hontaigaku);
		return hontaigaku;
	},

    // 率計算処理
	// 引数 value 金額
	//		rate 率 (%)
	//		marumeFlg まるめ単位フラグ(0:まるめを行わない, 1:1, 2:10, 3:100, 4:1000)
	//		hasuuFlg 端数調整フラグ(1:四捨五入 2:切上げ 3:切捨て)
	//		return 率計算後の数値
	calRate: function(value,rate,marumeFlg,hasuuFlg){
		var result = 0;

		// 誤差修正処理
		value = this.errorCorrect(value);
		rate /= 100;
		if(marumeFlg > 0){
			if(marumeFlg > 1){
				marumeFlg = eval(marumeFlg*(-1))+1;
			}
			result = this.marume(value*rate,eval(marumeFlg),eval(hasuuFlg));
			result = this.errorCorrect(result);
		} else {
			result = this.errorCorrect(value*rate);
		}
		return result;
	},

	// Method calGetRateValue.
	// val2に対するval1の割合(％)を算出する。
	// 不正なフラグデータなどが代入された場合はNULLを返します
	// @param val1 割合を求めたい数値
	// @param val2 基となる数値
	// @param keta 少数点以下の桁数(0未満を入力した場合はNULLが返ります。)
	// @param hasuuFlg (1:四捨五入 2:切上げ 3:切捨て)
	// @return val2に対するval1の割合(％)
	calGetRateValue: function( val1, val2, keta, hasuuFlg ){
	    var ZERO	= 0;

        //val1,val2が0の時
		if( val1 == ZERO || val2 == ZERO ) return ZERO;

		//scaleが0未満の場合はNULLを返す。
		if( keta < 0 ) return null;

		//端数フラグが範囲外の場合はNULLを返す。
		if( hasuuFlg < 1 || hasuuFlg > 3 ) return null;

		//％表記なので100倍する
		var ans = ( val1 / val2 ) * 100;

        return this.marume( ans, keta, hasuuFlg );
	},

    // 誤差修正処理
	// 引数 value 誤差修正したい数値
	//		return 修正後の数値
	errorCorrect: function(a) {
	    var x = "" + a;
	    var m = 0;
	    var e = x.length;
	    for (var i = 0; i < x.length; i++) {
	        var c = x.substring(i, i + 1);
	        if (c >= "0" && c <= "9") {
	            if (m == 0 && c == "0") {
	            } else {
	                m++;
	            }
	        } else if (c == " " || c == "+" || c == "-" || c == ".") {
	        } else if (c == "E" || c == "e") {
	            e = i;
	            break;
	        } else {
	            return a;
	        }
	    }

	    var b = 1.0 / 3.0;
	    var y = "" + b;
	    var q = y.indexOf(".");
	    var n;
	    if (q >= 0) {
	        n = y.length - (q + 1);
	    } else {
	        return a;
	    }

	    if (m < n) {
	        return a;
	    }

	    var p = x.indexOf(".");
	    if (p == -1) {
	        return a;
	    }
	    var w = " ";
	    for (var i = e - (m - n) - 1; i >= p + 1; i--) {
	        var c = x.substring(i, i + 1);
	        if (i == e - (m - n) - 1) {
	            continue;
	        }
	        if (i == e - (m - n) - 2) {
	            if (c == "0" || c == "9") {
	                w = c;
	                continue;
	            } else {
	                return a;
	            }
	        }
	        if (c != w) {
	            if (w == "0") {
	                var z = (x.substring(0, i + 1) + x.substring(e, x.length)) - 0;
	                return z;
	            } else if (w == "9") {
	                var z = (x.substring(0, i) + ("" + ((c - 0) + 1)) + x.substring(e, x.length)) - 0;
	                return z;
	            } else {
	                return a;
	            }
	        }
	    }
	    if (w == "0") {
	        var z = (x.substring(0, p) + x.substring(e, x.length)) - 0;
	        return z;
	    } else if (w == "9") {
	        var z = x.substring(0, p) - 0;
	        var f;
	        if (a > 0) {
	            f = 1;
	        } else if (a < 0) {
	            f = -1;
	        } else {
	            return a;
	        }
	        var r = (("" + (z + f)) + x.substring(e, x.length)) - 0;
	        return r;
	    } else {
	        return a;
	    }
	}

};
