//math stuff just to translate normal math to JavaScript!
//constants--don't change

    operators=" +-*/()[]^,!;="  //the ' ' here is important
   moperators=" /^,!;[]="       //because s.indexOf("") returns 0!
   coperators=" +()*"
     numerals=" 0123456789."
   
//customizable:

x=0
fixedmode=0
ndigits=5

function log(x){return Math.LOG10E*Math.log(x)}
function pH(x){return -Math.log(x)}

function lnfact(n)
{ 
 if (n<=highestfactorial)
 {
  return Math.log(fact(n))
 }else{  //Stirling's approximation!
  return n*Math.log(n)-n
 }
}


//globals that will be changed in functions:

   sthisop=""
   smath=""
   sresults=""
   testing=0
   nvars=0
   vlist=";"
   ulist=""
   havexyzs=0

 
//  REAL MATH TO JAVAMATH RULES

//  a) common terms will be converted: 
//      ln(x)==>Math.log(x)
//      log(x)==>(Math.LOG10E*Math.log(x))
//      sqr(x)==>Math.sqrt(x)
//  b) other functions such as abs and cos are straight conversions
//  c) x! evaluated using function here: fact(x) 
//  d) ln(x!) evaluated either exactly (x<170) or using approx (x ln(x) - x)
//  e) ')('==>')*(' ONLY when non-chem operators or chem is as 'MW()'!

//     NOTE!   trailing ' ' is necessary!
//    '|' will be replaced by 'Math.'
//     note that '`' will be ')' closing AFTER next () phrase

 funcabbrs="|log           |sqr  |ln   "
 functions="(|LOG10E*|log` |sqrt |log  "
 morefuncs="|abs |acos |asin |atan |cos |ceil |exp |floor |max |min |pow |random |round |sin |sqrt |tan "  
 myfunctions="()log()pH()fact()lnfact"

 constants="|e |ln10 |ln2 |log10e |pi |sqrt1_2 |sqrt2 "

//non-built in n! and ln(n!)

highestfactorial=170

function fact(nin)
{
 var n=Math.floor(nin)
 var nout=1
 if (n<0){Alert("Can't take log of a negative number!");return 0}
 if (n<=highestfactorial)
 {
  for(var i=2;i<=n;i++){nout=nout*i}
 }else{
  alert(n+"! is too large. You can take the log of this factorial, but not the factorial itself. Returning 0")
  nout=0
 }
 return nout
}

function math(stin,dovlist)  //cleans math; uses smath, sthisop
{ 
 smath=mathclean(stin)    
 var ipt=0
 var i=0
 var s=""
 var doreclean=0
 var snew=" "
 var swhat=""
 var svar=""
 if(testing)alert("math processing: "+smath+" "+vlist)
 while (smath.length!=0)
 {
  swhat=tokenof(1)  
  if (testing) alert("checking "+swhat+" "+sthisop+" "+smath) 
  svar=(numerals.indexOf(swhat.charAt(0))>0?"":swhat)
  if (swhat.length==0 && numerals.indexOf(smath.charAt(0))>0)
  {
   if (sthisop=="-" || sthisop=="+")
   {
    swhat=sthisop
    swhat+=tokenof(1)
   }
  }
  if (sthisop.length>0)
  {
   if (sthisop=="^")
   {
    if(smath.charAt(0)=="(")
    {
     s=ptokenof()
    }else{
     s=tokenof(0)
    }
    if (swhat.length==0)
    {
     ipt=findparen(snew,snew.length-1,-1)
     swhat=snew.substring(ipt,snew.length)
     snew=snew.substring(0,ipt)
    }
    swhat="(Math.pow("+swhat+","+s+"))"
    svar=""
    doreclean=1
    sthisop=""
   }
   if (sthisop=="!")
   { 
    if (snew.charAt(snew.length-1)==")")
    {
     ipt=findparen(snew,snew.length-1,-1)
     snew=snew.substring(0,ipt)+"(fact"+snew.substring(ipt,snew.length)+")"
     swhat=""
     sthisop=""
    }else{
     snew+="fact(" 
     sthisop=")"
    }
   }
   if (sthisop=="(")
   {
    var sv0=svar
    svar=""
    if (swhat.length>0)
    {
      var i=funcabbrs.indexOf("|"+swhat.toLowerCase()+" ")
      if (i>=0)
      {
       swhat=functions.substring(i,i+20)
       swhat=swhat.substring(0,swhat.indexOf(" ")) 
      }
      var i=morefuncs.indexOf("|"+swhat.toLowerCase()+" ")
      if (i>=0)
      {
       swhat=morefuncs.substring(i,i+20)
       swhat=swhat.substring(0,swhat.indexOf(" ")) 
      }
      if (testing) alert("checking function "+swhat)  
      var i=myfunctions.indexOf("()"+swhat+"()")
      if (i<0 && swhat.indexOf("Math")<0  && swhat.indexOf("|")<0)
      {
       swhat+="*"
       svar=sv0
      }

    }
   }
  }
  
  if (constants.indexOf("|"+swhat+" ")>=0)
  {
   swhat="|"+swhat.toUpperCase()
   svar=""
  }
  if(svar.length)
  {
   var s=","+svar+","
   var havexyz=(xyzlist.indexOf(s)>=0)
   if(havexyz)ulist+=s
   havexyzs=is_apdata && (havexyzs || havexyz)
   if (svar.indexOf("Math.")<0 && (!havexyzs || !havexyz))
   {
    var s=vlist
    vlist=updatevlist(vlist,svar,"",dovlist)
    nvars+=(vlist.length>s.length?1:0)
   }
  }
  swhat=strsub(swhat,"|","Math.")
  snew+=swhat+sthisop
 }
 if (snew.length==0){snew="0"}  
 snew=mathclean(snew)
 ipt=snew.indexOf("`(")
 while (ipt>=0)
 {
  snew=snew.substring(0,ipt)+snew.substring(ipt+1,snew.length)
  ipt=findparen(snew,ipt+1,1)
  snew=snew.substring(0,ipt+1)+")"+snew.substring(ipt+1,snew.length)
  ipt=snew.indexOf("`(")
 }
 if (doreclean) snew=math(snew,dovlist)
 snew=strsub(snew,"Math.log(fact(","lnfact((")  
 snew=strsub(snew,")(",")*(")
 if (testing) alert("math() returns: "+snew)
 return snew
}

function ptokenof()// get next parenthetical expression in smath
{
 if (smath.length==0){return ""}
 var spnew=""
 var ipt=0
 if (smath.charAt(ipt)!="("){return ""}
 ipt=findparen(smath,ipt,1)
 spnew=smath.substring(1,ipt)
 smath=smath.substring(ipt+1,smath.length)      
 return spnew
} 

function findparen(s,ipt0,idirect) //returns ptr to ")" or "("
{
 var ipt=ipt0
 var schar=(idirect==1?"(":")")
 var i=(s.charAt(ipt)==schar?0:idirect)
 while (ipt<s.length && ipt>=0) 
 {
  if (s.charAt(ipt)=="("){i=i+1}
  if (s.charAt(ipt)==")"){i=i-1}
  if (i==0) {return ipt}
  ipt+=idirect
 }
 return ipt  //-1 or s.length on failure to close
}

function tokenof(dochopoperator) //next token in smath; sthisop is next operator
{ //returns 2 for 2x  but x2 for x2
 if (testing) alert ("getting token for "+smath)
 sthisop=""
 var isexp=0
 var stoken=""
 if (smath.length==0) return ""
 var sch=smath.charAt(0)
 var havenum=(numerals.indexOf(sch)>0?1:0)
 var i=0
 while (i<smath.length)
 {
  sch=smath.charAt(i)
  if (operators.indexOf(sch)>0)  
  {
   sthisop=sch
   if (i>0){stoken=smath.substring(0,i)}
   smath=smath.substring(i+dochopoperator,smath.length)
   if (testing) alert ("token: "+stoken+" "+sthisop+" "+smath)
   return stoken
  }else{
   if (havenum && (numerals.indexOf(sch)<0))
   {
    if (sch=="E" || sch=="e")
    {
     i++ //skip +/-
    }else{
     sthisop="*"
     stoken=smath.substring(0,i)
     smath=smath.substring(i,smath.length)
     if (testing) alert(stoken+" "+sthisop+" "+smath)
     return stoken       
    }
   }
  }
  i++
 }
 stoken=smath
 smath=""
 if (testing) alert (stoken+" "+sthisop+" "+smath)
 return stoken      
}


