package com.cidat.proclets;

import gnu.regexp.RE;
import gnu.regexp.REException;
import gnu.regexp.REMatch;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class SqlProclet implements Proclet {
	String[] retNames;
	boolean[] retArray;
	int[] retIndex;
	String[] querys;
	Hashtable[] exceptions;
	String[] functionName;
	String[][] functionArgTypes;
	String[][] functionArgs;
	String[][] functionOutputVal;
	String[] functionCallStatementStr;
	String[] cacheNameExprs;
	Proclet beforeCommit;
	protected LogProclet logSql = null;
	protected LogProclet logSqlError = null;
	public static final String logFile = "sqlproclet.txt";
	public static final String logValName = "com.cidat.proclets.SqlProclet.querySql";
	public static final String logErrorValName = "com.cidat.proclets.SqlProclet.error_querySql";
	protected boolean initOk = true;
	public static final int NODATA_ERRORCODE = 0;
	public static final String NODATA_ERROR = "el query no ha devuelto ningún dato";
	private static RE queryFormat = null;
	private static RE functionCallFormat = null;
	private static RE outFunctionValFormat = null;

	public SqlProclet(String querysDefs) {
		this.beforeCommit = null;
		try {
			this.logSql = new LogProclet("sqlproclet.txt",
					"${com.cidat.proclets.SqlProclet.querySql}");
			this.logSqlError = new LogProclet(
					"sqlproclet.txt",
					"${com.cidat.proclets.SqlProclet.error_querySql} ${com.cidat.proclets.SqlProclet.querySql}");

			String[] queryDefsArr = ProcletServiceData.valListToArr(querysDefs,
					";");
			this.querys = new String[queryDefsArr.length];
			this.retNames = new String[this.querys.length];
			this.retArray = new boolean[this.querys.length];
			this.retIndex = new int[this.querys.length];
			this.exceptions = new Hashtable[this.querys.length];
			this.cacheNameExprs = new String[this.querys.length];

			this.functionName = new String[this.querys.length];
			this.functionArgTypes = new String[this.querys.length][];
			this.functionArgs = new String[this.querys.length][];
			this.functionOutputVal = new String[this.querys.length][];
			this.functionCallStatementStr = new String[this.querys.length];

			for (int n = 0; n < this.querys.length; n++) {
				if (!queryFormat.isMatch(queryDefsArr[n])) {
					throw new ValException(
							"Formato de la definición de la sentencia SQL errónea: \""
									+ queryDefsArr[n] + "\"");
				}

				REMatch reM = queryFormat.getMatch(queryDefsArr[n]);

				this.retNames[n] = reM.toString(1);
				this.retArray[n] = (reM.toString(2).length() > 0 ? true : false);
				this.retIndex[n] = (reM.toString(4).length() / 2);
				if ((this.retArray[n] == false) && (this.retIndex[n] > 0)) {
					throw new ValException(
							"No se puede activar .index[] sin array: \""
									+ queryDefsArr[n] + "\"");
				}
				String[] exceptionsArr = ProcletServiceData.valListToArr(
						reM.toString(7), ",");
				if (exceptionsArr.length > 0)
					this.exceptions[n] = new Hashtable();
				for (int nE = 0; nE < exceptionsArr.length; nE++) {
					int nEq = exceptionsArr[nE].indexOf(':');
					String valName = exceptionsArr[nE].substring(0, nEq);
					int error = Integer.parseInt(exceptionsArr[nE]
							.substring(nEq + 1));
					this.exceptions[n].put(new Integer(error), valName);
				}
				this.cacheNameExprs[n] = reM.toString(9);
				if (this.cacheNameExprs[n].length() == 0)
					this.cacheNameExprs[n] = null;
				this.querys[n] = changeQuotedExprToEscapeDb(reM.toString(10));
				this.functionName[n] = null;

				if (!this.querys[n].startsWith("F("))
					continue;
				if (this.cacheNameExprs[n] != null) {
					throw new ValException(
							"No se soporta cacheo de llamadas a procedimientos almacenados: \""
									+ this.querys[n] + "\"");
				}
				REMatch reMF = functionCallFormat.getMatch(this.querys[n]);
				if (reMF == null) {
					throw new ValException(
							"Llamada a función con formato no entendido: \""
									+ this.querys[n] + "\"");
				}
				this.functionArgTypes[n] = ProcletServiceData.valListToArr(reMF
						.toString(1));
				this.functionName[n] = reMF.toString(4);
				this.functionArgs[n] = ProcletServiceData.valListToArr(reMF
						.toString(5));
				this.functionOutputVal[n] = new String[this.functionArgs[n].length];

				if (this.functionArgs[n].length != this.functionArgTypes[n].length) {
					throw new ValException(
							"En la llamada a funcion, no coinciden el numero de argumentos con el numero declarado: \""
									+ this.querys[n] + "\"");
				}
				this.functionCallStatementStr[n] = ("{call " + this.functionName[n]);
				if (this.functionArgs[n].length > 0) {
					for (int nA = 0; nA < this.functionArgs[n].length; nA++) {
						int tmp808_807 = n;
						String[] tmp808_804 = this.functionCallStatementStr;
						tmp808_804[tmp808_807] = (tmp808_804[tmp808_807] + (nA == 0 ? "(?"
								: ",?"));
						if (this.functionArgTypes[n][nA].indexOf("O") >= 0) {
							REMatch reMO = outFunctionValFormat
									.getMatch(this.functionArgs[n][nA]);
							if (reMO == null)
								throw new ValException(
										"En la llamada a función, en el parámetro de salida número "
												+ (nA + 1)
												+ ", no se especifica un valor en la forma ${valor}: \""
												+ this.querys[n] + "\"");
							this.functionOutputVal[n][nA] = reMO.toString(1);
						}
					}
					int tmp962_961 = n;
					String[] tmp962_958 = this.functionCallStatementStr;
					tmp962_958[tmp962_961] = (tmp962_958[tmp962_961] + ")");
				}
				int tmp988_987 = n;
				String[] tmp988_984 = this.functionCallStatementStr;
				tmp988_984[tmp988_987] = (tmp988_984[tmp988_987] + "}");
			}

		} catch (Exception e) {
			System.out.println("[Proclets] SqlProclet ERROR: " + e.toString());
			this.initOk = false;
		}
	}

	public SqlProclet(String querysDefs, Proclet procletBeforeCommit) {
		this(querysDefs);
		this.beforeCommit = procletBeforeCommit;
	}

	public void process(ProcletServiceData sd) throws ProcletException {
		if (!this.initOk) {
			throw new ProcletException(
					sd,
					"SqlProclet:: Error de sintaxis en la definición de la sentencia SQL (el parámetro aQuerysDefs del constructor de SqlProclet no tiene el formato correcto)");
		}

		Connection conn = null;
		Statement st = null;
		boolean conn_error = false;

		int nQ = -1;
		try {
			for (nQ = 0; nQ < this.querys.length; nQ++) {
				String query = null;
				String cacheName = this.cacheNameExprs[nQ] == null ? null : sd
						.evalExpr(this.cacheNameExprs[nQ]);

				if (this.functionName[nQ] == null) {
					query = sd.evalExpr(this.querys[nQ]);
					if (isCached(sd, cacheName, query))
						continue;
				}
				Hashtable cacheVals = cacheName == null ? null
						: new Hashtable();
				sd.setVal("com.cidat.proclets.SqlProclet.querySql", query);

				if (conn == null) {
					conn = openConnection(sd);
					conn.setAutoCommit(false);
				}

				if (this.functionName[nQ] != null) {
					st = conn.prepareCall(this.functionCallStatementStr[nQ]);
					executeFunctionCall(sd, nQ, (CallableStatement) st,
							cacheVals);
				} else {
					st = conn.createStatement();
					if (sd.debugVersion) {
						this.logSql.process(sd);
					}
					st.execute(query);
				}

				if ((this.retNames[nQ] != null)
						&& (this.retNames[nQ].length() > 0)) {
					ResultSet rs = st.getResultSet();
					ResultSetMetaData rsmd = rs.getMetaData();
					String[] colums = new String[rsmd.getColumnCount()];
					for (int n = 0; n < colums.length; n++) {
						colums[n] = rsmd.getColumnName(n + 1).toLowerCase();
					}

					int nL = 0;

					int[] pIndex = new int[this.retIndex[nQ]];
					String[] lastVal = new String[this.retIndex[nQ]];

					for (int i = 0; i < this.retIndex[nQ]; i++) {
						pIndex[i] = 0;
						lastVal[i] = null;
					}

					while ((rs.next())
							&& ((nL <= 0) || (this.retArray[nQ] != false))) {
						String index = "";
						String indexAsoc = "";
						for (int nC = 0; nC < colums.length; nC++) {
							String col = rs.getString(nC + 1);
							if (col == null)
								col = "";
							if (this.retArray[nQ] != false)
								setVal(sd,
										this.retNames[nQ] + "["
												+ String.valueOf(nL) + "]."
												+ colums[nC], col, cacheVals);
							else {
								setVal(sd,
										this.retNames[nQ] + "." + colums[nC],
										col, cacheVals);
							}
							if (nC >= this.retIndex[nQ]) {
								continue;
							}
							if ((pIndex[nC] == 0) || (!lastVal[nC].equals(col))) {
								lastVal[nC] = col;
								String newIndex = index + "[" + pIndex[nC]
										+ "]";
								setVal(sd, this.retNames[nQ] + ".index"
										+ newIndex, String.valueOf(nL),
										cacheVals);
								String newIndexAssoc = indexAsoc + "{"
										+ lastVal[nC] + "}";
								setVal(sd, this.retNames[nQ] + ".index"
										+ newIndexAssoc, String.valueOf(nL),
										cacheVals);
								String prevIndex = index + "["
										+ (pIndex[nC] - 1) + "]";
								incrementAndCloseIndex(sd, nC, nQ, prevIndex,
										pIndex, lastVal, cacheVals);
							}

							index = index + "[" + (pIndex[nC] - 1) + "]";
							indexAsoc = indexAsoc + "{" + lastVal[nC] + "}";
						}

						nL++;
					}

					rs.close();
					rs = null;
					st.close();
					st = null;

					if ((this.retArray[nQ] == false) && (nL == 0)) {
						handleError(sd, nQ, 0,
								"el query no ha devuelto ningún dato");
					}

					if (this.retArray[nQ] != false) {
						setVal(sd, this.retNames[nQ] + ".length",
								String.valueOf(nL), cacheVals);
					}

					if (this.retIndex[nQ] > 0) {
						incrementAndCloseIndex(sd, -1, nQ, "", pIndex, lastVal,
								cacheVals);
					}
				}

				if (cacheVals != null) {
					saveCache(sd, cacheName, query, cacheVals);
					cacheVals = null;
				}

			}

			if (this.beforeCommit != null) {
				this.beforeCommit.process(sd);
			}
			if (conn != null)
				conn.commit();
		} catch (RuntimeException e) {
			logError(sd, e.toString());
			System.out
					.println("[Proclets] SqlProclet::process RunTimeException: "
							+ e.getMessage());
			rollback(conn);
			throw e;
		} catch (ProcletException e) {
			logError(
					sd,
					e.toString() + " Error: "
							+ sd.gOS("com.cidat.proclets.error"));
			System.out
					.println("[Proclets] SqlProclet::process ProcletException : "
							+ e.getMessage());
			rollback(conn);
			throw e;
		} catch (SQLException e) {
			logError(sd, e.toString());
			System.out.println("[Proclets] SqlProclet::process SQLException : "
					+ e.getMessage());
			rollback(conn);
			SQLException sqlE = e;

			if ((sd.servletSrv == 4) || (sd.servletSrv == 5)) {
				conn_error = true;
			}

			handleError(sd, nQ, sqlE.getErrorCode(), sqlE.toString());
		} finally {
			try {
				if (st != null) {
					st.close();
					st = null;
				}
				if (conn != null) {
					if (conn_error)
						conn = null;
					freeConnection(sd, conn);
					conn = null;
				}
			} catch (SQLException e) {
				System.out.println("[Proclets] SqlProclet:: ERROR en finally: "
						+ e.toString());
			}
		}
	}

	void rollback(Connection conn) {
		try {
			if (conn != null)
				conn.rollback();
		} catch (SQLException e) {
			System.out
					.println("[Proclets] SqlProclet::rollback ERROR en finally: "
							+ e.toString());
		}
	}

	void logError(ProcletServiceData sd, String errorStr) {
		if ((sd.debugVersion)
				&& (sd.exists("com.cidat.proclets.SqlProclet.querySql"))) {
			sd.setVal("com.cidat.proclets.SqlProclet.error_querySql", errorStr);
			try {
				this.logSqlError.process(sd);
			} catch (ProcletException le) {
				System.out
						.println("[Proclets] SqlProclet::logError ERROR en finally: "
								+ le.toString());
			}
		}
	}

	void executeFunctionCall(ProcletServiceData sd, int nQ,
			CallableStatement st, Hashtable cacheVals) throws SQLException {
		int nOutput = 0;
		for (int nA = 0; nA < this.functionArgs[nQ].length; nA++) {
			if (this.functionArgTypes[nQ][nA].indexOf("I") >= 0)
				st.setString(nA + 1, sd.evalExpr(this.functionArgs[nQ][nA]));
			if (this.functionArgTypes[nQ][nA].indexOf("O") >= 0) {
				st.registerOutParameter(nA + 1, 12);
				nOutput++;
			}
		}
		st.execute();
		if (nOutput > 0)
			for (int nA = 0; nA < this.functionArgs[nQ].length; nA++)
				if (this.functionArgTypes[nQ][nA].indexOf("O") >= 0)
					setVal(sd, sd.evalExpr(this.functionOutputVal[nQ][nA]),
							st.getString(nA + 1), cacheVals);
	}

	void handleError(ProcletServiceData sd, int nQ, int errorCode,
			String errorDes) throws ProcletException {
		if ((nQ >= 0) && (this.exceptions[nQ] != null)) {
			String excepVal = (String) this.exceptions[nQ].get(new Integer(
					errorCode));
			if (excepVal != null)
				throw new ProcletException(sd, excepVal, "true");
		}
		throw new ProcletException(sd, errorDes + " ERROR:" + errorCode
				+ "\n<BR> Query: "
				+ sd.gS("com.cidat.proclets.SqlProclet.querySql"));
	}

	void incrementAndCloseIndex(ProcletServiceData sd, int nC, int nQ,
			String index, int[] pIndex, String[] lastVal, Hashtable cacheVals) {
		if (nC >= 0) {
			int tmp7_6 = nC;
			int[] tmp7_4 = pIndex;
			int tmp9_8 = tmp7_4[tmp7_6];
			tmp7_4[tmp7_6] = (tmp9_8 + 1);
			if (tmp9_8 == 0) {
				return;
			}
		}

		String indexCpy = index;
		for (int n = nC + 1; n < this.retIndex[nQ]; n++) {
			if (pIndex[n] == 0)
				break;
			setVal(sd, this.retNames[nQ] + ".index" + indexCpy + ".length",
					String.valueOf(pIndex[n]), cacheVals);

			indexCpy = indexCpy + "[" + (pIndex[n] - 1) + "]";
			pIndex[n] = 0;
			lastVal[n] = null;
		}
	}

	void setVal(ProcletServiceData sd, String name, String value,
			Hashtable cacheVals) {
		sd.setVal(name, value);

		if (cacheVals != null) {
			cacheVals.put(new String(name), new String(value));
		}
	}

	boolean isCached(ProcletServiceData sd, String cacheName, String query)
			throws ProcletException {
		if (cacheName == null) {
			return false;
		}
		Hashtable cacheVals = (Hashtable) sd.getCache().getCacheObject(
				cacheName, query);
		if (cacheVals == null) {
			return false;
		}
		for (Enumeration e = cacheVals.keys(); e.hasMoreElements();) {
			String name = (String) e.nextElement();
			sd.setVal(name, cacheVals.get(name));
		}
		cacheVals = null;

		if (sd.debugVersion) {
			sd.setVal("com.cidat.proclets.SqlProclet.querySql",
					"RECOGIDO DEL CACHE: " + query);
			this.logSql.process(sd);
		}

		return true;
	}

	void saveCache(ProcletServiceData sd, String cacheName, String query,
			Hashtable cacheVals) throws ProcletException {
		sd.getCache().saveCacheObject(cacheName, query, cacheVals);
		if (sd.debugVersion) {
			sd.setVal("com.cidat.proclets.SqlProclet.querySql",
					"GUARDADO EN EL CACHE: " + query);
			this.logSql.process(sd);
		}
	}

	public static Connection openConnection(ProcletServiceData sd)
			throws ProcletException, SQLException {
		return sd.servletSrv == 5 ? openConnectionOracle9iAS(sd)
				: sd.servletSrv == 4 ? openConnectionTomcat(sd)
						: (sd.servletSrv == 3) && (sd.servletSrvVersion > 8) ? openConnectionWebLogic11(sd)
								: (sd.servletSrv == 3)
										&& (sd.servletSrvVersion > 5)
										&& (sd.servletSrvVersion < 9) ? openConnectionWebLogic8(sd)
										: (sd.servletSrv == 2)
												|| ((sd.servletSrv == 1) && (sd.servletSrvVersion >= 3))
												|| ((sd.servletSrv == 3) && (sd.servletSrvVersion == 5)) ? openConnectionNasWebLogic5JRun3Jrun4(sd)
												: (sd.servletSrv == 3)
														&& (sd.servletSrvVersion < 5) ? openConnectionWebLogic4(sd)
														: (sd.servletSrv == 1)
																&& (sd.servletSrvVersion < 3) ? openConnectionJRun2(sd)
																: openConnectionNoPool(sd);
	}

	public static Connection openConnectionWebLogic4(ProcletServiceData sd)
			throws ProcletException {
		Connection conn = null;
		try {
			String[] connData = ProcletServiceData
					.valListToArr(sd.dataSourceName);
			if (connData.length != 3)
				throw new ProcletException(
						sd,
						"Formato incorrecto de DataSourceName. Debe ser jdbc:weblogic:pool:nombrePool,usuario,clave");
			Class.forName("weblogic.jdbc.pool.Driver").newInstance();
			conn = DriverManager.getConnection(connData[0], connData[1],
					connData[2]);
		} catch (ProcletException e) {
			throw e;
		} catch (Exception e) {
			throw new ProcletException(sd,
					"SqlProclet.openConnectionWebLogic4: " + e.toString());
		}
		return conn;
	}

	public static Connection openConnectionNasWebLogic5JRun3Jrun4(
			ProcletServiceData sd) throws ProcletException {
		DataSource ds = null;
		Context conx = null;
		try {
			conx = new InitialContext();
			String dsName = ((sd.servletSrv == 1)
					&& (sd.servletSrvVersion == 3) ? "java:comp/env/jdbc/" : "")
					+ sd.dataSourceName;
			ds = (DataSource) conx.lookup(dsName);
			if (ds == null)
				throw new ProcletException(sd,
						"No se ha encontrado el pool de conexion a la base de datos "
								+ dsName);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Error NamingExc: " + e.getMessage());
			throw new ProcletException(sd,
					"No se ha encontrado el pool de conexion a la base de datos "
							+ sd.dataSourceName);
		}
		try {
			Connection conn = ds.getConnection();
			return conn;
		} catch (Exception e) {
			System.out.println("SqlProclet.openConnectionNasWebLogic5JRun3: "
					+ e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	public static Connection openConnectionWebLogic8(ProcletServiceData sd)
			throws ProcletException {
		DataSource ds = null;
		Context ctx = null;
		Connection conn = null;
		try {
			Hashtable ht = new Hashtable();
			ht.put("java.naming.factory.initial",
					"weblogic.jndi.WLInitialContextFactory");

			ctx = new InitialContext(ht);
			ds = (DataSource) ctx.lookup(sd.dataSourceName);
			conn = ds.getConnection();
		} catch (Exception e) {
			throw new ProcletException(sd,
					"SqlProclet.openConnectionWebLogic8: " + e.toString());
		}
		return conn;
	}

	public static Connection openConnectionWebLogic11(ProcletServiceData sd)
			throws ProcletException {
		DataSource ds = null;
		Context ctx = null;
		Connection conn = null;
		try {
			Hashtable ht = new Hashtable();
			ht.put("java.naming.factory.initial",
					"weblogic.jndi.WLInitialContextFactory");

			ctx = new InitialContext(ht);
			ds = (DataSource)ctx.lookup(sd.dataSourceName);
			conn = ds.getConnection();
		} catch (Exception e) {
			throw new ProcletException(sd,
					"SqlProclet.openConnectionWebLogic11: " + e.toString());
		}
		return conn;
	}

	public static Connection openConnectionJRun2(ProcletServiceData sd)
			throws ProcletException {
		Connection conn = DBConnectionManager.getInstance().getConnection(
				sd.dataSourceName);
		if (conn == null)
			throw new ProcletException(sd,
					"No se ha encontrado el pool de conexion a la base de datos "
							+ sd.dataSourceName);
		return conn;
	}

	public static Connection openConnectionTomcat(ProcletServiceData sd)
			throws ProcletException {
		Connection conn = DBConnectionManager.getInstance().getConnection(
				sd.dataSourceName);
		if (conn == null) {
			throw new ProcletException(
					sd,
					"SqlProclet.openConnectionTomcat: No se ha encontrado el pool de conexion a la base de datos "
							+ sd.dataSourceName);
		}
		return conn;
	}

	public static Connection openConnectionOracle9iAS(ProcletServiceData sd)
			throws ProcletException {
		Connection conn = DBConnectionManager.getInstance().getConnection(
				sd.dataSourceName);
		if (conn == null) {
			throw new ProcletException(
					sd,
					"SqlProclet.openConnectionOracle9iAS: No se ha encontrado el pool de conexion a la base de datos "
							+ sd.dataSourceName);
		}
		return conn;
	}

	public static Connection openConnectionNoPool(ProcletServiceData sd)
			throws ProcletException {
		Connection conn = null;
		try {
			String[] connData = ProcletServiceData
					.valListToArr(sd.dataSourceName);
			if (connData.length != 3)
				throw new ProcletException(
						sd,
						"Formato incorrecto de DataSourceName. Debe ser jdbc:oracle:thin:@[ip_host]:1521:[SID],[usuario],[clave]");
			Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
			conn = DriverManager.getConnection(connData[0], connData[1],
					connData[2]);
		} catch (ProcletException e) {
			throw e;
		} catch (Exception e) {
			throw new ProcletException(sd, "SqlProclet.openConnectionNoPool: "
					+ e.toString());
		}
		return conn;
	}

	public static void freeConnection(ProcletServiceData sd, Connection conn)
			throws SQLException {
		if (((sd.servletSrv == 1) && (sd.servletSrvVersion < 3))
				|| (sd.servletSrv == 4) || (sd.servletSrv == 5)) {
			DBConnectionManager.getInstance().freeConnection(sd.dataSourceName,
					conn);
			return;
		}

		conn.close();
	}

	static String changeQuotedExprToEscapeDb(String expression) {
		StringBuffer ret = new StringBuffer();
		int i = 0;
		while (i < expression.length()) {
			int iniQuote = expression.indexOf("'", i);
			int endQuote = -1;
			if (iniQuote >= 0)
				endQuote = expression.indexOf("'", iniQuote + 1);
			if ((iniQuote < 0) || (endQuote < 0)) {
				ret.append(expression.substring(i));
				return ret.toString();
			}
			ret.append(expression.substring(i, iniQuote));
			ret.append("'");
			ret.append(changeExprToEscapeDb(expression.substring(iniQuote + 1,
					endQuote)));
			ret.append("'");
			i = endQuote + 1;
		}
		return ret.toString();
	}

	static String changeExprToEscapeDb(String expression) {
		StringBuffer ret = new StringBuffer();
		int i = 0;

		String opVal = "${";
		String opValDbEscape = "$[dbEscape]{";

		while (i < expression.length()) {
			boolean dbEscape = false;
			int ini = -1;

			int nSearchDollar = i;
			while (true) {
				int nDollar = expression.indexOf('$', nSearchDollar);
				if (nDollar == -1)
					break;
				ini = nDollar;
				if (expression.indexOf(opVal, nDollar) == nDollar)
					break;
				if (expression.indexOf(opValDbEscape, nDollar) == nDollar) {
					dbEscape = true;
					break;
				}
				ini = -1;
				nSearchDollar = nDollar + 1;
			}

			if (ini < 0) {
				ret.append(expression.substring(i));
				return ret.toString();
			}

			int nOpen = 1;
			int iniBetweenBrackets = ini
					+ (dbEscape ? opValDbEscape.length() : opVal.length());
			int end = iniBetweenBrackets;

			char prevChar = '\000';
			while (end < expression.length()) {
				char ch = expression.charAt(end);
				if ((prevChar == '$') && (ch == '{'))
					nOpen++;
				else if (ch == '}')
					nOpen--;
				if (nOpen == 0)
					break;
				prevChar = ch;
				end++;
			}
			if (end >= expression.length()) {
				ret.append(expression.substring(i));
				return ret.toString();
			}

			ret.append(expression.substring(i, ini));
			if (!dbEscape) {
				ret.append(opValDbEscape);
				ret.append(expression.substring(iniBetweenBrackets, end + 1));
			} else {
				ret.append(expression.substring(ini, end + 1));
			}
			i = end + 1;
		}

		return ret.toString();
	}

	static {
		try {
			queryFormat = new RE(
					"([.a-zA-Z0-9_]*)(\\[\\])?(\\.index((\\[\\])+))?(\\{(,?[.a-zA-Z0-9_]*:[0-9]+(,[.a-zA-Z0-9_]*:[0-9]+)*,?)\\})?\\s*=\\s*(\\[[a-zA-Z0-9._${}]+\\])?\\s*(.*)");
			functionCallFormat = new RE(
					"F\\(((I?O?)?(,I?O?)*)\\)\\s+([a-zA-Z0-9_]+)\\s*\\((.*)\\)\\s*");
			outFunctionValFormat = new RE("^\\s*\\$\\{(.*)\\}\\s*$");
		} catch (REException e) {
			System.out
					.println("Error en SqlProclet, en queryFormat, functionCallFormat o outFunctionValFormat: \""
							+ e.toString() + "\"");
		}
	}
}

/*
 * Location:
 * D:\svn\ejie\q53.trunk\codigo\q53\q53ItourbaskWar\WebContent\WEB-INF\
 * lib\proclets_wl81.jar Qualified Name: com.cidat.proclets.SqlProclet JD-Core
 * Version: 0.6.0
 */