// This file contains JavaScript functions to convert a subset of tex into
// reasonable HTML. The conversion is done while the HTML page loads, and
// should work with IE 5+ and NS 4+.

// version of Nov 5 2001, (c) Peter Jipsen
// http://math.vanderbilt.edu/~pjipsen
// Freely available for non-commercial use. 
// Contact peter.jipsen@vanderbilt.edu for latest version.

//check if the symbol font is available
geqVer5 = navigator.appVersion.slice(0,1)>4; //fix for NS6

symb = navigator.appVersion.lastIndexOf('Win')!=-1 && !geqVer5 ||
    navigator.appVersion.lastIndexOf('Mac')!=-1;

function out(col,str,ent,alt,sp) {
  return sp+//"<b>"+
    "<font"+
    (col==""?"" : " color="+col)+     //comment out to get black symbols
    (alt==""?">"+str : (symb?" face=symbol>"+str : 
    (geqVer5?">"+ent : ">"+alt)))+"</font>"+//"</b>"+
    sp;
}

function outnf(str,ent,alt,sp) {
  return sp+(alt==""?str:(symb?str:(geqVer5?ent:alt)))+sp;
}

bl="&nbsp;";

symbols = [
//some greek symbols
 {tex:"\\alpha", output:out("","a","&alpha;","alpha","")}, 
 {tex:"\\beta", output:out("","b","&beta;","beta","")}, 
 {tex:"\\chi", output:out("","c","&chi;","chi","")}, 
 {tex:"\\delta", output:out("","d","&delta;","delta","")}, 
 {tex:"\\Delta", output:out("","D","&Delta;","Delta","")}, 
 {tex:"\\epsilon", output:out("","e","&epsilon;","epsilon","")}, 
 {tex:"\\varepsilon", output:out("","e","&epsilon;","epsilon","")}, 
 {tex:"\\eta", output:out("","h","&eta;","eta","")}, 
 {tex:"\\gamma", output:out("","g","&gamma;","gamma","")}, 
 {tex:"\\Gamma", output:out("","G","&Gamma;","Gamma","")}, 
 {tex:"\\iota", output:out("","i","&iota;","iota","")}, 
 {tex:"\\kappa", output:out("","k","&kappa;","kappa","")}, 
 {tex:"\\lambda", output:out("","l","&lambda;","lambda","")}, 
 {tex:"\\Lambda", output:out("","L","&Lambda;","Lambda","")}, 
 {tex:"\\mu", output:out("","m","&mu;","mu","")}, 
 {tex:"\\nu", output:out("","n","&nu;","nu","")}, 
 {tex:"\\omega", output:out("","w","&omega;","omega","")}, 
 {tex:"\\Omega", output:out("","W","&Omega;","Omega","")}, 
 {tex:"\\phi", output:out("","j","&phi;","phi","")}, 
 {tex:"\\varphi", output:out("","j","&phi;","phi","")}, 
 {tex:"\\Phi", output:out("","F","&Phi;","Phi","")}, 
 {tex:"\\pi", output:out("","p","&pi;","pi","")}, 
 {tex:"\\Pi", output:out("","P","&Pi;","Pi","")}, 
 {tex:"\\psi", output:out("","y","&psi;","psi","")}, 
 {tex:"\\rho", output:out("","r","&rho;","rho","")}, 
 {tex:"\\sigma", output:out("","s","&sigma;","sigma","")}, 
 {tex:"\\Sigma", output:out("","S","&Sigma;","Sigma","")}, 
 {tex:"\\tau", output:out("","t","&tau;","tau","")}, 
 {tex:"\\theta", output:out("","q","&theta;","theta","")}, 
 {tex:"\\Theta", output:out("","Q","&Theta;","Theta","")}, 
 {tex:"\\upsilon", output:out("","u","&upsilon;","upsilon","")}, 
 {tex:"\\Upsilon", output:out("","U","&Upsilon;","Upsilon","")}, 
 {tex:"\\xi", output:out("","x","&xi;","xi","")}, 
 {tex:"\\Xi", output:out("","X","&Xi;","Xi","")}, 
 {tex:"\\zeta", output:out("","z","&zeta;","zeta","")}, 

//binary operation symbols
 {tex:"+", output:out("Blue","+","+","+",bl)}, 
 {tex:"-", output:out("Blue","-","-","-","")}, 
 {tex:"\\star", output:out("Blue","*","*","*","")}, 
 {tex:"\\circ", output:out("Blue","<font size=-1>o</font>","","",bl)}, 
 {tex:"\\backslash", output:'<b><font color="Blue">\\</font></b>'}, 
// {tex:"/", output:'<b><font color="Blue">/</font></b>'}, 
 {tex:"/", output:out("Blue","<b>&#164;</b>","<b>&frasl;</b>","/","")}, 
 {tex:"\\divide", output:out("Blue","&#184;","&divide;","/",bl)}, 
 {tex:"\\oplus", output:out("Blue","&#197;","&oplus;","o+",bl)}, 
 {tex:"\\otimes", output:out("Blue","&#196;","&otimes;","ox",bl)}, 
 {tex:"\\wedge", output:out("Blue","&#217;","&and;","^",bl)}, 
 {tex:"\\vee", output:out("Blue","&#218;","&or;","v",bl)}, 
 {tex:"\\cup", output:out("Blue","&#200;","&cup;","u",bl)}, 
 {tex:"\\cap", output:out("Blue","&#199;","&cap;","n",bl)}, 
 {tex:"\\times", output:out("Blue","&#180;","&times;","times",bl)}, 

//binary relation symbols
 {tex:"=", output:out("Red","=","=","=",bl)}, 
 {tex:"\\ne", output:out("Red","&#185;","&ne;","!=",bl)}, 
 {tex:"\\le", output:out("Red","&#163;","&le;","&lt;=",bl)}, 
 {tex:"\\ge", output:out("Red","&#179;","&ge;","&gt;=",bl)}, 
 {tex:"<", output:'<font color="Red"> &lt; </font>'}, 
 {tex:">", output:'<font color="Red"> &gt; </font>'}, 
 {tex:"\\prec", output:'<font color="Red"> -&lt; </font>'}, 
 {tex:"\\succ", output:'<font color="Red"> &gt;- </font>'}, 
 {tex:"\\in", output:out("Red","&#206;","&isin;","in",bl)}, 
 {tex:"\\notin", output:out("Red","&#207;","&notin;","notin",bl)}, 
 {tex:"\\supset", output:out("Red","&#201;","&sup;","supset",bl)}, 
 {tex:"\\supseteq", output:out("Red","&#202;","&supe;","supseteq",bl)}, 
 {tex:"\\subset", output:out("Red","&#204;","&sub;","subset",bl)}, 
 {tex:"\\subseteq", output:out("Red","&#205;","&sube;","subseteq",bl)}, 
 {tex:"\\equiv", output:out("Red","&#186;","&equiv;","==","")}, 
 {tex:"\\cong", output:out("Red","&#64;","&cong;","~=","")}, 
 {tex:"\\approx", output:out("Red","&#187;","&asymp;","~~","")}, 

//logical symbols
 {tex:"\\forall", output:out("Blue","&#034;","&forall;","A","")}, 
 {tex:"\\exists", output:out("Blue","&#036;","&exist;","E","")}, 
 {tex:"\\neg", output:out("Blue","&#216;","&not;","not","")}, 

//miscellaneous symbols
 {tex:"\\perp", output:out("Blue","&#94;","&perp;","_|_","")}, 
 {tex:"\\partial", output:out("Blue","&#182;","&part;","d","")}, 
 {tex:"\\pm", output:out("Blue","&#177;","&plusmn;","-+",bl)}, 
 {tex:"\\sum", output:out("Blue","&#229;","&sum;","sum",bl)}, 
 {tex:"\\prod", output:out("Blue","&#213;","&prod;","prod",bl)}, 
 {tex:"\\int", output:out("Blue","&#242;","&int;","int",bl)}, 
 {tex:"\\emptyset", output:out("","&#198;","&empty;","empty","")}, 
 {tex:"\\infty", output:out("","&#165;","&infin;","infty","")}, 
 {tex:"\\aleph", output:out("","&#192;","&alefsym;","aleph","")}, 
 {tex:"\\ldots", output:"..."}, 
 {tex:"\\dollar", output:"$"}, 
 {tex:"\\ ", output:"&nbsp;"}, 
 {tex:"\\quad", output:"&nbsp;&nbsp;"}, 
 {tex:"\\qquad", output:"&nbsp;&nbsp;&nbsp;&nbsp;"}, 
 {tex:",", output:", "}, 
 {tex:":", output:" : "}, 
 {tex:"\\cdots", output:out("Blue","&#215;&#215;&#215;",
  "&sdot;&sdot;&sdot;","...","")}, 
 {tex:"\\cdot", output:out("Blue","&#215;","&sdot;",".","")}, 
 {tex:"\\diamond", output:out("Blue","&#224;","&loz;","<>","")}, 
 {tex:"\\square", output:out("Blue","[]","[]","[]","")}, 
 {tex:"\\qed", output:out("","&#168;","&diams;","[]","")}, 
 {tex:"\\lim", output:"lim"}, 
 {tex:"\\sin", output:"sin"}, 
 {tex:"\\cos", output:"cos"}, 
 {tex:"\\tan", output:"tan"}, 
 {tex:"\\cot", output:"cot"}, 
 {tex:"\\sec", output:"sec"}, 
 {tex:"\\csc", output:"csc"}, 
 {tex:"\\log", output:"log"}, 
 {tex:"\\ln", output:"ln"}, 
 {tex:"\\det", output:"det"}, 
 {tex:"\\dim", output:"dim"}, 

//arrows
 {tex:"\\uparrow", output:out("Blue","&#173;","&uarr;","!^","")}, 
 {tex:"\\downarrow", output:out("Blue","&#175;","&darr;","!v","")}, 
 {tex:"\\rightarrow", output:out("Blue","&#174;","&rarr;","-&gt;",bl)}, 
 {tex:"\\to", output:out("Blue","&#174;","&rarr;","-&gt;",bl)}, 
 {tex:"\\leftarrow", output:out("Blue","&#172;","&larr;","&lt;-",bl)}, 
 {tex:"\\leftrightarrow", output:out("Blue","&#171;","&harr;","<=>",bl)}, 
 {tex:"\\Rightarrow", output:out("Blue","&#222;","&rArr;","=>",bl+bl)}, 
 {tex:"\\Leftrightarrow", output:out("Blue","&#219;","&hArr;","<=>",bl+bl)}, 

//bracket operations
 {tex:"\\lfloor", output:out("","&#235;","|_","|_","")}, 
 {tex:"\\rfloor", output:out("","&#251;","_|","_|","")}, 
 {tex:"\\lceiling",
  output:out("","&#233;","|<sup>-</sup>","|<sup>-</sup>","")}, 
 {tex:"\\rceiling",
  output:out("","&#249;","<sup>-</sup>|","<sup>-</sup>|","")}, 
 {tex:"\\langle", output:out("","&#225;","&lt;","&lt;","")}, 
 {tex:"\\rangle", output:out("","&#241;","&gt;","&gt;","")}, 
 {tex:"\\{", output:"<b>{</b>"},
 {tex:"\\}", output:"<b>}</b>"},

//commands with argument
 {tex:"_", output:"<sub>", endStr:"</sub>"}, 
 {tex:"^", output:"<sup>", endStr:"</sup>"}, 
 {tex:"\\mathbf", output:"<b>", endStr:"</b>"}, 
 {tex:"\\underline", output:"<u>", endStr:"</u>"}, 
 {tex:"\\sqrt", output:outnf(
  "<b><font color=Blue face=symbol>&#214;</font></b>(","&radic;(",
  "sqrt(",""), endStr:")"}, 
 {tex:"\\frac", output:"<sup>", endStr:outnf(
  "</sup><b><font face=symbol color=Blue>&#164;</font></b><sub>",
  "</sup><b><font color=Blue>&frasl;</font></b><sub>","</sup>/<sub>",""),
  endStr2:"</sub>"}, 
 {tex:"\\mbox", output:" ", endStr:" "},
 {tex:"\\text", output:" ", endStr:" "},

//grouping braces
 {tex:"{", output:""},
 {tex:"}", output:""},

//abbreviations (add your own if you wish)
 {tex:"\\m", output:"<b>", endStr:"</b>"}, 
 {tex:"\\ul", output:"<u>", endStr:"</u>"},
 {tex:"\\<", output:out("","&#225;","&lt;","&lt;","")}, 
 {tex:"\\>", output:out("","&#241;","&gt;","&gt;","")}
];

function add(arr, elt){    // the push method is not supported in IExplorer
  arr[arr.length]=elt;
}

function remove(arr){
  if (arr.length==0) return "";
  var elt=arr[arr.length-1];
  arr.length=arr.length-1;
  return elt;
}

function compareNames(s1,s2) {
  if (s1.tex > s2.tex) return 1
  else return -1;
}

names=[];
stack=[];

function initSymbols() {
  symbols.sort(compareNames);
  for (var i=0; i<symbols.length; i++) names[i] = symbols[i].tex;
}

initSymbols();

function removeCharsAndBlanks(str,n) {
//remove n characters and any following blanks
  var st = str.slice(n);
  for (var i=0; i<st.length && st.charCodeAt(i)<=32; i=i+1);
  return st.slice(i);
}

function position(arr, str, n) { 
// return position >=n where str appears or would be inserted
// assumes arr is sorted
  if (n==0) {
    var h,m;
    n=-1;
    h=arr.length;
    while (n+1<h) {
      m=(n+h) >> 1;
      if (arr[m]<str) n=m; else h=m;
    }
    return h;
  } else
    for (var i=n; i<arr.length && arr[i]<str; i++);
  return i; // i=arr.length || arr[i]>=str
}

function getSymbol(str) {
//return maximal initial substring of str that appears in names
//return null if there is none
  var k=0; //new pos
  var j=0; //old pos
  var mk; //match pos
  var st;
  var match="";
  var more = true;
  for (var i=1; i<=str.length && more; i++) {
    st=str.slice(0,i); //initial substring of length i
    j=k;
    k=position(names, st, j);
    if (k<names.length && str.slice(0,names[k].length)==names[k]){
      match=names[k];
      mk=k;
      i=match.length;
    }
    more=k<names.length && str.slice(0,names[k].length)>=names[k];
  }
  if (match!="") return symbols[mk]; 
// if str[0] is a letter return maxsubstring of letters followed by numbers
  k=1;
  st=str.slice(0,1);
  while (k<=str.length && ("A"<=st && st<="Z") || ("a"<=st && st<="z")) {
    st=str.slice(k,k+1);
    k++;
  }
  if (k>1) st="<i>"+str.slice(0,k-1)+"</i>";
  else {
    k=2;
    st=str.slice(0,1); //take 1 non-letter character
  }
  return {tex:str.slice(0,k-1), output:st};
}

//document.writeln("names=",names,"<p>");

function m2h(str) { //processes str linearly, constructs hs
  var symbol;
  var hs="";
  var onesymbol=false;
  str=removeCharsAndBlanks(str,0);
  while (str.length>0) {
//document.writeln("***",str,"***",hs,"***<br>");
    symbol=getSymbol(str); // a nonblank symbol
    str=removeCharsAndBlanks(str,symbol.tex.length);
    hs=hs+symbol.output;
    if (symbol.endStr!=null) { // tex command with an argument
      if (symbol.endStr==" ") { // mbox or text command
        var ind=str.search('\}');
        hs=hs+str.slice(1,ind);
        str=str.slice(ind+1);
      } else {
        if (symbol.endStr2!=null)
          add(stack,symbol.endStr2);
        add(stack,symbol.endStr);
        onesymbol=true;
      }
    } else if (symbol.tex=="{") {
      onesymbol=false;
    } else if (onesymbol||symbol.tex=="}") { // end of argument
      hs=hs+remove(stack);
      onesymbol=false;
    }
  }
  return hs;
}

mathdelimit="$";

function t2h(str) {
  var st="";
  var arr=str.split(mathdelimit); // string to delimit math expressions
  var expr=false;
  for (var i=0; i<arr.length; i++) {
    if (expr) {
      st = st+m2h(arr[i]);
    }
    else st=st+(arr[i].charCodeAt(0)>32 || i==0?"":" &nbsp; ")+arr[i]+
      (arr[i].charCodeAt(arr[i].length-1)>32?"":" &nbsp; ")
    expr=!expr;
  }
  return st;
}

function p(str) {
  document.writeln(t2h(str));
}

function insertTeXhere() {
  document.writeln(t2h(
    document.forms[0].elements[0].value.replace(/\r\n(\r\n)+/g,"\n<p>")));
}

