package com.ejie.ab39a.dao;

import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.ejie.ab39a.constantes.Constantes;
import com.ejie.ab39a.constantes.SecuenciasSQL;
import com.ejie.ab39a.model.AccionesPg;
import com.ejie.ab39a.model.EjePe;
import com.ejie.ab39a.model.ElementosArbol;
import com.ejie.ab39a.model.ElementosPe;
import com.ejie.ab39a.model.ElementosPg;
import com.ejie.x38.dto.JQGridRequestDto;

/**
 * ElementosPeDaoImpl.
 * 
 *  
 */

@Repository
@Transactional
public class ElementosArbolDaoImpl implements ElementosArbolDao {

	private static final Logger logger = LoggerFactory.getLogger(ElementosArbolDaoImpl.class);

	private JdbcTemplate jdbcTemplate;

	/*
	 * ROW_MAPPERS
	 */
	private RowMapper<ElementosArbol> rwMap = new RowMapper<ElementosArbol>() {
		@Override
		public ElementosArbol mapRow(ResultSet rs, int rowNum) throws SQLException {

			ElementosArbol elemArbol = new ElementosArbol();
			EjePe nivel0 = null;
			ElementosPe nivel1 = null;
			ElementosPe nivel2 = null;
			ElementosPe nivel3 = null;
			List<ElementosArbol> listanivel0 = new ArrayList<ElementosArbol>();
			List<ElementosArbol> listanivel1 = new ArrayList<ElementosArbol>();
			List<ElementosArbol> listanivel2 = new ArrayList<ElementosArbol>();
			List<ElementosArbol> listanivel3 = new ArrayList<ElementosArbol>();
			Integer nivelAnterior = 0;
			Integer ejeAnterior = 0;
			do {

				if (rs.getInt("NIVEL") == Constantes.NIVEL_UNO) {

					nivel1 = new ElementosPe(rs.getLong("CODPLANE"), rs.getLong("CODELEMENTOPE"), rs.getLong("ORDEN"),
							rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"),
							rs.getString("HELBURU"), rs.getString("HELBURUCAS"), rs.getLong("ID_EJE"),
							rs.getBigDecimal("HAS_EUS"), rs.getBigDecimal("HAS_ELEBI"), rs.getBigDecimal("AURRE_EUS"),
							rs.getBigDecimal("AURRE_ELEBI"), rs.getBigDecimal("AMAI_EUS"),
							rs.getBigDecimal("AMAI_ELEBI"), rs.getLong("ELEMBASE"), rs.getString("OHARRAK"),
							rs.getLong("PONDERACION"), rs.getLong("TIENEELEBI"), rs.getLong("TIENEVALOR"),
							rs.getBigDecimal("HAS_VALOR"), rs.getBigDecimal("AURRE_VALOR"),
							rs.getBigDecimal("AMAI_VALOR"), rs.getLong("IDELEMENTO"), rs.getLong("TIENEEUS"),
							rs.getLong("TIENESINO"), rs.getLong("HAS_SINO"), rs.getLong("AURRE_SINO"),
							rs.getLong("AMAI_SINO"));

					if (ejeAnterior != rs.getLong("ID_EJE")) {
						nivel0 = new EjePe(rs.getLong("CODPLANE"), rs.getLong("ID_EJE"), rs.getLong("ORDEN_EJE"), 0l,
								rs.getString("NOMBRE_EJE"), rs.getString("NOMBRECAS_EJE"), rs.getString("HELBURU_EJE"),
								rs.getString("HELBURUCAS_EJE"), null, rs.getLong("PONDERACION_EJE"));
						listanivel0.add(nivel0);
						ejeAnterior = rs.getInt("ID_EJE");
						elemArbol.setHijosArbol(listanivel0);

						listanivel1 = new ArrayList<ElementosArbol>();
						listanivel1.add(nivel1);
					} else {
						listanivel1.add(nivel1);
					}

					nivel0.setHijosArbol(listanivel1);
					nivelAnterior = rs.getInt("NIVEL");

				} else if (rs.getInt("NIVEL") == Constantes.NIVEL_DOS) {

					nivel2 = new ElementosPe(rs.getLong("CODPLANE"), rs.getLong("CODELEMENTOPE"), rs.getLong("ORDEN"),
							rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"),
							rs.getString("HELBURU"), rs.getString("HELBURUCAS"), rs.getLong("CODELEMENTOPEPADRE"),
							rs.getBigDecimal("HAS_EUS"), rs.getBigDecimal("HAS_ELEBI"), rs.getBigDecimal("AURRE_EUS"),
							rs.getBigDecimal("AURRE_ELEBI"), rs.getBigDecimal("AMAI_EUS"),
							rs.getBigDecimal("AMAI_ELEBI"), rs.getLong("ELEMBASE"), rs.getString("OHARRAK"),
							rs.getLong("PONDERACION"), rs.getLong("TIENEELEBI"), rs.getLong("TIENEVALOR"),
							rs.getBigDecimal("HAS_VALOR"), rs.getBigDecimal("AURRE_VALOR"),
							rs.getBigDecimal("AMAI_VALOR"), rs.getLong("IDELEMENTO"), rs.getLong("TIENEEUS"),
							rs.getLong("TIENESINO"), rs.getLong("HAS_SINO"), rs.getLong("AURRE_SINO"),
							rs.getLong("AMAI_SINO"));
					if (nivelAnterior == 1) {
						listanivel2 = new ArrayList<ElementosArbol>();
						listanivel2.add(nivel2);
					} else {
						listanivel2.add(nivel2);
					}
					nivel1.setHijosArbol(listanivel2);
					nivelAnterior = rs.getInt("NIVEL");
				} else if (rs.getInt("NIVEL") == Constantes.NIVEL_TRES) {

					nivel3 = new ElementosPe(rs.getLong("CODPLANE"), rs.getLong("CODELEMENTOPE"), rs.getLong("ORDEN"),
							rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"),
							rs.getString("HELBURU"), rs.getString("HELBURUCAS"), rs.getLong("CODELEMENTOPEPADRE"),
							rs.getBigDecimal("HAS_EUS"), rs.getBigDecimal("HAS_ELEBI"), rs.getBigDecimal("AURRE_EUS"),
							rs.getBigDecimal("AURRE_ELEBI"), rs.getBigDecimal("AMAI_EUS"),
							rs.getBigDecimal("AMAI_ELEBI"), rs.getLong("ELEMBASE"), rs.getString("OHARRAK"),
							rs.getLong("PONDERACION"), rs.getLong("TIENEELEBI"), rs.getLong("TIENEVALOR"),
							rs.getBigDecimal("HAS_VALOR"), rs.getBigDecimal("AURRE_VALOR"),
							rs.getBigDecimal("AMAI_VALOR"), rs.getLong("IDELEMENTO"), rs.getLong("TIENEEUS"),
							rs.getLong("TIENESINO"), rs.getLong("HAS_SINO"), rs.getLong("AURRE_SINO"),
							rs.getLong("AMAI_SINO"));
					if (nivelAnterior == Constantes.NIVEL_DOS) {
						listanivel3 = new ArrayList<ElementosArbol>();
						listanivel3.add(nivel3);
					} else {
						listanivel3.add(nivel3);
					}
					nivel2.setHijosArbol(listanivel3);
					nivelAnterior = rs.getInt("NIVEL");
				}

			} while (rs.next());

			return elemArbol;
		}
	};

	private RowMapper<Map<Long, ElementosPe>> rwMapVersiones = new RowMapper<Map<Long, ElementosPe>>() {
		@Override
		public Map<Long, ElementosPe> mapRow(ResultSet rs, int rowNum) throws SQLException {

			Map<Long, ElementosPe> mapaLista = new HashMap<Long, ElementosPe>();
			ElementosPe nivel1 = null;
			do {

				nivel1 = new ElementosPe(rs.getLong("CODPLANE"), rs.getLong("CODELEMENTOPE"), rs.getLong("ORDEN"),
						rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"), rs.getString("HELBURU"),
						rs.getString("HELBURUCAS"), rs.getLong("ID_EJE"), rs.getBigDecimal("HAS_EUS"),
						rs.getBigDecimal("HAS_ELEBI"), rs.getBigDecimal("AURRE_EUS"), rs.getBigDecimal("AURRE_ELEBI"),
						rs.getBigDecimal("AMAI_EUS"), rs.getBigDecimal("AMAI_ELEBI"), rs.getLong("ELEMBASE"),
						rs.getString("OHARRAK"), rs.getLong("PONDERACION"), rs.getLong("TIENEELEBI"),
						rs.getLong("TIENEVALOR"), rs.getBigDecimal("HAS_VALOR"), rs.getBigDecimal("AURRE_VALOR"),
						rs.getBigDecimal("AMAI_VALOR"), rs.getLong("IDELEMENTO"), rs.getLong("TIENEEUS"),
						rs.getLong("TIENESINO"), rs.getLong("HAS_SINO"), rs.getLong("AURRE_SINO"),
						rs.getLong("AMAI_SINO"));

				mapaLista.put(rs.getLong("IDELEMENTO"), nivel1);

			} while (rs.next());

			return mapaLista;
		}
	};

	private RowMapper<Map<Long, EjePe>> rwMapVersionesEje = new RowMapper<Map<Long, EjePe>>() {
		@Override
		public Map<Long, EjePe> mapRow(ResultSet rs, int rowNum) throws SQLException {

			Map<Long, EjePe> mapaLista = new HashMap<Long, EjePe>();
			EjePe nivel1 = null;
			do {

				nivel1 = new EjePe(rs.getLong("CODPLANE"), rs.getLong("ID_EJE"), rs.getString("HELBURUCAS"),
						rs.getString("HELBURU"));

				mapaLista.put(rs.getLong("ID_EJE"), nivel1);

			} while (rs.next());

			return mapaLista;
		}
	};

	private RowMapper<ElementosArbol> rwMapGestion = new RowMapper<ElementosArbol>() {
		@Override
		public ElementosArbol mapRow(ResultSet rs, int rowNum) throws SQLException {

			ElementosArbol elemArbol = new ElementosArbol();
			EjePe nivel0 = null;
			ElementosPg nivel1 = null;
			ElementosPg nivel2 = null;
			ElementosPg nivel3 = null;
			ElementosPg nivel4 = null;
			List<ElementosArbol> listanivel0 = new ArrayList<ElementosArbol>();
			List<ElementosArbol> listanivel1 = new ArrayList<ElementosArbol>();
			List<ElementosArbol> listanivel2 = new ArrayList<ElementosArbol>();
			List<ElementosArbol> listanivel3 = new ArrayList<ElementosArbol>();
			List<ElementosArbol> listanivel4 = new ArrayList<ElementosArbol>();
			Integer nivelAnterior = 0;
			Integer ejeAnterior = 0;
			do {

				if (rs.getInt("NIVEL") == Constantes.NIVEL_UNO) {

					nivel1 = new ElementosPg(rs.getLong("CODPLANG"), rs.getLong("CODELEMPG"), rs.getLong("ORDEN"),
							rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"),
							rs.getString("HELBURU"), rs.getString("HELBURUCAS"), rs.getLong("ID_EJE"),
							rs.getLong("ELEMBASE"), rs.getLong("PUEDEACCION"), rs.getLong("PUEDENUEVOELEM"),
							rs.getLong("TIENEVALOR"));

					if (ejeAnterior != rs.getLong("ID_EJE")) {
						nivel0 = new EjePe(rs.getLong("CODPLANG"), rs.getLong("ID_EJE"), rs.getLong("ORDEN_EJE"), 0l,
								rs.getString("NOMBRE_EJE"), rs.getString("NOMBRECAS_EJE"), rs.getString("HELBURU_EJE"),
								rs.getString("HELBURUCAS_EJE"), null, rs.getLong("PONDERACION_EJE"));
						listanivel0.add(nivel0);
						ejeAnterior = rs.getInt("ID_EJE");
						elemArbol.setHijosArbol(listanivel0);

						listanivel1 = new ArrayList<ElementosArbol>();
						listanivel1.add(nivel1);
					} else {
						listanivel1.add(nivel1);
					}

					nivel0.setHijosArbol(listanivel1);
					nivelAnterior = rs.getInt("NIVEL");

				} else if (rs.getInt("NIVEL") == Constantes.NIVEL_DOS) {

					nivel2 = new ElementosPg(rs.getLong("CODPLANG"), rs.getLong("CODELEMPG"), rs.getLong("ORDEN"),
							rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"),
							rs.getString("HELBURU"), rs.getString("HELBURUCAS"), rs.getLong("CODELEMPGPADRE"),
							rs.getLong("ELEMBASE"), rs.getLong("PUEDEACCION"), rs.getLong("PUEDENUEVOELEM"),
							rs.getLong("TIENEVALOR"));
					if (nivelAnterior == 1) {
						listanivel2 = new ArrayList<ElementosArbol>();
						listanivel2.add(nivel2);
					} else {
						listanivel2.add(nivel2);
					}
					nivel1.setHijosArbol(listanivel2);
					nivelAnterior = rs.getInt("NIVEL");

				} else if (rs.getInt("NIVEL") == Constantes.NIVEL_TRES) {

					nivel3 = new ElementosPg(rs.getLong("CODPLANG"), rs.getLong("CODELEMPG"), rs.getLong("ORDEN"),
							rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"),
							rs.getString("HELBURU"), rs.getString("HELBURUCAS"), rs.getLong("CODELEMPGPADRE"),
							rs.getLong("ELEMBASE"), rs.getLong("PUEDEACCION"), rs.getLong("PUEDENUEVOELEM"),
							rs.getLong("TIENEVALOR"));
					if (nivelAnterior == Constantes.NIVEL_DOS) {
						listanivel3 = new ArrayList<ElementosArbol>();
						listanivel3.add(nivel3);
					} else {
						listanivel3.add(nivel3);
					}
					nivel2.setHijosArbol(listanivel3);
					nivelAnterior = rs.getInt("NIVEL");

				} else if (rs.getInt("NIVEL") == Constantes.NIVEL_CUATRO) {

					nivel4 = new ElementosPg(rs.getLong("CODPLANG"), rs.getLong("CODELEMPG"), rs.getLong("ORDEN"),
							rs.getLong("NIVEL"), rs.getString("NOMBRE"), rs.getString("NOMBRECAS"),
							rs.getString("HELBURU"), rs.getString("HELBURUCAS"), rs.getLong("CODELEMPGPADRE"),
							rs.getLong("ELEMBASE"), rs.getLong("PUEDEACCION"), rs.getLong("PUEDENUEVOELEM"),
							rs.getLong("TIENEVALOR"));
					if (nivelAnterior == Constantes.NIVEL_TRES) {
						listanivel4 = new ArrayList<ElementosArbol>();
						listanivel4.add(nivel4);
					} else {
						listanivel4.add(nivel4);
					}
					nivel3.setHijosArbol(listanivel4);
					nivelAnterior = rs.getInt("NIVEL");
				}

			} while (rs.next());

			return elemArbol;
		}
	};

	/**
	 * Method use to set the datasource.
	 *
	 * @param dataSource
	 *            DataSource dataSource
	 */
	@Resource
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	/*
	 * OPERACIONES CRUD
	 */

	/**
	 * Busca los datos del arbol
	 * 
	 * @param idPE
	 *            Integer idPE
	 * @param jqGridRequestDto
	 *            JQGridRequestDto jqGridRequestDto
	 * @return List<ElementosPe> lista
	 */
	@Override
	@Transactional(readOnly = true)
	public List<ElementosArbol> findAll(Integer idPE, Integer version, JQGridRequestDto jqGridRequestDto) {

		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.findAll: Inicio findAll");

		StringBuilder query = new StringBuilder(this.getQueryArbolPE());
		query.append(" WHERE E_PE.CODPLANE = " + idPE + " AND E_PE.CODVERSIONPE = " + version);
		query.append(" CONNECT BY (PRIOR E_PE.CODELEMENTOPE=E_PE.CODELEMENTOPEPADRE) START WITH E_PE.NIVEL=1 ");

		// 20180626: se incluye el order para solucionar que en produccion no
		// salian los elementos en el orden correcto
		query.append(" ORDER SIBLINGS BY IDELEMENTO, NIVEL ");

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAll: sql:" + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAll: params:" + idPE);
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.findAll: Fin findAll");
		return this.jdbcTemplate.query(query.toString(), this.rwMap);
	}

	/**
	 * Devuelve la Select con todos los campos. Incluye el From si se indica.
	 * 
	 * @param includeFrom
	 *            boolean includeFrom
	 * @return String String
	 */
	private String getQueryArbolPE() {
		StringBuilder query = new StringBuilder(
				"SELECT	E_PE.CODELEMENTOPE, E_PE.IDELEMENTO,E_PE.ORDEN, E_PE.NIVEL, E_PE.NOMBRE,E_PE.NOMBRECAS,E_PE.HELBURU,E_PE.HELBURUCAS, E_PE.CODELEMENTOPEPADRE,E_PE.CODPLANE,");
		query.append(
				"	E_PE.HAS_EUS,E_PE.HAS_ELEBI,E_PE.AURRE_EUS,E_PE.AURRE_ELEBI,E_PE.AMAI_EUS,E_PE.AMAI_ELEBI,E_PE.ELEMBASE,E_PE.OHARRAK,E_PE.HAS_VALOR,  E_PE.AURRE_VALOR,  E_PE.AMAI_VALOR,");
		query.append(
				"E.PONDERACION,   E_PE.TIENEELEBI,  E_PE.TIENEVALOR,  E_PE.TIENEEUS,  E_PE.TIENESINO,E.ID_EJE,E_PE.HAS_SINO,  E_PE.AURRE_SINO,  E_PE.AMAI_SINO,");
		query.append(
				"	EJE.NOMBRE AS NOMBRE_EJE,EJE.NOMBRECAS AS NOMBRECAS_EJE,EJES_PE.HELBURU AS HELBURU_EJE,	EJES_PE.HELBURUCAS AS HELBURUCAS_EJE,EJE.ORDEN AS ORDEN_EJE,");
		query.append(
				" EJE.PONDERACION AS PONDERACION_EJE,SYS_CONNECT_BY_PATH (E_PE.CODELEMENTOPE,'/')	FROM ELEMENTOS_PE E_PE LEFT OUTER JOIN ELEMENTO E ON (E_PE.IDELEMENTO = E.ID_ELEMENTO)");
		query.append(
				" LEFT OUTER JOIN EJE EJE ON (E.ID_EJE = EJE.ID_EJE) LEFT OUTER JOIN EJES_PE EJES_PE ON EJES_PE.ID_EJE = ");
		query.append("EJE.ID_EJE AND E_PE.CODPLANE = EJES_PE.CODPLANE AND E_PE.CODVERSIONPE = EJES_PE.CODVERSIONPE");

		return query.toString();
	}

	/**
	 * Busca los datos del arbol
	 * 
	 * @param idPE
	 *            Integer idPE
	 * @param jqGridRequestDto
	 *            JQGridRequestDto jqGridRequestDto
	 * @return List<ElementosPe> lista
	 */
	@Override
	@Transactional(readOnly = true)
	public Map<Long, ElementosPe> findAllVersionAnterior(Integer idPE, Integer version,
			JQGridRequestDto jqGridRequestDto) {

		ElementosArbolDaoImpl.logger
				.info("ElementosArbolDaoImpl.findAllVersionAnterior: Inicio findAllVersionAnterior");
		Integer VersionAnterior = version - 1;
		StringBuilder query = new StringBuilder(this.getQueryArbolPE());
		query.append(" WHERE 1 = 1 AND E_PE.CODPLANE = " + idPE + " AND E_PE.CODVERSIONPE = " + VersionAnterior);
		query.append(" CONNECT BY (PRIOR E_PE.CODELEMENTOPE=E_PE.CODELEMENTOPEPADRE) START WITH E_PE.NIVEL=1");

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAllVersionAnterior: sql:" + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAllVersionAnterior: params:" + idPE);
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.findAllVersionAnterior: Fin findAllVersionAnterior");
		List<Map<Long, ElementosPe>> lista = this.jdbcTemplate.query(query.toString(), this.rwMapVersiones);
		return lista.get(0);
	}

	/**
	 * Busca los datos del arbol
	 * 
	 * @param idPE
	 *            Integer idPE
	 * @param jqGridRequestDto
	 *            JQGridRequestDto jqGridRequestDto
	 * @return List<ElementosPe> lista
	 */
	@Override
	@Transactional(readOnly = true)
	public Map<Long, EjePe> findAllEjesVersionAnterior(Integer idPE, Integer version,
			JQGridRequestDto jqGridRequestDto) {

		ElementosArbolDaoImpl.logger
				.info("ElementosArbolDaoImpl.findAllEjesVersionAnterior: Inicio findAllEjesVersionAnterior");
		Integer VersionAnterior = version - 1;

		StringBuilder query = new StringBuilder("SELECT CODPLANE,ID_EJE,HELBURU,HELBURUCAS FROM EJES_PE ");
		query.append(" WHERE 1 = 1 AND EJES_PE.CODPLANE = " + idPE + " AND EJES_PE.CODVERSIONPE = " + VersionAnterior);

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAllEjesVersionAnterior: sql:" + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAllEjesVersionAnterior: params:" + idPE);
		ElementosArbolDaoImpl.logger
				.info("ElementosArbolDaoImpl.findAllEjesVersionAnterior: Fin findAllEjesVersionAnterior");
		List<Map<Long, EjePe>> lista = this.jdbcTemplate.query(query.toString(), this.rwMapVersionesEje);
		return lista.get(0);
	}

	/**
	 * Busca los datos del arbol
	 * 
	 * @param idPE
	 *            Integer idPE
	 * @param jqGridRequestDto
	 *            JQGridRequestDto jqGridRequestDto
	 * @param acciones
	 *            Map<String, List<AccionesPg>> acciones
	 * @return List<ElementosPe> lista
	 */
	@Override
	@Transactional(readOnly = true)
	public List<ElementosArbol> findAllGestion(Integer idPE, JQGridRequestDto jqGridRequestDto) {

		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.findAllGestion: Inicio findAllGestion");

		StringBuilder query = new StringBuilder(
				" SELECT E_PG.CODELEMPG, E_PG.ORDEN, E_PG.NIVEL, E_PG.NOMBRE,E_PG.NOMBRECAS,E_PE.HELBURU,E_PE.HELBURUCAS, E_PG.CODELEMPGPADRE,E_PG.CODPLANG,E_PG.ELEMBASE,");
		query.append("  E.TIENEELEBI,E.TIENEVALOR,DECODE(E_PG.ELEMBASE,0,E.PUEDEACCION,0) AS PUEDEACCION,");
		query.append(
				"  DECODE(E_PG.ELEMBASE,0,E.PUEDENUEVOELEM,1,0) AS PUEDENUEVOELEM,E.ID_EJE,EJE.NOMBRE AS NOMBRE_EJE,");
		query.append("EJE.NOMBRECAS AS NOMBRECAS_EJE,E.PONDERACION PONDERACION_EJE,");
		query.append("EJES_PE.HELBURU AS HELBURU_EJE,EJES_PE.HELBURUCAS AS HELBURUCAS_EJE,EJE.ORDEN AS ORDEN_EJE");
		query.append(
				" ,SYS_CONNECT_BY_PATH (E_PG.CODELEMPG,'/') FROM ELEMENTOS_PG E_PG LEFT OUTER JOIN ELEMENTOS_PE E_PE ON (E_PG.CODELEMENTOPE = E_PE.CODELEMENTOPE)");
		query.append(
				" LEFT JOIN ELEMENTO E ON E_PE.IDELEMENTO = E.ID_ELEMENTO LEFT JOIN EJE EJE ON (E.ID_EJE = EJE.ID_EJE) LEFT JOIN EJES_PE EJES_PE ON EJES_PE.ID_EJE = EJE.ID_EJE");
		query.append(
				" AND E_PE.CODPLANE = EJES_PE.CODPLANE AND E_PE.CODVERSIONPE = EJES_PE.CODVERSIONPE LEFT JOIN AB3909T00 ON E_PG.CODPLANG  = AB3909T00.CODPLANG AND AB3909T00.CODPLANE = E_PE.CODPLANE");
		query.append(
				" LEFT JOIN (SELECT AB3905T00.ID_ELEMENTO, eje.ID_TIPOORGANIZACION   FROM eje   INNER JOIN AB3905T00   ON AB3905T00.ID_EJE  = eje.ID_EJE");
		query.append("   ) tipoOrganiz ON E_PE.CODELEMENTOPEPADRE = tipoOrganiz.ID_ELEMENTO");
		query.append(" WHERE 1 = 1 AND E_PG.CODPLANG  = " + idPE);
		query.append(" CONNECT BY (PRIOR E_PG.CODELEMPG=E_PG.CODELEMPGPADRE) START WITH E_PG.NIVEL=1 ");
		// Si el elemento de nivel 3 no es elemento base para ver si puede crear
		// nuevo elemento o añadir acciones no se mira en la tabla de elementos
		// el campo puedeaccion o puedenuevoelem sino que se
		// mira el tipo de organizacion de su eje. Y si es base se miran esos
		// dos campos de la tabla elementos
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAllGestion: sql:" + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.findAllGestion: params:" + idPE);
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.findAllGestion: Fin findAllGestion");
		return this.jdbcTemplate.query(query.toString(), this.rwMapGestion);
	}

	/**
	 * Guarda el helburu del elemento
	 * 
	 * @param elem
	 *            ElementosArbol elem
	 * 
	 */
	public void guardarHelburu(ElementosArbol elem) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.guardarHelburu: Inicio guardarHelburu");
		StringBuilder query = new StringBuilder("");
		if (elem.getNivelA() == 0) {
			query = new StringBuilder("UPDATE EJES_PE SET HELBURU=?,HELBURUCAS=? WHERE ID_EJE=? AND CODPLANE =?");
		} else {
			query = new StringBuilder(
					"UPDATE ELEMENTOS_PE SET HELBURU=?,HELBURUCAS=? WHERE CODELEMENTOPE=? AND CODPLANE =?");
		}

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.guardarHelburu: sql: " + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.guardarHelburu: params: " + elem.toString());
		this.jdbcTemplate.update(query.toString(), elem.getHelburuA(), elem.getHelburucasA(), elem.getIdElementoA(),
				elem.getCodPlaneA());
	}

	/**
	 * Guarda el titulo del elemento
	 * 
	 * @param elem
	 *            ElementosArbol elem
	 * 
	 */
	public void guardarTituloPG(ElementosArbol elem) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.guardarTituloPG: Inicio guardarTituloPG");
		StringBuilder query = new StringBuilder("");

		query = new StringBuilder("UPDATE ELEMENTOS_PG SET NOMBRE=?,NOMBRECAS=? WHERE CODELEMPG=?");

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.guardarTituloPG: sql: " + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.guardarTituloPG: params: " + elem.toString());
		this.jdbcTemplate.update(query.toString(), elem.getNombreA(), elem.getNombrecasA(), elem.getIdElementoA());
	}

	/**
	 * Guarda los datos de todo el arbol
	 * 
	 * @param elementos
	 *            List<ElementosPe> elementos
	 */

	public void guardarDatosArbol(final List<ElementosPe> elementos) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.guardarDatosArbol: Inicio guardarDatosArbol");
		StringBuilder query = new StringBuilder("");

		query.append(
				"UPDATE ELEMENTOS_PE SET HAS_EUS = ?,HAS_ELEBI =?,AURRE_EUS=?,AURRE_ELEBI=?,AMAI_EUS=?,AMAI_ELEBI =?, HAS_VALOR=?,AURRE_VALOR=?,AMAI_VALOR=? ");
		query.append(
				" ,HAS_SINO =?,AURRE_SINO=?, AMAI_SINO=? WHERE CODPLANE=? AND CODELEMENTOPE=? AND CODELEMENTOPEPADRE=?");
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.guardarDatosArbol: sql: " + query.toString());

		this.jdbcTemplate.batchUpdate(query.toString(), new BatchPreparedStatementSetter() {

			@Override
			public void setValues(PreparedStatement ps, int i) throws SQLException {
				ps.setBigDecimal(Constantes.NUM_UNO,
						elementos.get(i).getHasEus() == null ? BigDecimal.ZERO : elementos.get(i).getHasEus());
				ps.setBigDecimal(Constantes.NUM_DOS,
						elementos.get(i).getHasElebi() == null ? BigDecimal.ZERO : elementos.get(i).getHasElebi());
				ps.setBigDecimal(Constantes.NUM_TRES,
						elementos.get(i).getAurreEus() == null ? BigDecimal.ZERO : elementos.get(i).getAurreEus());
				ps.setBigDecimal(Constantes.NUM_CUATRO,
						elementos.get(i).getAurreElebi() == null ? BigDecimal.ZERO : elementos.get(i).getAurreElebi());
				ps.setBigDecimal(Constantes.NUM_CINCO,
						elementos.get(i).getAmaiEus() == null ? BigDecimal.ZERO : elementos.get(i).getAmaiEus());
				ps.setBigDecimal(Constantes.NUM_SEIS,
						elementos.get(i).getAmaiElebi() == null ? BigDecimal.ZERO : elementos.get(i).getAmaiElebi());
				ps.setBigDecimal(Constantes.NUM_SIETE,
						elementos.get(i).getHasValor() == null ? BigDecimal.ZERO : elementos.get(i).getHasValor());
				ps.setBigDecimal(Constantes.NUM_OCHO,
						elementos.get(i).getAurreValor() == null ? BigDecimal.ZERO : elementos.get(i).getAurreValor());
				ps.setBigDecimal(Constantes.NUM_NUEVE,
						elementos.get(i).getAmaiValor() == null ? BigDecimal.ZERO : elementos.get(i).getAmaiValor());
				ps.setLong(Constantes.NUM_DIEZ,
						elementos.get(i).getHasSiNo() == null ? 0 : elementos.get(i).getHasSiNo());
				ps.setLong(Constantes.NUM_ONCE,
						elementos.get(i).getAurreSiNo() == null ? 0 : elementos.get(i).getAurreSiNo());
				ps.setLong(Constantes.NUM_DOCE,
						elementos.get(i).getAmaiSiNo() == null ? 0 : elementos.get(i).getAmaiSiNo());
				ps.setLong(Constantes.NUM_TRECE,
						elementos.get(i).getCodplane() == null ? 0 : elementos.get(i).getCodplane());
				ps.setLong(Constantes.NUM_CATORCE,
						elementos.get(i).getIdelemento() == null ? 0 : elementos.get(i).getIdelemento());
				ps.setInt(Constantes.NUM_QUINCE,
						elementos.get(i).getCodElementoPadre() == null ? 0 : elementos.get(i).getCodElementoPadre());
			}

			public int getBatchSize() {
				return elementos.size();
			}
		});

	}

	/**
	 * Borra un elemento
	 * 
	 * @param idElemento
	 *            Long idElemento
	 */

	public void borrarElemento(Long idElemento) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.borrarElemento: Inicio borrarElemento");

		StringBuilder query = new StringBuilder(Constantes.STRING_BUILDER_INIT);
		query.append("{call TRASLADA_ACCIONPE_PLAN_GESTION (?,?)}");
		ElementosArbolDaoImpl.logger.info(query.toString());
		final String procedureCall = query.toString();
		final Long idElem = idElemento;

		SqlParameter parametro = new SqlParameter(Types.NUMERIC);

		List<SqlParameter> paramArray = new ArrayList<SqlParameter>();
		paramArray.add(parametro);

		this.jdbcTemplate.call(new CallableStatementCreator() {
			@Override
			public CallableStatement createCallableStatement(Connection connection) throws SQLException {

				CallableStatement callableStatement = connection.prepareCall(procedureCall);
				callableStatement.setLong(1, 0);
				callableStatement.setLong(Constantes.NUM_DOS, idElem);
				return callableStatement;

			}
		}, paramArray);
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.borrarElemento: Fin borrarElemento");

	}

	/**
	 * Nuevo elemento
	 *
	 * @param elem
	 *            ElementosArbol elem
	 * @return ElementosArbol elem
	 * 
	 */
	public ElementosArbol elementoNuevo(ElementosPe elem) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.elementoNuevo: Inicio elementoNuevo");
		StringBuilder query = new StringBuilder("");
		List<Object> params = new ArrayList<Object>();
		query = new StringBuilder(
				"SELECT DECODE(MAX(ORDEN)+1,null,1,MAX(ORDEN)+1) AS ORDEN FROM ELEMENTOS_PE WHERE CODELEMENTOPEPADRE = ? AND CODPLANE = ?");
		params.add(elem.getElementoPadreA());
		params.add(elem.getCodPlaneA());
		long orden = this.jdbcTemplate.queryForObject(query.toString(), params.toArray(), Long.class);

		query = new StringBuilder(
				"INSERT INTO ELEMENTOS_PE(CODELEMENTOPE,CODPLANE,ORDEN,NIVEL,NOMBRE,NOMBRECAS,HELBURU,HELBURUCAS,CODELEMENTOPEPADRE,ELEMBASE,CODVERSIONPE,IDELEMENTO,");
		query.append(
				"HAS_EUS,HAS_ELEBI,AURRE_EUS,AURRE_ELEBI,AMAI_EUS,AMAI_ELEBI,HAS_VALOR,AURRE_VALOR,AMAI_VALOR,TIENEEUS,TIENEELEBI,TIENESINO,TIENEVALOR)");
		query.append(" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,0,0,0,0,0,0,0,0,0,?,?,?,?)");

		Integer codElemento = SecuenciasSQL.ELEMENTOS.getNextInteger(jdbcTemplate);
		Integer idElementoNuevo = SecuenciasSQL.IDELEMENTONUEVO.getNextInteger(jdbcTemplate);

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: sql: " + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: params: " + elem.toString());

		this.jdbcTemplate.update(query.toString(), codElemento, elem.getCodPlaneA(), orden, elem.getNivelA(),
				elem.getNombreA(), elem.getNombrecasA(), elem.getHelburuA(), elem.getHelburucasA(),
				elem.getElementoPadreA(), Constantes.ELEMENTO_VALOR_1, elem.getVersion(), idElementoNuevo,
				elem.getTieneEus(), elem.getTieneElebi(), elem.getTieneSiNo(), elem.getTieneValor());

		// llamada al pl
		query = new StringBuilder(Constantes.STRING_BUILDER_INIT);
		query.append("{call TRASLADA_ACCIONPE_PLAN_GESTION (?,?)}");
		ElementosArbolDaoImpl.logger.info(query.toString());
		final String procedureCall = query.toString();
		final int idElem = codElemento;

		SqlParameter parametro = new SqlParameter(Types.NUMERIC);

		List<SqlParameter> paramArray = new ArrayList<SqlParameter>();
		paramArray.add(parametro);

		this.jdbcTemplate.call(new CallableStatementCreator() {
			@Override
			public CallableStatement createCallableStatement(Connection connection) throws SQLException {

				CallableStatement callableStatement = connection.prepareCall(procedureCall);
				callableStatement.setLong(1, 1);
				callableStatement.setLong(Constantes.NUM_DOS, idElem);
				return callableStatement;

			}
		}, paramArray);

		ElementosPe elemento = new ElementosPe(elem.getCodPlaneA(), (long) codElemento, orden,
				Constantes.ELEMENTO_NIVEL_3, elem.getNombreA(), elem.getNombrecasA(), elem.getHelburuA(),
				elem.getHelburucasA(), elem.getElementoPadreA(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO,
				BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, Constantes.ELEMENTO_VALOR_1, Constantes.VACIO,
				Constantes.ELEMENTO_VALOR_0, elem.getTieneElebi(), elem.getTieneValor(), BigDecimal.ZERO,
				BigDecimal.ZERO, BigDecimal.ZERO, (long) idElementoNuevo, elem.getTieneEus(), elem.getTieneSiNo(),
				Constantes.ELEMENTO_VALOR_0, Constantes.ELEMENTO_VALOR_0, Constantes.ELEMENTO_VALOR_0);
		List<ElementosArbol> listanivel3 = new ArrayList<ElementosArbol>();
		listanivel3.add(elemento);
		ElementosPe elem1 = new ElementosPe();

		elem1.setHijosArbol(listanivel3);

		return elem1;

	}

	/**
	 * Nuevo elemento de nivel 4
	 *
	 * @param elem
	 *            ElementosArbol elem
	 * @param accion
	 *            AccionesPg accion
	 * @return ElementosArbol ElementosArbol
	 * 
	 */
	public ElementosArbol elementoNuevoNivel4(ElementosArbol elem, AccionesPg accion) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.elementoNuevoNivel4: Inicio elementoNuevoNivel4");
		StringBuilder query = new StringBuilder("");
		List<Object> params = new ArrayList<Object>();

		// Elemento nivel 4
		query = new StringBuilder(
				"SELECT DECODE(MAX(ORDEN)+1,NULL,1,MAX(ORDEN)+1) AS ORDEN FROM ELEMENTOS_PG WHERE CODELEMPG =?");
		params.add(elem.getElementoPadreA());
		long orden = this.jdbcTemplate.queryForObject(query.toString(), params.toArray(), Long.class);

		query = new StringBuilder(
				"INSERT INTO ELEMENTOS_PG(CODELEMPG,CODPLANG,ORDEN,NIVEL,NOMBRE,NOMBRECAS,CODELEMPGPADRE,ELEMBASE,IDELEMENTO)VALUES(?,?,?,?,?,?,?,?,0)");
		Integer codElemento = SecuenciasSQL.ELEMENTOSPG.getNextInteger(jdbcTemplate);

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: sql: " + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: params: " + elem.toString());

		this.jdbcTemplate.update(query.toString(), codElemento, elem.getCodPlaneA(), orden, Constantes.NIVEL_CUATRO,
				elem.getNombreA(), elem.getNombrecasA(), elem.getElementoPadreA(), Constantes.ELEMENTO_VALOR_1);
		params.clear();

		// accion
		query = new StringBuilder(
				"SELECT DECODE(MAX(ORDEN)+1,null,1,MAX(ORDEN)+1) AS ORDEN FROM Acciones_pg WHERE codelempg =?");
		params.add(elem.getElementoPadreA());
		long ordenAccion = this.jdbcTemplate.queryForObject(query.toString(), params.toArray(), Long.class);

		query = new StringBuilder(
				"INSERT INTO ACCIONES_PG(CODACCIONPG,CODELEMPG,ORDEN,NOMBRE,NOMBRECAS,ELEMBASE)VALUES(?,?,?,?,?,?)");
		Integer codAccion = SecuenciasSQL.ACCIONESPG.getNextInteger(jdbcTemplate);

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: sql accion: " + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: params accion: " + elem.toString());

		this.jdbcTemplate.update(query.toString(), codAccion, codElemento, ordenAccion, accion.getNombre(),
				accion.getNombrecas(), Constantes.ELEMENTO_VALOR_1);

		ElementosPg elemento = new ElementosPg(elem.getCodPlaneA(), (long) codElemento, orden,
				Constantes.ELEMENTO_NIVEL_4, elem.getNombreA(), elem.getNombrecasA(), Constantes.VACIO,
				Constantes.VACIO, elem.getElementoPadreA(), Constantes.ELEMENTO_VALOR_1, Constantes.ELEMENTO_VALOR_0,
				Constantes.ELEMENTO_VALOR_0, Constantes.ELEMENTO_VALOR_0);

		AccionesPg accionNueva = new AccionesPg(codAccion, codElemento, Constantes.NUM_CERO,
				Constantes.ELEMENTO_VALOR_0, Constantes.ELEMENTO_VALOR_0, Constantes.NUM_CERO, ordenAccion,
				accion.getNombre(), accion.getNombrecas(), null, Constantes.NUM_CERO, Constantes.VACIO, null, null,
				Constantes.VACIO, Constantes.VACIO, Constantes.VACIO, Constantes.VACIO, Constantes.VACIO,
				Constantes.VACIO, Constantes.VACIO, Constantes.VACIO, Constantes.ELEMENTO_VALOR_1,
				Constantes.ELEMENTO_VALOR_0);
		List<AccionesPg> listaAccion = new ArrayList<AccionesPg>();
		listaAccion.add(accionNueva);
		elemento.setAcciones(listaAccion);
		List<ElementosArbol> listanivel4 = new ArrayList<ElementosArbol>();
		listanivel4.add(elemento);
		ElementosPg elem1 = new ElementosPg();
		elem1.setHijosArbol(listanivel4);

		return elem1;

	}

	/**
	 * Modifica el helburu del elemento
	 *
	 * @param elem
	 *            ElementosArbol elem
	 * 
	 */
	public void modificarElemento(ElementosArbol elem) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.modificarElemento: Inicio modificarElemento");
		StringBuilder query = new StringBuilder("");
		query = new StringBuilder(
				"UPDATE ELEMENTOS_PE SET NOMBRE=?,NOMBRECAS=?,HELBURU=?,HELBURUCAS =? WHERE CODELEMENTOPE = ?");

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: sql: " + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: params: " + elem.toString());

		this.jdbcTemplate.update(query.toString(), elem.getNombreA(), elem.getNombrecasA(), elem.getHelburuA(),
				elem.getHelburucasA(), elem.getIdElementoA());

		// llamada al pl
		query = new StringBuilder(Constantes.STRING_BUILDER_INIT);
		query.append("{call TRASLADA_ACCIONPE_PLAN_GESTION (?,?)}");
		ElementosArbolDaoImpl.logger.info(query.toString());
		final String procedureCall = query.toString();
		final long idElem = elem.getIdElementoA();

		SqlParameter parametro = new SqlParameter(Types.NUMERIC);

		List<SqlParameter> paramArray = new ArrayList<SqlParameter>();
		paramArray.add(parametro);

		this.jdbcTemplate.call(new CallableStatementCreator() {
			@Override
			public CallableStatement createCallableStatement(Connection connection) throws SQLException {

				CallableStatement callableStatement = connection.prepareCall(procedureCall);
				callableStatement.setLong(1, Constantes.NUM_DOS);
				callableStatement.setLong(Constantes.NUM_DOS, idElem);
				return callableStatement;

			}
		}, paramArray);

	}

	/**
	 * Editar oharrak
	 *
	 * @param elem
	 *            ElementosPe elem
	 * 
	 */
	public void editarOharrak(ElementosPe elem) {
		ElementosArbolDaoImpl.logger.info("ElementosArbolDaoImpl.editarOharrak: Inicio editarOharrak");
		StringBuilder query = new StringBuilder("");
		query = new StringBuilder("UPDATE ELEMENTOS_PE SET OHARRAK=? WHERE CODELEMENTOPE = ?");

		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: sql: " + query.toString());
		ElementosArbolDaoImpl.logger.debug("ElementosArbolDaoImpl.elementoNuevo: params: " + elem.toString());

		this.jdbcTemplate.update(query.toString(), elem.getOharrak(), elem.getIdElementoA());

	}

}
