package com.tcs.wenrgise.util.common;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

public class FWSAXParser extends DefaultHandler {
  private String lastName;
  
  private Stack aStack = new Stack();
  
  private Object objFinal;
  
  private String sPackage = "";
  
  void setPackage(String sPackage_) {
    this.sPackage = sPackage_;
  }
  
  void setObject(Object obj) {
    this.objFinal = obj;
  }
  
  Object getFinalObject() {
    return this.objFinal;
  }
  
  public void startElement(String uri, String name, String qName, Attributes atts) {
    this.lastName = new String(name);
    this.sCharStringBuffer = new StringBuffer();
    try {
      this.aStack.push(name);
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    } 
  }
  
  public void endElement(String uri, String name, String qName) {
    try {
      this.sPathMap = getPathMap();
      String sChar = this.sCharStringBuffer.toString();
      String sTempChar = new String(sChar);
      sTempChar = sTempChar.replace('\r', ' ');
      sTempChar = sTempChar.replace('\n', ' ');
      sTempChar = sTempChar.trim();
      if (sChar != null && sChar.length() > 0 && sTempChar.length() > 0)
        populateValue(sChar, this.sPathMap); 
      this.sCharStringBuffer = new StringBuffer();
      String sTopElement = this.aStack.pop();
      if (sTopElement.equals(name)) {
        addToHashMap(getPathMap(this.sPathMap));
      } else {
        this.aStack.push(sTopElement);
      } 
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    } 
  }
  
  ArrayList sPathMap = null;
  
  StringBuffer sCharStringBuffer = new StringBuffer();
  
  public void characters(char[] ch, int start, int length) {
    try {
      this.sCharStringBuffer.append(new String(ch, start, length));
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    } 
  }
  
  private ArrayList getPathMap() {
    ArrayList aList = new ArrayList(this.aStack.size());
    for (int i = 0; i < this.aStack.size(); i++)
      aList.add(this.aStack.get(i)); 
    return aList;
  }
  
  private void populateValue(Object value, ArrayList aPathMap) throws Exception {
    StringBuffer sbfGetMethodName = new StringBuffer(20);
    StringBuffer sbfSetMethodName = new StringBuffer(20);
    try {
      if (null == aPathMap)
        return; 
      Object objOriginal = this.objFinal;
      Object objTempCurrent = this.objFinal;
      ArrayList aTempPathMap = new ArrayList();
      aTempPathMap.add(aPathMap.get(0));
      for (int i = 1; i < aPathMap.size(); i++) {
        String sElement = aPathMap.get(i);
        aTempPathMap.add(sElement);
        sbfGetMethodName = (new StringBuffer("get_")).append(sElement);
        Method mGet = objTempCurrent.getClass().getMethod(sbfGetMethodName.toString(), null);
        Object objChild = mGet.invoke(objTempCurrent, null);
        if (objChild == null) {
          Class retClass = mGet.getReturnType();
          objChild = retClass.newInstance();
        } 
        if (objChild instanceof ArrayList) {
          sbfSetMethodName = (new StringBuffer("set_")).append(sElement);
          if (i == aPathMap.size() - 1) {
            ((ArrayList)objChild).add(value);
            Method mSet = objTempCurrent.getClass().getMethod(sbfSetMethodName.toString(), new Class[] { objChild.getClass() });
            mSet.invoke(objTempCurrent, new Object[] { objChild });
          } else {
            ArrayList aList = (ArrayList)objChild;
            Object objTemp = null;
            String sTempPathMap = getPathMap(aTempPathMap);
            int iCounter = getCounter(sTempPathMap);
            if (aList.size() > iCounter) {
              objTemp = aList.get(iCounter);
            } else {
              Class cTemp = Class.forName(this.sPackage + sElement);
              objTemp = cTemp.newInstance();
              aList.add(objTemp);
            } 
            Method mSet = objTempCurrent.getClass().getMethod(sbfSetMethodName.toString(), new Class[] { objChild.getClass() });
            mSet.invoke(objTempCurrent, new Object[] { objChild });
            objChild = objTemp;
          } 
        } else {
          if (i == aPathMap.size() - 1)
            objChild = value; 
          sbfSetMethodName = (new StringBuffer("set_")).append(sElement);
          Method mSet = objTempCurrent.getClass().getMethod(sbfSetMethodName.toString(), new Class[] { objChild.getClass() });
          mSet.invoke(objTempCurrent, new Object[] { objChild });
        } 
        objTempCurrent = objChild;
      } 
      this.objFinal = objOriginal;
    } catch (Exception e) {
      throw new Exception(String.valueOf(String.valueOf(e.getMessage()).concat(String.valueOf(" TAGMETHODNAME: "))).concat(String.valueOf(sbfGetMethodName.toString())));
    } 
  }
  
  private void addToHashMap(String sPathMap) {
    if (sPathMap == null || sPathMap.trim().length() <= 0)
      return; 
    Object objCounter = this.aCounterMap.get(sPathMap);
    Integer iCounter = null;
    if (objCounter != null) {
      iCounter = (Integer)objCounter;
    } else {
      iCounter = new Integer(0);
    } 
    iCounter = new Integer(iCounter.intValue() + 1);
    this.aCounterMap.put(sPathMap, iCounter);
    Set keySet = this.aCounterMap.keySet();
    Iterator itrKey = keySet.iterator();
    while (itrKey.hasNext()) {
      String sKey = itrKey.next();
      if (sKey.startsWith(sPathMap) && sKey.length() > sPathMap.length())
        this.aCounterMap.put(sKey, new Integer(0)); 
    } 
  }
  
  private int getCounter(String sPathMap) {
    if (sPathMap == null || sPathMap.trim().length() <= 0)
      return 0; 
    Object objCounter = this.aCounterMap.get(sPathMap);
    Integer iCounter = null;
    if (objCounter != null) {
      iCounter = (Integer)objCounter;
    } else {
      iCounter = new Integer(0);
    } 
    return iCounter.intValue();
  }
  
  private String getPathMap(ArrayList aPathMap) {
    if (aPathMap == null || aPathMap.size() <= 0)
      return null; 
    StringBuffer sTotStringBuffer = new StringBuffer();
    for (int i = 0; i < aPathMap.size(); i++)
      sTotStringBuffer.append(aPathMap.get(i)).append("/"); 
    return sTotStringBuffer.toString();
  }
  
  private HashMap aCounterMap = new HashMap(20);
}
