/*
ASCIIMathMFallback.js
==============
This version of ASCIIMathML has been modified with TeX conversion for 
IMG fallback June 11, 2008 (c) David Lippman http://www.pierce.ctc.edu/dlippman
This this version, if browser supports MathML, it is used.  Otherwise, image-
based math rendering is used (set AMTcgiloc for renderer)
*/
//var AMTcgiloc = "http://www.forkosh.com/cgi-bin/mimetex.cgi"; //path to CGI script that can render a TeX string for AMTparseMath src
//var AMTcgiloc = "http://www.forkosh.com/cgi-bin/mathtex.cgi"; //path to CGI script that can render a TeX string for AMTparseMath src
var AMTcgiloc = "http://www.imathas.com/cgi-bin/mimetex.cgi"; //path to CGI script that can render a TeX string

function AMTremoveBrackets(node) {
	
  var st;
  if (node.charAt(0)=='{' && node.charAt(node.length-1)=='}') {

    st = node.charAt(1);
    if (st=="(" || st=="[") node = '{'+node.substr(2);
    st = node.substr(1,6);
    if (st=="\\left(" || st=="\\left[" || st=="\\left{") node = '{'+node.substr(7);
    st = node.substr(1,12);
    if (st=="\\left\\lbrace" || st=="\\left\\langle") node = '{'+node.substr(13);
    st = node.charAt(node.length-2);
    if (st==")" || st=="]") node = node.substr(0,node.length-8)+'}';
    st = node.substr(node.length-8,7)
    if (st=="\\rbrace" || st=="\\rangle") node = node.substr(0,node.length-14) + '}';
    
  } 
  return node;
}

function AMTgetTeXsymbol(symb) {
	if (typeof symb.val == "boolean" && symb.val) {
		pre = '';
	} else {
		pre = '\\';
	}
	if (symb.tex==null) {
		return (pre+symb.input);
	} else {
		return (pre+symb.tex);
	}
}
function AMTgetTeXbracket(symb) {
	if (symb.tex==null) {
		return (symb.input);
	} else {
		return ('\\'+symb.tex);
	}
}

function AMTparseSexpr(str) { //parses str and returns [node,tailstr]
  var symbol, node, result, i, st,// rightvert = false,
  newFrag = '';
  str = AMremoveCharsAndBlanks(str,0);
  symbol = AMgetSymbol(str);             //either a token or a bracket or empty
  if (symbol == null || symbol.ttype == RIGHTBRACKET && AMnestingDepth > 0) {
    return [null,str];
  }
  if (symbol.ttype == DEFINITION) {
    str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length); 
    symbol = AMgetSymbol(str);
  }
  switch (symbol.ttype) {
  case UNDEROVER:
  case CONST:
    str = AMremoveCharsAndBlanks(str,symbol.input.length); 
    var texsymbol = AMTgetTeXsymbol(symbol);
    if (texsymbol.charAt(0)=="\\" || symbol.tag=="mo") return [texsymbol,str];
    else return ['{'+texsymbol+'}',str];
    
  case LEFTBRACKET:   //read (expr+)
    AMnestingDepth++;
    str = AMremoveCharsAndBlanks(str,symbol.input.length); 
   
    result = AMTparseExpr(str,true);
    AMnestingDepth--;
    if (typeof symbol.invisible == "boolean" && symbol.invisible) 
    	node = '{\\left.'+result[0]+'}';
    else {
	    node = '{\\left'+AMTgetTeXbracket(symbol) + result[0]+'}';
    }
    return [node,result[1]];
  case TEXT:
      if (symbol!=AMquote) str = AMremoveCharsAndBlanks(str,symbol.input.length);
      if (str.charAt(0)=="{") i=str.indexOf("}");
      else if (str.charAt(0)=="(") i=str.indexOf(")");
      else if (str.charAt(0)=="[") i=str.indexOf("]");
      else if (symbol==AMquote) i=str.slice(1).indexOf("\"")+1;
      else i = 0;
      if (i==-1) i = str.length;
      st = str.slice(1,i);
      if (st.charAt(0) == " ") {
	      newFrag = '\\ ';
      }
     newFrag += '\\text{'+st+'}';
      if (st.charAt(st.length-1) == " ") {
	      newFrag += '\\ ';
      }
      str = AMremoveCharsAndBlanks(str,i+1);
      return [newFrag,str];
  case UNARY:
      str = AMremoveCharsAndBlanks(str,symbol.input.length); 
      result = AMTparseSexpr(str);
      if (result[0]==null) return ['{'+AMTgetTeXsymbol(symbol)+'}',str];
      if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
        st = str.charAt(0);
        if (st=="^" || st=="_" || st=="/" || st=="|" || st==",") {
          return ['{'+AMTgetTeXsymbol(symbol)+'}',str];
        } else {
		node = '{'+AMTgetTeXsymbol(symbol)+'{'+result[0]+'}}';
		return [node,result[1]];
        }
      }
      result[0] = AMTremoveBrackets(result[0]);
      if (symbol.input == "sqrt") {           // sqrt
	      return ['\\sqrt{'+result[0]+'}',result[1]];
      } else if (typeof symbol.acc == "boolean" && symbol.acc) {   // accent
	      return ['{'+AMTgetTeXsymbol(symbol)+'{'+result[0]+'}}',result[1]];
      } else {                        // font change command  
	    return ['{'+AMTgetTeXsymbol(symbol)+'{'+result[0]+'}}',result[1]];
      }
  case BINARY:
    str = AMremoveCharsAndBlanks(str,symbol.input.length); 
    result = AMTparseSexpr(str);
    if (result[0]==null) return ['{'+AMTgetTeXsymbol(symbol)+'}',str];
    result[0] = AMTremoveBrackets(result[0]);
    var result2 = AMTparseSexpr(result[1]);
    if (result2[0]==null) return ['{'+AMTgetTeXsymbol(symbol)+'}',str];
    result2[0] = AMTremoveBrackets(result2[0]);
    if (symbol.input=="root" || symbol.input=="stackrel") {
	    if (symbol.input=="root") {
		    newFrag = '{\\sqrt['+result[0]+']{'+result2[0]+'}}';
	    } else {
		    newFrag = '{'+AMTgetTeXsymbol(symbol)+'{'+result[0]+'}{'+result2[0]+'}}';
	    }
    }
    if (symbol.input=="frac") {
	    newFrag = '{\\frac{'+result[0]+'}{'+result2[0]+'}}';
    }
    return [newFrag,result2[1]];
  case INFIX:
    str = AMremoveCharsAndBlanks(str,symbol.input.length); 
    return [symbol.output,str];
  case SPACE:
    str = AMremoveCharsAndBlanks(str,symbol.input.length);
    return ['{\\quad\\text{'+symbol.input+'}\\quad}',str];
  case LEFTRIGHT:
//    if (rightvert) return [null,str]; else rightvert = true;
    AMnestingDepth++;
    str = AMremoveCharsAndBlanks(str,symbol.input.length); 
    result = AMTparseExpr(str,false);
    AMnestingDepth--;
    var st = "";
    st = result[0].charAt(result[0].length -1);
//alert(result[0].lastChild+"***"+st);
    if (st == "|") { // its an absolute value subterm
	    node = '{\\left|'+result[0]+'}';
      return [node,result[1]];
    } else { // the "|" is a \mid
      node = '{\\mid}';
      return [node,str];
    }
   
  default:
//alert("default");
    str = AMremoveCharsAndBlanks(str,symbol.input.length); 
    return ['{'+AMTgetTeXsymbol(symbol)+'}',str];
  }
}

function AMTparseIexpr(str) {
  var symbol, sym1, sym2, node, result, underover;
  str = AMremoveCharsAndBlanks(str,0);
  sym1 = AMgetSymbol(str);
  result = AMTparseSexpr(str);
  node = result[0];
  str = result[1];
  symbol = AMgetSymbol(str);
  if (symbol.ttype == INFIX && symbol.input != "/") {
    str = AMremoveCharsAndBlanks(str,symbol.input.length);
   // if (symbol.input == "/") result = AMTparseIexpr(str); else 
    result = AMTparseSexpr(str);
    if (result[0] == null) // show box in place of missing argument
	    result[0] = '{}';
    else result[0] = AMTremoveBrackets(result[0]);
    str = result[1];
//    if (symbol.input == "/") AMTremoveBrackets(node);
    if (symbol.input == "_") {
      sym2 = AMgetSymbol(str);
      underover = (sym1.ttype == UNDEROVER);
      if (sym2.input == "^") {
        str = AMremoveCharsAndBlanks(str,sym2.input.length);
        var res2 = AMTparseSexpr(str);
        res2[0] = AMTremoveBrackets(res2[0]);
        str = res2[1];
        node = '{' + node;
       	node += '_{'+result[0]+'}';
	    node += '^{'+res2[0]+'}';
        node += '}';
      } else {
        node += '_{'+result[0]+'}';
      }
    } else { //must be ^
      node = '{'+node+'}^{'+result[0]+'}';
    }
  } 
  
  return [node,str];
}

function AMTparseExpr(str,rightbracket) {
  var symbol, node, result, i, nodeList = [],
  newFrag = '';
  var addedright = false;
  do {
    str = AMremoveCharsAndBlanks(str,0);
    result = AMTparseIexpr(str);
    node = result[0];
    str = result[1];
    symbol = AMgetSymbol(str);
    if (symbol.ttype == INFIX && symbol.input == "/") {
      str = AMremoveCharsAndBlanks(str,symbol.input.length);
      result = AMTparseIexpr(str);
      
      if (result[0] == null) // show box in place of missing argument
	      result[0] = '{}';
      else result[0] = AMTremoveBrackets(result[0]);
      str = result[1];
      node = AMTremoveBrackets(node);
      node = '\\frac' + '{'+ node + '}';
      node += '{'+result[0]+'}';
      newFrag += node;
      symbol = AMgetSymbol(str);
    }  else if (node!=undefined) newFrag += node;
  } while ((symbol.ttype != RIGHTBRACKET && 
           (symbol.ttype != LEFTRIGHT || rightbracket)
           || AMnestingDepth == 0) && symbol!=null && symbol.output!="");

  if (symbol.ttype == RIGHTBRACKET || symbol.ttype == LEFTRIGHT) {
//    if (AMnestingDepth > 0) AMnestingDepth--;
	var len = newFrag.length;
	if (len>2 && newFrag.charAt(0)=='{' && newFrag.indexOf(',')>0) { //could be matrix (total rewrite from .js)
		var right = newFrag.charAt(len - 2);
		if (right==')' || right==']') {
			var left = newFrag.charAt(6);
			if ((left=='(' && right==')' && symbol.output != '}') || (left=='[' && right==']')) {
				var mxout = '\\matrix{';
				var pos = new Array(); //position of commas
				pos.push(0);
				var matrix = true;
				var mxnestingd = 0;
				for (i=1; i<len-1; i++) {
					if (newFrag.charAt(i)==left) mxnestingd++;
					if (newFrag.charAt(i)==right) {
						mxnestingd--;
						if (mxnestingd==0 && newFrag.charAt(i+2)==',' && newFrag.charAt(i+3)=='{') pos.push(i+2);
					}
				}
				pos.push(len);
				var lastmxsubcnt = -1;
				if (mxnestingd==0 && pos.length>0) {
					for (i=0;i<pos.length-1;i++) {
						if (i>0) mxout += '\\\\';
						if (i==0) {
							var subarr = newFrag.substr(pos[i]+7,pos[i+1]-pos[i]-15).split(',');
						} else {
							var subarr = newFrag.substr(pos[i]+8,pos[i+1]-pos[i]-16).split(',');
						}
						if (lastmxsubcnt>0 && subarr.length!=lastmxsubcnt) {
							matrix = false;
						} else if (lastmxsubcnt==-1) {
							lastmxsubcnt=subarr.length;
						}
						mxout += subarr.join('&');
					}
				}
				mxout += '}';
				if (matrix) { newFrag = mxout;}
			}
		}
	}
    
    str = AMremoveCharsAndBlanks(str,symbol.input.length);
    if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
      node = '\\right'+AMTgetTeXbracket(symbol); //AMcreateMmlNode("mo",document.createTextNode(symbol.output));
      newFrag += node;
      addedright = true;
    } else {
	    newFrag += '\\right.';
	    addedright = true;
    }
   
  }
  if(AMnestingDepth>0 && !addedright) {
	  newFrag += '\\right.'; //adjust for non-matching left brackets
	  //todo: adjust for non-matching right brackets
  }
  
  return [newFrag,str];
}

function AMTparseAMtoTeX(str) {
	//DLMOD to remove &nbsp;, which editor adds on multiple spaces
  AMnestingDepth = 0;
  str = str.replace(/&nbsp;/g,"");
  str = str.replace(/&gt;/g,">");
  str = str.replace(/&lt;/g,"<");
  return AMTparseExpr(str.replace(/^\s+/g,""),false)[0];
}

function AMTparseMath(str,istex) {
	if (istex) { 
		var texstring = str;
	} else {
		var texstring = AMTparseAMtoTeX(str);
	}
  if (mathcolor!="") {
	  texstring = "\\"+mathcolor + texstring;
  }
  if (displaystyle) {
	  texstring = "\\displaystyle" + texstring;
  } else {
	  texstring = "\\textstyle" + texstring;
  }
  var node = createElementXHTML("img");
  if (typeof encodeURIComponent == "function") {
	  texstring = encodeURIComponent(texstring);
  } else {
	  texstring = escape(texstring);
  }
  node.src = AMTcgiloc + '?' + texstring;
  node.style.verticalAlign = "middle";
  if (showasciiformulaonhover)                      //fixed by djhsu so newline
    node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko
 
  return node;
}
