package com.fitbank.web;

import java.sql.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.fitbank.common.crypto.Decrypt;
import com.fitbank.common.logger.FitbankLogger;
import com.fitbank.common.properties.PropertiesHandler;
import com.fitbank.dto.GeneralResponse;
import com.fitbank.dto.management.Detail;
import com.fitbank.dto.management.Field;
import com.fitbank.dto.management.Record;
import com.fitbank.dto.management.Table;

public class Search {

	public static final String PARAM_QUERY = "_query";

	public static final String PARAM_ID = "_id";

	public static PropertiesHandler jsonProp = null;

	private HttpServletRequest request;

	private HttpSession session;

	private DataManage dm;

	private String query;

	private String tableId;

	private String security;

	private Map<String, String> parameters = new HashMap<String, String>();

	private String data = "";

	@SuppressWarnings("unchecked")
	public Search(HttpServletRequest pRequest) throws Exception {
		this.request = pRequest;
		this.session = this.request.getSession();
		this.dm = (DataManage) this.session.getAttribute("dm");
		this.query = this.request.getParameter(PARAM_QUERY);
		this.tableId = this.request.getParameter(PARAM_ID);
		if (jsonProp == null) {
			jsonProp = new PropertiesHandler("json");
		}
		if ((this.query != null) && (this.query.compareTo("trnPage") == 0)) {
			this.session.setAttribute("_responseCode", "0");
		}

		Enumeration<String> param = this.request.getParameterNames();
		while (param.hasMoreElements()) {
			String paramName = param.nextElement();

			if ((paramName.indexOf("cLov_") < 0) && (paramName.indexOf("pLov_") < 0)) {
				continue;
			}
			String val = this.request.getParameter(paramName).trim();
			if (val.compareTo("_") == 0) {
				val = "";
			}

			// paramName = paramName.replaceAll("cLov_", "");
			paramName = paramName.replaceAll("pLov_", "cLov_");
			this.parameters.put(paramName, val);
		}
	}

	public String executeQuery() throws Exception {
		Detail det = this.prepareDetail();
		if (this.query.indexOf("CTL_") == 0) {
			det = this.prepareCombo(det, this.query);
		} else {
			BussinessDelegate bd = new BussinessDelegate();
			det = bd.process(det);
		}
		return this.manageResponse(det);
	}

	private String formatDataFinal(Iterable<Record> pData, String pId, String[] pFields) {
	    	String data = "{identifier:\"" + pId + "\",";
		data += "items: [";
		boolean first = true;
		for (Record record : pData) {
			if (first) {
				first = false;
			} else {
				data += ",";
			}
			data += "{";
			String aux=""+record.findFieldByNameCreate(pId).getValue();
			data += pId + ":'" + aux.replace("'", "\\'") + "'";
			if (pFields != null) {
				for (String field : pFields) {
					Field f = record.findFieldByNameCreate(field);
					Object val = f.getValue();
					if (val instanceof Date) {
						try {
							data += "," + field + ":'" + f.getDateValue() + "'";
						} catch (Exception e) {
							data += "," + field + ":'" + val + "'";
						}
					} else {
						aux=""+val;
						data += "," + field + ":'" + aux.replace("'", "\\'") + "'";
					}
				}
			} else {
				for (Field field : record.getFields()) {
					String fname = field.getRealName();
					fname = fname.replace('.', '_');
					fname = fname.replace('+', '_');
					if (fname.compareTo(pId) == 0) {
						continue;
					}
					aux=""+field.getValue();
					data += "," + fname + ":'" + aux.replace("'", "\\'") + "'";
				}
			}
			data += "}";
		}
		return data + "]}";
	}

	private boolean jsonQueryData(Detail pDetail) throws Exception {
		Table table = pDetail.findTableByAlias((String) pDetail.findFieldByNameCreate("LOV_DATA").getValue());
		if (table.getRecordCount() <= 0) {
			this.data = "{identifier:\"id\",";
			this.data += "items:[{id:-1,error:true, msg:\"OK\"}]}";
			return true;
		}
		this.data = this.formatDataFinal(table.getRecords(), this.tableId, null);
		return true;
	}

	private String manageResponse(Detail pDet) throws Exception {
		if (pDet.getResponse().getCode().compareTo(GeneralResponse.OK) != 0) {
			String data = "{identifier:\"id\",";
			data += "items:[{id:-1,error:true, msg:\"" + pDet.getResponse().getUserMessage() + "\"}]}";
			return data;
		}

		if (this.jsonQueryData(pDet)) {
			return this.data;
		}
		throw new Exception("Consulta " + this.query + " no implementada");
	}

	private Detail prepareCombo(Detail pDetail, String pQuery) throws Exception {
		pDetail.findFieldByNameCreate("LOV_DATA").setValue("combo");
		Table table = new Table("COMBO", "combo");
		table.setReadonly(true);
		Detail det = (Detail) this.dm.get("det");
		String field = pQuery.substring(4);
		Field f = null;
		if (field.indexOf("|") < 0) {
			f = det.findFieldByNameCreate(field);
		} else {
			try {
				String[] dir = field.split("|");
				FitbankLogger.getLogger().debug(">>>Direccion " + dir[0] + " " + dir[1]);
				Table t = pDetail.findTableByAlias(dir[0]);
				Record r = t.getStructure();
				f = r.findFieldByName(dir[1]);
			} catch (Exception er) {
				throw new Exception("Error al encontrar el campo de combo " + field, er);
			}
		}
		try {
			List<String> codes = f.getComboCodes();
			List<String> labels = f.getComboLabels();
			if (codes.size() != labels.size()) {
				throw new Exception("CODIGOS Y ETIQUETAS DIFERENTES");
			}
			for (int i = 0; i < codes.size(); i++) {
				String code = codes.get(i);
				String label = labels.get(i);
				Record rec = new Record();
				rec.findFieldByNameCreate("ID").setValue(code);
				rec.findFieldByNameCreate("LABEL").setValue(label);
				table.addRecord(rec);
			}
			pDetail.addTable(table);
			pDetail.setResponse(new GeneralResponse(GeneralResponse.OK));
		} catch (Exception e) {
			throw new Exception(e.getMessage() + " " + f.getName(), e);

		}
		return pDetail;
	}

	private Detail prepareDetail() throws Exception {
		Detail det = new Detail();
		this.security = jsonProp.getStringValue("json." + this.query + ".security");
		try {
			if ((this.security == null) || (this.security.compareTo("false") != 0)) {
				this.dm.prepareHeaderData(det, this.request);
			} else {
				this.prepareHeaderDataWithoutLogIn(det);
			}
		} catch (Exception e) {
			throw new Exception("EL USUARIO NO ESTA INGRESADO ", e);
		}
		det.setType(MessageTypes.CON.name());
		det.setSubsystem("03");
		det.setTransaction("7003");
		det.setVersion("01");
		det.findFieldByNameCreate("NAME").setValue(this.query);
		for (String key : this.parameters.keySet()) {
			det.findFieldByNameCreate(key).setValue(this.parameters.get(key));
		}
		return det;
	}

	private void prepareHeaderDataWithoutLogIn(Detail pDetail) throws Exception {
		pDetail.setUser(jsonProp.getStringValue("json." + this.query + ".user"));
		Decrypt de = new Decrypt();
		if (!de.isWebencrypt()) {
			pDetail.setPassword(de.encrypt(jsonProp.getStringValue("json." + this.query + ".password")));
		}
		pDetail.setIpaddress("0.0.0.0");
		pDetail.setSessionid(jsonProp.getStringValue("json." + this.query + ".sessionId"));
		pDetail.setLanguage(jsonProp.getStringValue("json." + this.query + ".language"));
		pDetail.setTerminal(jsonProp.getStringValue("json." + this.query + ".terminal"));
		pDetail.setChannel(jsonProp.getStringValue("json." + this.query + ".channel"));
		pDetail.setRole(new Integer(jsonProp.getStringValue("json." + this.query + ".rol")));
		pDetail.setCompany(new Integer(jsonProp.getStringValue("json." + this.query + ".company")));
		pDetail.setOriginbranch(new Integer(jsonProp.getStringValue("json." + this.query + ".originbranch")));
		pDetail.setOriginoffice(new Integer(jsonProp.getStringValue("json." + this.query + ".originoffice")));
		pDetail.setSecuritylevel(new Integer(jsonProp.getStringValue("json." + this.query + ".securitylevel")));
		pDetail.setAccountingdate(new java.sql.Date(System.currentTimeMillis()));
		pDetail.findFieldByNameCreate("_AUTOLOTE").setValue(1);
	}
	
}
