// Zum Parsen von Ausdrücken, die ^ (hoch) und ! (Faktorielle)
// enthalten
// Ein Problem besteht noch: ^ hat in JavaScript eine (logische)
// Bedeutung, sollte hier aber nicht in dieser Bedeutung benützt werden.

abbruch_links  = new Array ("(","[","{","+","-","*","/","&","|","<",">","^","=",";",",");
abbruch_rechts = new Array (")","]","}","+","-","*","/","&","|","<",">","^","=",";",",");

function parsen(a)
{   
   var j = a.indexOf("^");
   var l, k;
   var b, c;

   while (j != -1)   // Hochzeichen ^
   {
      j = a.indexOf("^");
      l=j-1;
      while (  !( l<=0 || 
	               ( 
				     ( inListe_links(a.charAt(l-1)) || sonstigerAbbruch(l,a) ) 
					   && klammerkonsistent(a.substring(l,j))
				     )
				)
		    )    // !Abbruchbedingung
				 
	  {
	     l=l-1;
	  }
	  b = a.substring(l,j); // die Basis
	  
      k=j+1;
      while (  !( k>=a.length-1 || 
	               ( inListe_rechts(a.charAt(k+1)) && klammerkonsistent(a.substring(j+1,k+1)) )
				)
		    )    // !Abbruchbedingung
				 
	  {
	     k=k+1;
	  }
	  c = a.substring(j+1,k+1);	// der Exponent  	  
	  a = ERSETZE(a,b+"^"+c,"pow("+b+","+c+")");
   }
   
   
   j = a.indexOf("!");

   while (j != -1)   // Faktorielle !
   {
      j = a.indexOf("!");
      l=j-1;
      while (  !( l<=0 || 
	               ( 
				     ( inListe_links(a.charAt(l-1)) || sonstigerAbbruch(l,a) ) 
					   && klammerkonsistent(a.substring(l,j))
				     )
				)
		    )    // !Abbruchbedingung
				 
	  {
	     l=l-1;
	  }
	  b = a.substring(l,j); // der Ausdruck, der Faktorielle genommen wird
	  a = ERSETZE(a,b+"!","factorial("+b+")");
   }

   return a;
}


function inListe_links(a)        // Analysiere   ...   Y   X   X   X   ^ .....
{                                //                   l-1  l           j
                                 // falls Abbruch -> true
   var ergebnis = false;
   for(i=0; i<abbruch_links.length; i++)
   {
      if (a == abbruch_links[i])
	  { ergebnis = true; break;}
   }
   return ergebnis;
}

function sonstigerAbbruch(l,a)  // was in der JavaScript-Syntax links vom Exponenten
                                // sont noch so auftreten kann
{
   if (a.substring(l-7,l) == "return ")
   return true;
   else return false;
}

function inListe_rechts(a)       // Analysiere   ...    ^   X   X   X   Y  .....
{                                //                     j           k  k+1
                                 // falls Abbruch -> true
   var ergebnis = false;
   for(i=0; i<abbruch_rechts.length; i++)
   {
      if (a == abbruch_rechts[i])
	  { ergebnis = true; break; }
   }
   return ergebnis;
}

function klammerkonsistent2(a,klammer_links,klammer_rechts)
{
   var q=0;
   while (q < a.length)  // alles weg au&szlig;er den Klammern
   {
      if (a.charAt(q) != klammer_links && a.charAt(q) != klammer_rechts)
      a = ERSETZE(a,a.charAt(q),"");
	  else
	  q=q+1;
   }
   
   while(a.indexOf(klammer_links+klammer_rechts) != -1)
   {
      a = ERSETZE(a,
	  a.substring(a.indexOf(klammer_links+klammer_rechts),a.indexOf(klammer_links+klammer_rechts)+2),"");
   }
   if (a == "") return true;
   else return false;
}

function klammerkonsistent(a)
{
   if ( klammerkonsistent2(a,"(",")") && klammerkonsistent2(a,"[","]") 
        && klammerkonsistent2(a,"{","}") ) 
   return true;
   else return false;
}

function ERSETZE(s, a, b)
{   var n, laengea, laengeb;

      laengea = a.length; 1;
      laengeb = b.length; 

      while(s.indexOf(a) != -1)
      {
       n = s.indexOf(a);       
       if (0<=n && n <= s.length-laengea)        
       {  if (n==0) 
           s = b+s.substring(laengea,s.length);
          else if (n == s.length-laengea)
           s=s.substring(0,n)+b;
          else
           s=s.substring(0,n)+b+s.substring(n+laengea,s.length); 
       }
      }
     return s;             
 }

/* alte Version:
function faktorielle(n)
{
  if (n == 0 || n == 1) return 1;
  else return n*faktorielle(n-1);
} */

function faktorielle(n)
{
  return factorial(n);
}

// Ab hier (17. 3. 2000) von Ken's Script übernommen:

function factorial(n) {  /* factorial */
  with(Math) {
  if (n<0)  /* if negative */
  	return gamma(n+1);
  else if ((n == 0) || (n == 1))
    return 1;
  else if (abs(n)-floor(abs(n))==0 ) /* if positive integer */
    return n * factorial(n-1) ;
  else         /* if non-integer */
    return gamma(n+1);
} }

function loggamma(x)  { /* log gamma */
    with(Math) {
        var v=1;
        var w=0;
        var z=0;
        while ( x<8 ) { v*=x; x++ }
        w=1/(x*x);
        return ((((((((-3617/122400)*w + 7/1092)*w
         -691/360360)*w + 5/5940)*w
         -1/1680)*w + 1/1260)*w
         -1/360)*w + 1/12)/x + 0.5 * log(2*PI)-log(v)-x+(x-0.5)*log(x) ;
} }


function gamma(x) {  /* gamma */
    with(Math) {
        if ( x <= 0 ) {
            if (abs(x)-floor(abs(x))==0 )
                return "ComplexInfinity" ;
            else return PI/( sin(PI*x) * exp( loggamma(1-x) ) );
            }
        else 
            return exp(loggamma(x)) ;
} }

