package net.sf.jasperreports.engine.design;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import net.sf.jasperreports.engine.JRExpressionChunk;
import net.sf.jasperreports.engine.base.JRBaseExpression;
import net.sf.jasperreports.engine.design.events.JRChangeEventsSupport;
import net.sf.jasperreports.engine.design.events.JRPropertyChangeSupport;

public class JRDesignExpression extends JRBaseExpression implements JRChangeEventsSupport {
  private static final long serialVersionUID = 10200L;
  
  public static final String PROPERTY_TEXT = "text";
  
  public static final String PROPERTY_VALUE_CLASS_NAME = "valueClassName";
  
  protected List chunks = new ArrayList();
  
  private transient JRPropertyChangeSupport eventSupport;
  
  public JRDesignExpression() {
    regenerateId();
  }
  
  public void setValueClass(Class clazz) {
    setValueClassName(clazz.getName());
  }
  
  public void setValueClassName(String className) {
    Object old = this.valueClassName;
    this.valueClassName = className;
    this.valueClass = null;
    this.valueClassRealName = null;
    getEventSupport().firePropertyChange("valueClassName", old, this.valueClassName);
  }
  
  public void setId(int id) {
    this.id = id;
  }
  
  public JRExpressionChunk[] getChunks() {
    JRExpressionChunk[] chunkArray = null;
    if (this.chunks != null && this.chunks.size() > 0) {
      chunkArray = new JRExpressionChunk[this.chunks.size()];
      this.chunks.toArray((Object[])chunkArray);
    } 
    return chunkArray;
  }
  
  public void setChunks(List chunks) {
    this.chunks.clear();
    this.chunks.addAll(chunks);
  }
  
  public void addChunk(JRDesignExpressionChunk chunk) {
    this.chunks.add(chunk);
  }
  
  protected void addChunk(byte type, String text) {
    JRDesignExpressionChunk chunk = new JRDesignExpressionChunk();
    chunk.setType(type);
    chunk.setText(text);
    this.chunks.add(chunk);
  }
  
  public void addTextChunk(String text) {
    JRDesignExpressionChunk chunk = new JRDesignExpressionChunk();
    chunk.setType((byte)1);
    chunk.setText(text);
    this.chunks.add(chunk);
  }
  
  public void addParameterChunk(String text) {
    JRDesignExpressionChunk chunk = new JRDesignExpressionChunk();
    chunk.setType((byte)2);
    chunk.setText(text);
    this.chunks.add(chunk);
  }
  
  public void addFieldChunk(String text) {
    JRDesignExpressionChunk chunk = new JRDesignExpressionChunk();
    chunk.setType((byte)3);
    chunk.setText(text);
    this.chunks.add(chunk);
  }
  
  public void addVariableChunk(String text) {
    JRDesignExpressionChunk chunk = new JRDesignExpressionChunk();
    chunk.setType((byte)4);
    chunk.setText(text);
    this.chunks.add(chunk);
  }
  
  public void addResourceChunk(String text) {
    JRDesignExpressionChunk chunk = new JRDesignExpressionChunk();
    chunk.setType((byte)5);
    chunk.setText(text);
    this.chunks.add(chunk);
  }
  
  public void setText(String text) {
    Object old = getText();
    this.chunks.clear();
    if (text != null) {
      StringBuffer textChunk = new StringBuffer();
      StringTokenizer tkzer = new StringTokenizer(text, "$", true);
      int behindDelims = 0;
      while (tkzer.hasMoreTokens()) {
        String token = tkzer.nextToken();
        if (token.equals("$")) {
          if (behindDelims > 0)
            textChunk.append("$"); 
          behindDelims++;
          continue;
        } 
        byte chunkType = 1;
        if (behindDelims > 0)
          if (token.startsWith("P{")) {
            chunkType = 2;
          } else if (token.startsWith("F{")) {
            chunkType = 3;
          } else if (token.startsWith("V{")) {
            chunkType = 4;
          } else if (token.startsWith("R{")) {
            chunkType = 5;
          }  
        if (chunkType == 1) {
          if (behindDelims > 0)
            textChunk.append("$"); 
          textChunk.append(token);
        } else {
          int end = token.indexOf('}');
          if (end > 0) {
            if (behindDelims > 1) {
              textChunk.append(token);
            } else {
              if (textChunk.length() > 0)
                addTextChunk(textChunk.toString()); 
              addChunk(chunkType, token.substring(2, end));
              textChunk = new StringBuffer(token.substring(end + 1));
            } 
          } else {
            if (behindDelims > 0)
              textChunk.append("$"); 
            textChunk.append(token);
          } 
        } 
        behindDelims = 0;
      } 
      if (behindDelims > 0)
        textChunk.append("$"); 
      if (textChunk.length() > 0)
        addTextChunk(textChunk.toString()); 
    } 
    getEventSupport().firePropertyChange("text", old, text);
  }
  
  public JRPropertyChangeSupport getEventSupport() {
    synchronized (this) {
      if (this.eventSupport == null)
        this.eventSupport = new JRPropertyChangeSupport(this); 
    } 
    return this.eventSupport;
  }
  
  public Object clone() {
    JRDesignExpression clone = (JRDesignExpression)super.clone();
    if (this.chunks != null) {
      clone.chunks = new ArrayList(this.chunks.size());
      for (int i = 0; i < this.chunks.size(); i++)
        clone.chunks.add(((JRExpressionChunk)this.chunks.get(i)).clone()); 
    } 
    return clone;
  }
}
