/* Calc.js
 *
 * Date:    2007/07/01
 * Author:    Poturi
 * Description:
 * 12-digit Desktop Calculator.
 *
 * Copyright (c) 2008 Poturi, All Rights Reserved.
 * http://www.poturi.net/
 *
 * ソースコードの改変・再頒布は自由ですが、
 * その際はこのCopyrightを明記してください。
 * 商用利用は不可です。
 */

/* Calcコンストラクタ
 * ------------------------------------
 * 全プロパティを初期化する
 *
 */
function Calc() {
    this.mode = "num";  // 入力モード（数値はnum、演算子類はope）
    this.num = 0;       // 入力値
    this.ope = "plus";  // 演算子
    this.result = 0;    // 計算結果
}

/* set_display()メソッド
 * ------------------------------------
 * 計算結果を12桁に整形してから画面表示を更新する
 *
 */
Calc.prototype.set_display = function(arg) {
    var num = "" + arg;
    if (num.match(/\./)) {
        if (num.match(/-/)) {
            if (num.length >= 15) { num = num.slice(0,14); }
        }
        else {
            if (num.length >= 14) { num = num.slice(0,13); }
        }
    }
    else {
        if (num.match(/-/)) {
            if (num.length >= 14) { num = num.slice(0,13); }
        }
        else {
            if (num.length >= 13) { num = num.slice(0,12); }
        }
    }
    var text = document.createTextNode(num);
    var display = document.getElementById("display");
    if (display.hasChildNodes()) {
        display.replaceChild(text, display.firstChild);
    }
    else {
        display.appendChild(text);
    }
}

/* set_num()メソッド
 * ------------------------------------
 * ユーザインターフェイスからの数値入力を処理する
 *
 */
Calc.prototype.set_num = function(n) {
    switch (this.mode) {
        case "ope":
            this.mode = "num";
            if (n) { this.num = "" + n; }
            else { this.num = 0; }
            break;
        case "num":
            if (!this.num) {
                if (n) { this.num = "" + n; }
            }
            else if (this.num.match(/\./)) {
                if (this.num.length <= 12) { this.num += n; }
                else { }
            }
            else {
                if (this.num.length <= 11) { this.num += n; }
                else { }
            }
            break;
        default:
            break;
    }
    this.set_display(this.num);
}

/* set_dot()メソッド
 * ------------------------------------
 * ユーザインターフェイスからの小数点入力を処理する
 *
 */
Calc.prototype.set_dot = function() {
    switch (this.mode) {
        case "ope":
            this.mode = "num";
            this.num = "0.";
            break;
        case "num":
            if (!this.num) { this.num = "0."; }
            else {
                if (!this.num.match(/\./)) {
                    if (this.num.length <= 11) { this.num += "."; }
                    else { }
                }
            }
            break;
        default:
            break;
    }
    this.set_display(this.num);
}

/* set_ope()メソッド
 * ------------------------------------
 * ユーザインターフェイスからの演算子入力を処理する
 *
 */
Calc.prototype.set_ope = function(arg) {
    switch (this.mode) {
        case "num":
            if (arg == "sqrt") {
                this.ope = arg;
                this.result = this.compute();
                this.set_display(this.result);
                this.num = this.result;
                this.mode = "ope";
            }
            else if (arg == "percent") {
                if (this.ope == "multiply") {
                    this.result = (this.compute() / 100);
                    this.set_display(this.result);
                }
            }
            else {
                this.mode = "ope";
                this.result = this.compute();
                this.set_display(this.result);
                if (arg != "equal") { this.ope = arg; }
            }
            break;
        case "ope":
            if (arg == "equal") {
                this.result = this.compute();
                this.set_display(this.result);
                if (this.ope == "sqrt") { this.num = this.result; }
            }
            else {
                this.ope = arg;
                this.num = this.result;
                if (arg == "sqrt") {
                    this.result = this.compute();
                    this.set_display(this.result);
                    this.num = this.result;
                }
            }
            break;
        default:
            break;
    }
}

/* compute()メソッド
 * ------------------------------------
 * 入力値を演算する
 *
 */
Calc.prototype.compute = function() {
    this.num = this.num -0;
    switch (this.ope) {
        case "plus":
            this.result += this.num;
            return this.check_num(this.result);
            break;
        case "minus":
            this.result -= this.num;
            return this.check_num(this.result);
            break;
        case "multiply":
            this.result *= this.num;
            return this.check_num(this.result);
            break;
        case "divide":
            this.result /= this.num;
            return this.check_num(this.result);
            break;
        case "sqrt":
            this.result = Math.sqrt(this.num);
            return this.check_num(this.result);
            break;
        case "equal":
            return this.check_num(this.result);
            break;
        default:
            break;
    }
}

/* check_num()メソッド
 * ------------------------------------
 * 数値が12桁を超えていないかチェックする
 * 数値にeが含まれる場合もoverflowにする
 */
Calc.prototype.check_num = function(arg) {
    if (arg) {
        var arg_str = "" + arg;
        if (arg_str.match(/e/) || arg >= 1000000000000) {
            return "Overflow";
        }
        else {
            return arg;
        }
    }
    else {
        return 0;
    }
}

/* clear()メソッド
 * ------------------------------------
 * CとCEボタンの処理
 * Cはオールクリア、CEは入力値のみクリア
 */
Calc.prototype.clear = function(arg) {
    switch (arg) {
        case "c":
            this.mode = "num";
            this.num = 0;
            this.ope = "plus";
            this.result = 0;
            break;
        case "ce":
            this.num = 0;
            break;
        default:
            break;
    }
    this.set_display(this.num);
}

/* prepare_calc()メソッド
 * ------------------------------------
 *  HTMLのonload時に呼び出す
 *
 */
Calc.prototype.prepare_calc = function() {
    if (!document.getElementById) { return false; }
    this.set_display(this.num);
    this.set_onclick();
}

/* set_onclick()メソッド
 * ------------------------------------
 * ボタンのonclick属性を設定する
 *
 */
Calc.prototype.set_onclick = function(arg) {
    var self = this;
    var zero = document.getElementById("zero").firstChild;
    var one = document.getElementById("one").firstChild;
    var two = document.getElementById("two").firstChild;
    var three = document.getElementById("three").firstChild;
    var four = document.getElementById("four").firstChild;
    var five = document.getElementById("five").firstChild;
    var six = document.getElementById("six").firstChild;
    var seven = document.getElementById("seven").firstChild;
    var eight = document.getElementById("eight").firstChild;
    var nine = document.getElementById("nine").firstChild;
    var dot = document.getElementById("dot").firstChild;
    var equal = document.getElementById("equal").firstChild;
    var plus = document.getElementById("plus").firstChild;
    var minus = document.getElementById("minus").firstChild;
    var multiply = document.getElementById("multiply").firstChild;
    var divide = document.getElementById("divide").firstChild;
    var percent = document.getElementById("percent").firstChild;
    var sqrt = document.getElementById("sqrt").firstChild;
    var c = document.getElementById("c").firstChild;
    var ce = document.getElementById("ce").firstChild;
    zero.onclick = function() { self.set_num(0); return false; };
    one.onclick = function() { self.set_num(1); return false; };
    two.onclick = function() { self.set_num(2); return false; };
    three.onclick = function() { self.set_num(3); return false; };
    four.onclick = function() { self.set_num(4); return false; };
    five.onclick = function() { self.set_num(5); return false; };
    six.onclick = function() { self.set_num(6); return false; };
    seven.onclick = function() { self.set_num(7); return false; };
    eight.onclick = function() { self.set_num(8); return false; };
    nine.onclick = function() { self.set_num(9); return false; };
    dot.onclick = function() { self.set_dot(); return false; };
    equal.onclick = function() { self.set_ope("equal"); return false; };
    plus.onclick = function() { self.set_ope("plus"); return false; };
    minus.onclick = function() { self.set_ope("minus"); return false; };
    multiply.onclick = function() { self.set_ope("multiply"); return false; };
    divide.onclick = function() { self.set_ope("divide"); return false; };
    percent.onclick = function() { self.set_ope("percent"); return false; };
    sqrt.onclick = function() { self.set_ope("sqrt"); return false; };
    c.onclick = function() { self.clear("c"); return false; };
    ce.onclick = function() { self.clear("ce"); return false; };
}

/* set_onkeydown()メソッド
 * ------------------------------------
 * キー入力を可能にする
 *
 */
Calc.prototype.set_onkeydown = function(e) {
    var keycode;
    if (e) { keycode = e.which; }
    else { keycode = event.keyCode; }
    if (!keycode) { return false; }
    switch (keycode) {
        case 48:
            this.set_num(0);
            break;
        case 49:
            this.set_num(1);
            break;
        case 50:
            this.set_num(2);
            break;
        case 51:
            this.set_num(3);
            break;
        case 52:
            this.set_num(4);
            break;
        case 53:
            this.set_num(5);
            break;
        case 54:
            this.set_num(6);
            break;
        case 55:
            this.set_num(7);
            break;
        case 56:
            this.set_num(8);
            break;
        case 57:
            this.set_num(9);
            break;
        case 190:
            this.set_dot();
            break;
        default:
            break;
    }
}
