/*
 * $Id: BulletmlUtil.java,v 1.1.1.1 2002/06/14 10:54:13 kenta Exp $
 *
 * Copyright 2002 Kenta Cho. All rights reserved.
 */
package jp.gr.java_conf.abagames.bulletml2swf;

import jp.gr.java_conf.abagames.bulletml.*;
import java.util.Hashtable;
import java.awt.TextArea;

/**
 * Utility class for BulletML.
 *
 * @version $Revision: 1.1.1.1 $
 */
public class BulletmlUtil {
  private static Hashtable expressions = new Hashtable();

  public static int getIntValue(String v, float[] prms) {
    return (int)evalExpression(v, prms);
  }

  public static float getFloatValue(String v, float[] prms) {
    return evalExpression(v, prms);
  }

  private static char[] expChr;
  private static float rank = 0.5f;

  public static void setRank(float rk) {
    rank = rk;
  }

  public static float getRank() {
    return rank;
  }

  private static void evalFloatValue(Expression ep, int stIdx, int lgt, float sign) {
    if ( expChr[stIdx] == '$' ) {
      String label = new String(expChr, stIdx+1, lgt-1);
      if ( label.equals("rand") ) {
        //return rnd.nextFloat();
        ep.push(0, Expression.STACK_RAND);
      } else if ( label.equals("rank") ) {
        //return rank;
        ep.push(0, Expression.STACK_RANK);
      } else {
        int idx;
        try {
          idx = new Integer(label).intValue()-1;
        } catch ( NumberFormatException e ) {
          //return 0;
          ep.push(0, Expression.STACK_NUM);
          return;
        }
        //return prms[idx];
        ep.push(0, Expression.STACK_VARIABLE+idx);
      }
    } else {
      try {
        //return new Float(new String(expChr, stIdx, lgt)).floatValue();
        ep.push(new Float(new String(expChr, stIdx, lgt)).floatValue()*sign,
         Expression.STACK_NUM);
      } catch ( NumberFormatException e ) {
        //return 0;
        ep.push(0, Expression.STACK_NUM);
      }
    }
  }

  private static void evalExpPart(Expression ep, int stIdx, int edIdx) {
    int op[] = new int[] {-1, -1};
    while (expChr[stIdx]=='(' && expChr[edIdx-1]==')') {
      stIdx++;
      edIdx--;
    }
    for ( int i = edIdx-1; i >= stIdx ; i-- ) {
      char c = expChr[i];
      if ( c == ')' ) {
        do {
          i--;
        } while ( expChr[i] != '(' );
      } else if ( op[0] < 0 && (c=='*' || c=='/' || c=='%') ) {
	op[0] = i;
      } else if ( c=='+' || c=='-' ) {
	op[1] = i;
	break;
      }
    }
    if ( op[1] < 0 ) {
      if ( op[0] < 0 ) {
        //return evalFloatValue(stIdx, edIdx-stIdx);
        evalFloatValue(ep, stIdx, edIdx-stIdx, 1);
      } else {
	switch(expChr[op[0]]) {
	case '*':
	  //return evalExpPart(stIdx, op[0]) * evalExpPart(op[0]+1, edIdx);
	  evalExpPart(ep, stIdx, op[0]);
          evalExpPart(ep, op[0]+1, edIdx);
          ep.setOperator(Expression.MULTIPLE);
          break;
	case '/':
	  //return evalExpPart(stIdx, op[0]) / evalExpPart(op[0]+1, edIdx);
	  evalExpPart(ep, stIdx, op[0]);
          evalExpPart(ep, op[0]+1, edIdx);
          ep.setOperator(Expression.DIVISION);
          break;
	case '%':
	  //return evalExpPart(stIdx, op[0]) % evalExpPart(op[0]+1, edIdx);
	  evalExpPart(ep, stIdx, op[0]);
          evalExpPart(ep, op[0]+1, edIdx);
          ep.setOperator(Expression.MODULO);
          break;
	}
      }
    } else {
      if ( op[1] == stIdx ) {
	switch (expChr[op[1]]) {
	case '-':
          //return -evalFloatValue(stIdx+1, edIdx-stIdx-1);
          evalFloatValue(ep, stIdx+1, edIdx-stIdx-1, -1);
          break;
	case '+':
          //return  evalFloatValue(stIdx+1, edIdx-stIdx-1);
          evalFloatValue(ep, stIdx+1, edIdx-stIdx-1, 1);
          break;
	}
      } else {
	switch(expChr[op[1]]) {
	case '+':
	  //return evalExpPart(stIdx, op[1]) + evalExpPart(op[1]+1, edIdx);
	  evalExpPart(ep, stIdx, op[1]);
          evalExpPart(ep, op[1]+1, edIdx);
          ep.setOperator(Expression.PLUS);
          break;
	case '-':
	  //return evalExpPart(stIdx, op[1]) - evalExpPart(op[1]+1, edIdx);
	  evalExpPart(ep, stIdx, op[1]);
          evalExpPart(ep, op[1]+1, edIdx);
          ep.setOperator(Expression.MINUS);
          break;
	}
      }
    }
  }

  public static float evalExpression(String exp, float[] p) {
    Expression ep = (Expression)expressions.get(exp);
    if ( ep == null ) {
      expChr = new char[exp.length()];
      int ecIdx = 0;
      boolean skip = false;
      StringBuffer buf = new StringBuffer(exp);
      int depth = 0;
      boolean balance = true;
      char ch;
      for( int i=0 ; i<buf.length() ; i++ ) {
        ch = buf.charAt(i);
        switch(ch) {
        case ' ':
        case '\n':
          skip = true;
          break;
        case ')':
          depth--;
          if ( depth < 0 ) balance = false;
          break;
        case '(':
          depth++;
          break;
        }
        if ( skip ) {
          skip = false;
        } else {
          expChr[ecIdx] = ch;
          ecIdx++;
        }
      }
      if ( depth != 0 || !balance ) {
        return 0;
      }
      ep = new Expression();
      evalExpPart(ep, 0, ecIdx);
      expressions.put(exp, ep);
    }
    return ep.calc(p);
  }


  private static Hashtable bullets = new Hashtable();
  private static Hashtable actions = new Hashtable();
  private static Hashtable fires = new Hashtable();

  private static TextArea console;

  public static void setConsole(TextArea csl) {
    console = csl;
  }

  public static void clear() {
    bullets.clear();
    actions.clear();
    fires.clear();
    expressions.clear();
  }

  public static void addBullet(Bullet blt) {
    bullets.put(blt.getLabel(), blt);
  }

  public static void addAction(Action act) {
    actions.put(act.getLabel(), act);
  }

  public static void addFire(Fire fre) {
    fires.put(fre.getLabel(), fre);
  }

  public static Bullet getBulletElm(IBulletElmChoice bec) {
    if ( bec instanceof BulletRef ) {
      String label = ((BulletRef)bec).getLabel();
      Bullet blt = (Bullet)bullets.get(label);
      if ( blt == null ) {
        if ( console != null ) {
          console.append("unknown bullet label: " + label + "\n");
        } else {
          System.out.println("unknown bullet label: " + label);
        }
      }
      return blt;
    } else if ( bec instanceof Bullet ) {
      return (Bullet)bec;
    }
    return null;
  }

  public static float[] getBulletParams(IBulletElmChoice bec, float[] prms) {
    if ( bec instanceof BulletRef ) {
      BulletRef br = (BulletRef)bec;
      float[] prm = new float[br.getParamCount()];
      for ( int i=prm.length-1; i>=0 ; i-- ) {
        prm[i] = BulletmlUtil.getFloatValue(br.getParam(i).getContent(), prms);
      }
      return prm;
    }
    return null;
  }

  public static Action getActionElm(IActionElmChoice aec) {
    if ( aec instanceof ActionRef ) {
      String label = ((ActionRef)aec).getLabel();
      Action act = (Action)actions.get(label);
      if ( act == null ) {
        if ( console != null ) {
          console.append("unknown action label: " + label + "\n");
        } else {
          System.out.println("unknown action label: " + label);
        }
      }
      return act;
    } else if ( aec instanceof Action ) {
      return (Action)aec;
    }
    return null;
  }

  public static float[] getActionParams(IActionElmChoice aec, float[] prms) {
    if ( aec instanceof ActionRef ) {
      ActionRef ar = (ActionRef)aec;
      float[] prm = new float[ar.getParamCount()];
      for ( int i=prm.length-1; i>=0 ; i-- ) {
        prm[i] = BulletmlUtil.getFloatValue(ar.getParam(i).getContent(), prms);
      }
      return prm;
    }
    return null;
  }

  //public static Fire getFireElm(IFireElmChoice fec) {
  public static Fire getFireElm(IActionChoice fec) {
    if ( fec instanceof FireRef ) {
      String label = ((FireRef)fec).getLabel();
      Fire fire = (Fire)fires.get(label);
      if ( fire == null ) {
        if ( console != null ) {
          console.append("unknown fire label: " + label + "\n");
        } else {
          System.out.println("unknown fire label: " + label);
        }
      }
      return fire;
    } else if ( fec instanceof Fire ) {
      return (Fire)fec;
    }
    return null;
  }

 // public static float[] getFireParams(IFireElmChoice fec, float[] prms) {
  public static float[] getFireParams(IActionChoice fec, float[] prms) {
    if ( fec instanceof FireRef ) {
      FireRef fr = (FireRef)fec;
      float[] prm = new float[fr.getParamCount()];
      for ( int i=prm.length-1; i>=0 ; i-- ) {
        prm[i] = BulletmlUtil.getFloatValue(fr.getParam(i).getContent(), prms);
      }
      return prm;
    }
    return null;
  }
}
