var NDIGITS = 16;
var STACKSIZE = 12;
var value = 0;
var level = 0;
var entered = true;
var decimal = 0;
var fixed = 0;
var exponent = false;
function stackItem()
{
 this.value = 0;
 this.op = "";
}
function array(length)
{
  this[0] = 0;
  for (i=0; i<length; ++i)
  {
    this[i] = 0;
    this[i] = new stackItem();
  }
  this.length = length;
}
stack = new array(STACKSIZE);
function push(value,op,prec)
{
  if (level==STACKSIZE)
                 return false;
  for (i=level;i>0; --i)
  {
    stack[i].value = stack[i-1].value;
    stack[i].op = stack[i-1].op;
    stack[i].prec = stack[i-1].prec;
  }
  stack[0].value = value;
  stack[0].op = op;
  stack[0].prec = prec;
  ++level;
  return true;
}
function pop()
{
  if (level==0)
  return false;
  for (i=0;i<level; ++i)
  {
    stack[i].value = stack[i+1].value;
    stack[i].op = stack[i+1].op;
    stack[i].prec = stack[i+1].prec;
  }
  --level;
  return true;
}
function format(value)
{
  var valStr = "" + value;
  if (valStr.indexOf("N")>=0 || (value == 2*value && value == 1+value))
    return "Error ";
  var i = valStr.indexOf("e")
  if (i>=0)
  {
    var expStr = valStr.substring(i+1,valStr.length);
    if (i>NDIGITS-5) i=NDIGITS-5;
    valStr = valStr.substring(0,i);
    if (valStr.indexOf(".")<0) valStr += ".";
    valStr += " " + expStr;
  } else {
    var valNeg = false;
    if (value < 0) { value = -value; valNeg = true; }
    var expval = Math.log(value)*Math.LOG10E;
    if (value == 0) {
      expval = 0;
    } else if (expval > NDIGITS-5) {
      expval = Math.floor(expval);
      value /= Math.pow(10, expval);
    } else if (-expval > NDIGITS-5) {
      expval = Math.ceil(expval);
      value /= Math.pow(10, expval);
    } else {
      expval = 0;
    }
    var valInt = Math.floor(value);
    var valFrac = value - valInt;
    var prec = NDIGITS - (""+valInt).length - 1;
    if (prec < 0) return "Error"
    if (! entered && fixed>0)
      prec = fixed;
    var mult = " 1000000000000000000".substring(1,prec+2);
    var frac = Math.floor(valFrac * mult + 0.5);
    valInt = Math.floor(Math.floor(value * mult + .5) / mult);
    if (valNeg)
      valStr = "-" + valInt;
    else
      valStr = "" + valInt;
    var fracStr = "00000000000000"+frac;
    fracStr = fracStr.substring(fracStr.length-prec, fracStr.length);
    i = fracStr.length-1;
    if (entered || fixed==0)
    {
      while (i>=0 && fracStr.charAt(i)=="0")
       --i;
      fracStr = fracStr.substring(0,i+1);
    }
    if (i>=0) valStr += "." + fracStr;
    if (expval != 0) {
      var expStr = "" + expval;
      valStr += " " + expStr;
    }
  }
  return valStr;
}
function refresh()
{
  var display = format(value);
  if (exponent)
  {
    if (expval<0)
       display += " " + expval;
    else
       display += " +" + expval;
  }
  if (display.indexOf(".")<0 && display != "Error ")
  {
    if (entered || decimal>0)
      display += '.';
    else
      display += ' ';
  }
  display = "               " + display;
  display = display.substring(display.length-NDIGITS-1,display.length);
  document.calculator.result.value = display;
}
function clearDisp()
{
  exponent = false;
  value = 0;
  enter();
  refresh();
}
function clearAll()
{
  level = 0;
  clearDisp();
}
function evalx()
{
  if (level==0)
    return false;
  op = stack[0].op;
  sval = stack[0].value;
  if (op == "+")
    value = sval + value;
  else if (op == '-')
    value = sval - value;
  else if (op == '*')
    value = sval * value;
  else if (op == '/')
    value = sval / value;
  else if (op == 'pow')
    value = Math.pow(sval,value);
  pop();
  if (op=='(')
    return false;
  return true;
}
function openp()
{
  enter();
  if (!push(0,'(',0))
    value = "NAN";
  refresh();
}
function closep()
{
  enter();
  while (evalx()) ;
  refresh();
}
function operator(op)
{
  enter();
  if (op=='+' || op=='-')
    prec = 1;
  else if (op=='*' || op=='/')
    prec = 2;
  else if (op=="pow")
    prec = 3;
  if (level>0 && prec <= stack[0].prec)
     evalx();
  if (!push(value,op,prec))
    value = "NAN";
  refresh();
}
function enter()
{
  if (exponent)
    value = value * Math.exp(expval * Math.LN10);
  entered = true;
  exponent = false;
  decimal = 0;
  fixed = 0;
}
function equals()
{
  enter()
  while (level>0)
    evalx();
  refresh();
}
function digit(n)
{
  if (entered)
  {
    value = 0;
    digits = 0;
    entered = false;
  }
  if (n==0 && digits==0)
  {
    refresh();
    return;
  }
  if (exponent)
  {
    if (expval<0)
       n = -n;
    if (digits < 3)
    {
      expval = expval * 10 + n;
      ++digits;
      refresh();
    }
    return;
  }
  if (value<0)
    n = -n;
  if (digits < NDIGITS-1)
  {
    ++digits;
    if (decimal>0)
   {
     decimal = decimal * 10;
     value = value + (n/decimal);
     ++fixed;
   }
   else
     value = value * 10 + n;
  }
  refresh();
}
function bksp()
{
  if (entered)
  {
    refresh();
    return;
  }
  if (digits==0)
  {
    refresh();
    return;
  }
  if (exponent)
  {
    if (expval<0)
      expval = -Math.floor(-expval/10);
    else
      expval = Math.floor(expval/10);
    --digits;
    refresh();
     return;
  }
  if (decimal>1)
  {
    if (value<0)
      value = -Math.floor(-value*decimal/10);
    else
      value = Math.floor(value*decimal/10);
    decimal = decimal / 10;
    value = value/decimal;
    --fixed;
    if (decimal == 1)
      decimal = 0;
  }
  else
  {
    if (value<0)
      value = -Math.floor(-value/10);
    else
      value = Math.floor(value/10);
    decimal = 0;
  }
  --digits;
  refresh();
}
function sign()
{
  if (exponent)
    expval = -expval;
  else
    value = -value;
  refresh();
}
function period()
{
  if (entered)
  {
    value = 0;
    digits = 1;
  }
  entered = false;
  if (decimal == 0)
    decimal = 1;
  refresh();
}
function exp()
{
  if (entered || exponent)
    return;
  exponent = true;
  expval = 0;
  digits = 0;
  decimal = 0;
  refresh();
}
function func(f)
{
  enter();

  if (f=="1/x")
  {
    value = 1/value;
  }
  else if (f=='n!')
  {
    if (value<0 || value>200 || value != Math.round(value))
      value = "NAN";
    else
    {
      var n = 1;
      var i;
      for (i=1;i<=value;++i)
        n *= i;
      value = n;
    }
  }
  else
  {
    if (f=="sin")
      value = Math.sin(value/180 * Math.PI);
    else if (f=="cos")
      value = Math.cos(value/180 * Math.PI);
    else if (f=="tan")
      value = Math.tan(value/180 * Math.PI);
    else if (f=="log")
      value = Math.log(value)/Math.LN10;
    else if (f=="log2")
      value = Math.log(value)/Math.LN2;
    else if (f=="ln")
      value = Math.log(value);
    else if (f=="sqrt")
      value = Math.sqrt(value);
    else if (f=="pi")
      value = Math.PI;
    else if (f=="asin")
      value = Math.asin(value)*180/Math.PI;
    else if (f=="acos")
      value = Math.acos(value)*180/Math.PI;
    else if (f=="atan")
      value = Math.atan(value)*180/Math.PI;
    else if (f=="alog")
      value = Math.exp(value * Math.LN10);
    else if (f=="alog2")
      value = Math.exp(value * Math.LN2);
    else if (f=="exp")
      value = Math.exp(value);
    else if (f=="sqr")
      value = value*value;
    else if (f=="e")
      value = Math.E;
  }
   refresh();
}
