/*
  Scientific calculator with 26 variables/memories (A-Z) and expression evaluator.
  Use as calculator with up to 26 memories or as expression evaluator with 26 variables.
  All variables are upper case.
  Type an expression in the Expression field using standard Javascript syntax including variables A-Z.
  When using the Javascript Math object either always specify Math. or never specify it (it
  will be filled in for you. If you do not use Math. and you wish to use the E constant specify
  EU to avoid conflict with variable E.
  After entering an expression, set the variables and press Run.
  The result will appear in the calculator display box.
  You can then change the variables to obtain more results.
  Useful for what-if scenarios.
  You can assign values to variables and can use multi statement expressions.
  The last statement should not be an assign, unless you want a variable to receive the result
  instead of displaying it in the display box.
  E.G. Canadian mortgage payments:
  inputs - R = interest rate per annum (e.g. 5.00)
           T = term in years (e.g. 25)
           P = principal (e.g. 100000.00)
  Note that this uses an interim variable I
  I=pow((1+R/200),(1/6))-1;P*I/(1-pow((1+I),-(T*12)))
  Result should be 581.60....
  E.G. US mortgage payments:
  inputs - R = interest rate per annum (e.g. 5.00)
           T = term in years (e.g. 25)
           P = principal (e.g. 100000.00)
  Note that this uses an interim variable I
  I=R/1200;P*I/(1-pow((1+I),-(T*12)))
  Result should be 584.59....
*/
cv = "";
dv = "";
con = false;
op1 = "";
adding = "";
tape = "";
A=0;
B=0;
C=0;
D=0;
E=0;
F=0;
G=0;
H=0;
I=0;
J=0;
K=0;
L=0;
M=0;
N=0;
O=0;
P=0;
Q=0;
R=0;
S=0;
T=0;
U=0;
V=0;
W=0;
X=0;
Y=0;
Z=0;
Result = 0;
dorr = "R";
cb = 10;
ValChars = "0123456789ABCDEF";
Alphas = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Value10 = 0;
decs = -1;
d0 = true;
nakedfuncs = new Array("abs", "acos", "asin", "atan", "atan2", "cail", "cos", "exp", "floor", "log", "max", "min", "pow", "random", "round", "sin", "sqrt", "tan");
nakedcons = new Array("EU", "LN2", "LOG", "LOG2E", "LOG10E", "PI", "SQRT1_2", "SQRT2");
function ChangeBase(CurBase, NewBase, val)
{
var BaseStr;
var BStr;
var CVal;
var NumStr;
var i, j, sl;

    decs = -1;
    Value10 = 0;
    NumStr = "" + val;
    sl = NumStr.length;
    for (i=0;i<sl;i++) {
        if (NumStr.charAt(i) == ".") decs++; else {        
      	    j = ValChars.indexOf(NumStr.charAt(i));
            if (j < CurBase) {
                if (decs > -1) decs++;
            	Value10 = Value10 * CurBase + j;
            } else {
                alert("\nYou have entered an invalid value.");
                Value10 = 0;
                val = "";
                break;
            }
        }
    }
    while (decs > 0 && decs < 8) {
        Value10 = Value10 * 10;
        decs++;
    }
    BaseStr = "";
    BStr = "";
    CVal = Value10;
    for (i=0;i < decs;i++) CVal = CVal * NewBase / CurBase;
    d0 = true;
    while (CVal >= 1) {
        if (decs == 0) {
            BStr = "." + BaseStr;
            BaseStr = BStr;
            decs = -1;
        } else {
            d0 = false;
            BStr = ValChars.charAt(CVal % NewBase) + BaseStr;
            BaseStr = BStr;
            CVal = CVal / NewBase;
            if (decs > 0) decs--;
        }
    }
    if (BaseStr == "") BaseStr = "0";
    val = BaseStr;
    return(BaseStr);
}

function calcit() {

   if (dv == "") dv="0";
   if (cb != 10) dv = ChangeBase(cb, 10, dv);
   cv = cv + dv + adding;
   dv = eval(cv);
   cv = "";
   con = true;
   adding = "";
   if (cb != 10) dv = ChangeBase(10, cb, dv);
   document.calc.disp.value = dv;   
   tape += '=';
}

function setnum(n) {

    dv = n + adding;
    adding = "";
    document.calc.disp.value = dv;
    tape += n;
}

function chsign() {

    dv = - dv;
    document.calc.disp.value = dv;
    tape += '+/-';

}

function addnum(n) {
   if (con) {
       con = false;
       dv = "";
   }
   if (n == "." || n == "(" || n == ")" || ValChars.indexOf(n) < cb) {
	if (dv == "0") dv = "";
	dv = dv + n;
   	document.calc.disp.value = dv;
   }
   tape += n;
}

function subnum() {

    if (dv.length > 0) {
        dv = dv.substring(0,dv.length-1);
    }
    document.calc.disp.value = dv;
    tape.length--; 
}

function addop(n) {
    
    if (cb != 10) dv = ChangeBase(cb, 10, dv);
    if (dv == "") return;
    if (n == "^") {
        cv = cv + "Math.pow(" + dv + ",";
        adding = ")";
    } else {
        cv = cv + dv + adding + n;
        adding = "";
    }
    dv = "";
    tape += n;
}

function factorial(n) {
var res;
 
    for (res=1;n>1;n--) res = res * n;
    tape += 'n!';
    return (res);
}

function dofunc(n) {

    if (cb != 10) dv = ChangeBase(cb, 10, dv);
    if (dv == "") return; 
    if ((n < 4) && (dorr == "D")) dv = dv * Math.PI / 180;
    if (n == 1) { dv = Math.sin(dv); tape += 'SIN'; }
    if (n == 2) { dv = Math.cos(dv); tape += 'COS'; }
    if (n == 3) { dv = Math.tan(dv); tape += 'TAN'; }
    if (n == 4) { dv = Math.log(dv); tape += 'LN'; }
    if (n == 5) { dv = Math.LOG10E * Math.log(dv); tape += 'LOG'; }
    if (n == 6) { dv = factorial(Math.floor(dv)); tape += 'n!'; } 
    if (n == 7) { dv = 1 / dv; tape += '1/x'; }
    if (n == 8) { dv = Math.asin(dv); tape += 'ASIN'; }
    if (n == 9) { dv = Math.acos(dv); tape += 'ACOS'; }
    if (n == 10) { dv = Math.atan(dv); tape += 'ATAN'; }
    if (n == 11) { dv = Math.sqrt(dv); tape += 'SQRT'; }
    if ((n > 7) && (n < 11) && (dorr == "D")) dv = dv * 180 / Math.PI;
    con = true;
    if (cb != 10) dv = ChangeBase(10, cb, dv);
    document.calc.disp.value = dv;
}

function clearall() {
   cv = "";
   dv = "";
   document.calc.disp.value = dv;
   tape += 'C';
}

function clearentry() {
   dv = "";
   document.calc.disp.value = dv;
   tape += 'CE';
}

function clrmem() {

    
    var s = Alphas.charAt(document.calc.vars.value) + " = 0";
    eval(s);
    showmem();
    tape += 'MC(' + document.calc.vars.value + ')';
}

function rclmem() {

    var s = Alphas.charAt(document.calc.vars.value);
    setnum(eval(s));
    tape += 'MR(' + document.calc.vars.value + ')';
}

function strmem() {

    var s = Alphas.charAt(document.calc.vars.value) + "= dv*1";
    eval(s);
    showmem();
    cv = "";
    con = true;
    adding = "";
    tape += 'MS(' + document.calc.vars.value + ')';
}

function addmem() {

    var s = Alphas.charAt(document.calc.vars.value) + " += dv*1";
    eval(s);
    showmem();
    tape += 'M+(' + document.calc.vars.value + ')';
}

function settrig(v) {

    dorr = v;
    if (v == 'R') tape += 'RAD'; else tape += 'DEG';
}

function setbase(b) {

    if (b != cb) {
        dv = ChangeBase(cb, b, dv);
        cb = b;
    	if (dv == 0) dv = "";
    	document.calc.disp.value = dv;
        con = true;
    }
    tape += 'BASE(' + b + ')';
}

function evalit() {

    var s = document.calc.xdisp.value;
    if (s == "") s = "0";
    if (s.indexOf("Math.") == -1) {
      for (i=0;i<nakedfuncs.length;i++) 
        s = s.replace(new RegExp(nakedfuncs[i],"g"),"Math." + nakedfuncs[i]);
      for (i=0;i<nakedcons.length;i++) 
        s = s.replace(new RegExp(nakedcons[i],"g"),"Math." + nakedcons[i]);
      s = s.replace(/Math.EU/g, "Math.E");
    }
//    if (s.indexOf("Result") == -1) s = "Result=" + s;
    dv = eval(s);
    cv = "";
    con = true;
    adding = "";
    document.calc.disp.value = dv;//Result;
    tape += 'RUN(' + document.calc.xdisp.value + ')';
}

function showmem() {

  document.getElementById("vimg").innerHTML = eval(Alphas.charAt(document.calc.vars.value));
}

function showtape() {

  alert(tape);      
}

function Calc() {

  var rep = document.getElementById("calcdiv");
  var h = '<div id="calc"><h2>Calculator</h2>';
  h += '<form name="calc">';
  h += '<table cols="8" class="tab" id="ctable">';
  h += '<tr><td colspan="8" class="cpartx"><input type="text" id="cval" readonly name="disp"></td></tr>';
  h += '<tr><td colspan="8" class="cpartx" ';
  h += '<input type="radio" name="angle" checked="true" onClick="settrig('+ "'R'" + ')">Radians';
  h += '<input type="radio" name="angle" onClick="settrig('+ "'D'" + ')">Degrees</td></tr>';
  h += '<tr><td class="cpartx" colspan="8" ';
  h += '<input type="radio" name="base" onClick="setbase(2)">Binary';
  h += '<input type="radio" name="base" onClick="setbase(8)">Octal';
  h += '<input type="radio" name="base" checked="true" onClick="setbase(10)">Decimal';
  h += '<input type="radio" name="base" onClick="setbase(16)">Hex</td></tr>';
  h += '<tr><td class="cpart tkey" onclick="dofunc(8)">asin</td>';
  h += '<td class="cpart tkey" onclick="dofunc(1)">sin</td>';
  h += '<td class="cpart ckey" onclick="setnum(Math.PI)">PI</td>';
  h += '<td class="cpart nkey" onclick="addnum(7)">7</td>';
  h += '<td class="cpart nkey" onclick="addnum(8)">8</td>';
  h += '<td class="cpart nkey" onclick="addnum(9)">9</td>';
  h += '<td class="cpart ckey" onclick="addop(' + "'/'" + ')">/</td>';
  h += '<td class="cpart vkey" onclick="clearall()">C</td></tr>';
  h += '<tr><td class="cpart tkey" onclick="dofunc(9)">acos</td>';
  h += '<td class="cpart tkey" onclick="dofunc(2)">cos</td>';
  h += '<td class="cpart ckey" onclick="dofunc(4)">ln</td>';
  h += '<td class="cpart nkey" onclick="addnum(4)">4</td>';
  h += '<td class="cpart nkey" onclick="addnum(5)">5</td>';
  h += '<td class="cpart nkey" onclick="addnum(6)">6</td>';
  h += '<td class="cpart ckey" onclick="addop(' + "'*'" + ')">*</td>';
  h += '<td class="cpart vkey" onclick="clearentry()">CE</td></tr>';
  h += '<tr><td class="cpart tkey" onclick="dofunc(10)">atan</td>';
  h += '<td class="cpart tkey" onclick="dofunc(3)">tan</td>';
  h += '<td class="cpart ckey" onclick="dofunc(5)">log</td>';
  h += '<td class="cpart nkey" onclick="addnum(1)">1</td>';
  h += '<td class="cpart nkey" onclick="addnum(2)">2</td>';
  h += '<td class="cpart nkey" onclick="addnum(3)">3</td>';
  h += '<td class="cpart ckey" onclick="addop(' + "'-'" + ')">-</td>';
  h += '<td class="cpart ckey" onclick="addnum(' + "'('" + ')">(</td></tr>';
  h += '<tr><td class="cpart tkey" onclick="dofunc(11)">sqrt</td>';
  h += '<td class="cpart ckey" onclick="addop(' + "'^'" + ')">x^y</td>';
  h += '<td class="cpart ckey" onclick="dofunc(6)">n!</td>';
  h += '<td class="cpart ckey" onclick="dofunc(7)">1/X</td>';
  h += '<td class="cpart nkey" onclick="addnum(0)">0</td>';
  h += '<td class="cpart ckey" onclick="addnum(' + "'.'" + ')">.</td>';
  h += '<td class="cpart ckey" onclick="addop(' + "'+'" + ')">+</td>';
  h += '<td class="cpart ckey" onclick="addnum(' + "')'" + ')">)</td></tr>';
  h += '<tr><td class="cpart nkey" onclick="addnum(' + "'A'" + ')">A</td>';
  h += '<td class="cpart nkey" onclick="addnum(' + "'B'" + ')">B</td>';
  h += '<td class="cpart nkey" onclick="addnum(' + "'C'" + ')">C</td>';
  h += '<td class="cpart nkey" onclick="addnum(' + "'D'" + ')">D</td>';
  h += '<td class="cpart nkey" onclick="addnum(' + "'E'" + ')">E</td>';
  h += '<td class="cpart nkey" onclick="addnum(' + "'F'" + ')">F</td>';
  h += '<td class="cpart ckey" onclick="chsign()">+/-</td>';
  h += '<td class="cpart cckey" onclick="subnum()"><-</td></tr>';
  h += '<tr><td colspan="2" class="cpart varkey">Var ';
  h += '<select name="vars" onchange="showmem()"><option value=0>A</option><option value=1>B</option>';
  h += '<option value=2>C</option><option value=3>D</option><option value=4>E</option>';
  h += '<option value=5>F</option><option value=6>G</option><option value=7>H</option>';
  h += '<option value=8>I</option><option value=9>J</option><option value=10>K</option>';
  h += '<option value=11>L</option><option value=12>M</option><option value=13>N</option>';
  h += '<option value=14>O</option><option value=15>P</option><option value=16>Q</option>';
  h += '<option value=17>R</option><option value=18>S</option><option value=19>T</option>';
  h += '<option value=20>U</option><option value=21>V</option><option value=22>W</option>';
  h += '<option value=23>X</option><option value=24>Y</option><option value=25>Z</option>';
  h += '</select><div id="vimg" class="vikey"></div>';
  h += '</td>';
  h += '<td class="cpart mkey" onclick="clrmem()">Clr</td>';
  h += '<td class="cpart mkey" onclick="rclmem()">Rcl</td>';
  h += '<td class="cpart mkey" onclick="strmem()">Str</td>';
  h += '<td class="cpart mkey" onclick="addmem()">Add</td>';
  h += '<td colspan="2" class="cpart ckey" onclick="calcit()">=</td></tr>';
  h += '<tr><td colspan="7" class="cpartx">Expression:<input type="text" id="xval" name="xdisp"></td><td class="cpart ckey" onclick="evalit()">Run</td></tr>';
  
  h += '</table></form></div>';
  rep.innerHTML = h;
  showmem();
  
}