package maps.dao.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import maps.common.DBConnection;
import maps.dao.ProducerDao;
import maps.model.Producer;

import org.springframework.stereotype.Component;

@Component
public class JDBCProducerDao implements ProducerDao {

	@Override
	public int create(Integer project, Integer context) {
		
		Connection conexion = null;
		PreparedStatement stmt;
		
		try {
					
			// Establecer una conexión con la base de datos: 
			
			conexion = DBConnection.open();
		
			// Crear una instrucción SQL parametrizada:
						
			if (context != null) {
			
				stmt = conexion.prepareStatement("INSERT INTO producers (id_project, id_context, spot) VALUES (?, ?, (SELECT COUNT(*) + 1 FROM producers AS a WHERE id_project = ? AND id_context = ?))", PreparedStatement.RETURN_GENERATED_KEYS);
				
				stmt.setInt(1, project);
				stmt.setInt(2, context);
				stmt.setInt(3, project);
				stmt.setInt(4, context);
				
			} else {
				
				stmt = conexion.prepareStatement("INSERT INTO producers (id_project, id_context, spot) VALUES (?, NULL, (SELECT COUNT(*) + 1 FROM producers AS a WHERE id_project = ? AND id_context IS NULL))", PreparedStatement.RETURN_GENERATED_KEYS);
				
				stmt.setInt(1, project);
				stmt.setInt(2, project);
				
			}
			
			// Ejecutar la instrucción:
			
			stmt.executeUpdate();		
		
			// Regresar el ID generado:
		
			ResultSet rs = stmt.getGeneratedKeys();
			
			if (rs.next()) { 

				return rs.getInt(1);

			} else {
				
				return -1;

			}
		
		} catch (Exception e) {
			
			e.printStackTrace();
			
			return -1;
			
		} finally {
			
			// Cerra la conexión con la base de datos:
			
			DBConnection.close(conexion);
			
		}
		
	}

	@Override
	public void update(Producer producer) {
		
		Connection conexion = null;
		
		try {
		
			// Establecer una conexión con la base de datos: 
			
			conexion = DBConnection.open();
		
			// Crear una instrucción SQL parametrizada: 
			
			PreparedStatement stmt = conexion.prepareStatement("UPDATE producers SET "
					+ "id_project = ?, "
					+ "id_context = ?, "
					+ "kind = ?, "
					+ "display_text = ?, "
					+ "description = ?, "
					+ "spot = ? "
					+ "WHERE id = ?");
						
			// Asignar valores a los parámetros:
			
			stmt.setInt(1, producer.getProject());
			if (producer.getContext() != null) stmt.setInt(2, producer.getContext()); else stmt.setNull(2, java.sql.Types.INTEGER);
			if (producer.getKind() != null) stmt.setInt(3, producer.getKind()); else stmt.setNull(3, java.sql.Types.TINYINT);
			stmt.setString(4, producer.getDisplayText());
			stmt.setString(5, producer.getDescription());
			if (producer.getSpot() != null) stmt.setInt(6, producer.getSpot()); else stmt.setNull(6, java.sql.Types.INTEGER);
			stmt.setInt(7, producer.getId());
						
			// Ejecutar la instrucción:
			
			stmt.executeUpdate();	
		
		} catch (Exception e) {
			
			e.printStackTrace();
			
		} finally {
			
			// Cerra la conexión con la base de datos:
			
			DBConnection.close(conexion);
			
		}
		
	}
	
	@Override
	public void delete(Integer id) {
		
		Connection conexion = null;
		
		try {
		
			// Establecer una conexión con la base de datos: 
			
			conexion = DBConnection.open();
		
			// Crear una instrucción SQL parametrizada: 
			
			PreparedStatement stmt = conexion.prepareStatement("DELETE FROM producers WHERE id = ?");
			
			// Asignar valores a los parámetros:

			stmt.setInt(1, id);
			
			// Ejecutar la instrucción:
			
			stmt.executeUpdate();	
		
		} catch (Exception e) {
			
			e.printStackTrace();
			
		} finally {
			
			// Cerra la conexión con la base de datos:
			
			DBConnection.close(conexion);
			
		}
		
	}

	@Override
	public Producer select(Integer id) {
		
		Connection conexion = null;
		
		try {
		
			// Establecer una conexión con la base de datos: 
			
			conexion = DBConnection.open();

			// Crear una instrucción SQL parametrizada: 
			
			PreparedStatement stmt = conexion.prepareStatement("SELECT * FROM producers WHERE id = ?");
			
			// Asignar valores a los parámetros:
			
			stmt.setInt(1, id);
			
			// Ejecutar la instrucción:

			ResultSet rs = stmt.executeQuery();
			
			// Crear el objeto que se va a regresar:
			
			Producer trabajador = new Producer();
						
			if(rs.next()) {
				
				trabajador.setProject(rs.getInt("id_project"));
				trabajador.setId(rs.getInt("id"));
				trabajador.setContext((Integer) rs.getObject("id_context")); // NOTA: Se utiliza getObject() porque debe asignarse NULL al campo cuando se trata de un elemento raíz.
				trabajador.setKind(rs.getByte("kind"));
				trabajador.setDisplayText(rs.getString("display_text"));
				trabajador.setDescription(rs.getString("description"));
				trabajador.setSpot(rs.getInt("spot"));
				
				// Obtener la lista de subtrabajadores:
				
				trabajador.setProducers(list(rs.getInt("id_project"), rs.getInt("id")));
				
			}
			
			// Regresar el objeto:
			
			return trabajador;
			
		} catch (Exception e) {
		
			e.printStackTrace();
			
			return null;
			
		} finally {
			
			// Cerra la conexión con la base de datos:
			
			DBConnection.close(conexion);
			
		}
		
	}

	@Override
	public List<Producer> list(Integer project, Integer context) {
		
		Connection conexion = null;
		PreparedStatement stmt;
		
		try {
		
			// Establecer una conexión con la base de datos: 
			
			conexion = DBConnection.open();
		
			// Crear una instrucción SQL parametrizada:
			
			if (context != null) {
				
				stmt = conexion.prepareStatement("SELECT id FROM producers WHERE id_project = ? AND id_context = ? ORDER BY spot");
				
				stmt.setInt(1, project);
				stmt.setInt(2, context);
				
			} else {
				
				stmt = conexion.prepareStatement("SELECT id FROM producers WHERE id_project = ? AND id_context IS NULL ORDER BY spot");
				
				stmt.setInt(1, project);
				
			}
			
			// Ejecutar la instrucción:

			ResultSet rs = stmt.executeQuery();
			
			// Crear la lista de objetos que se va a regresar:
			
			List<Producer> producers = new ArrayList<Producer>();
						
			while(rs.next()) {
				
				Producer producer = select(rs.getInt("id"));
				
				producers.add(producer);
				
			}
			
			// Regresar la lista de objetos:
			
			return producers;
			
		} catch (Exception e) {
		
			e.printStackTrace();
			
			return null;
			
		} finally {
			
			// Cerra la conexión con la base de datos:
			
			DBConnection.close(conexion);
			
		}
		
	}

}
