package com.ejie.aa20b.service;

import com.ejie.aa20b.classes.Aa20bFecha;
import com.ejie.aa20b.dao.ActuacionDao;
import com.ejie.aa20b.dao.CuestionarioDao;
import com.ejie.aa20b.dao.FichaDao;
import com.ejie.aa20b.dao.FichatecnicoDao;
import com.ejie.aa20b.dao.MaquinasDao;
import com.ejie.aa20b.dao.TecnicoplanifDao;
import com.ejie.x38.dto.Pagination;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.aa20b.model.ActAnual;
import com.ejie.aa20b.model.Actuacion;
import com.ejie.aa20b.model.Cuestionario;
import com.ejie.aa20b.model.Ficha;
import com.ejie.aa20b.model.Fichatecnico;
import com.ejie.aa20b.model.Maquinas;
import com.ejie.aa20b.model.PlanGeneral;
import com.ejie.aa20b.model.PrevAnual;
import com.ejie.aa20b.model.Tecnicoplanif;

/**
 * MaquinasServiceImpl generated by UDA, 04-mar-2015 15:44:07.
 * 
 * @author UDA
 */

@Service(value = "maquinasService")
public class MaquinasServiceImpl implements MaquinasService {

	@Autowired
	private MaquinasDao maquinasDao;

	@Autowired
	private FichaDao fichaDao;

	@Autowired
	private FichatecnicoDao fichatecnicoDao;

	@Autowired
	private CuestionarioDao cuestionarioDao;

	@Autowired
	private ActuacionDao actuacionDao;

	@Autowired
	private TecnicoplanifDao tecnicoplanifDao;

	/**
	 * Inserts a single row in the Maquinas table.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @return Maquinas
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Maquinas add(Maquinas maquinas) {
		return this.maquinasDao.add(maquinas);
	}

	/**
	 * Updates a single row in the Maquinas table.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @return Maquinas
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Maquinas update(Maquinas maquinas) {
		return this.maquinasDao.update(maquinas);
	}

	/**
	 * Finds a single row in the Maquinas table.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @return Maquinas
	 */
	public Maquinas find(Maquinas maquinas) {
		return (Maquinas) this.maquinasDao.find(maquinas);
	}

	/**
	 * Finds a List of rows in the Maquinas table.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @param pagination
	 *            Pagination
	 * @return List
	 */
	public List<Maquinas> findAll(Maquinas maquinas, Pagination pagination) {
		return (List<Maquinas>) this.maquinasDao.findAll(maquinas, pagination);
	}

	/**
	 * Counts rows in the Maquinas table.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @return Long
	 */
	public Long findAllCount(Maquinas maquinas) {
		return this.maquinasDao.findAllCount(maquinas);
	}

	/**
	 * Finds rows in the Maquinas table using like.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @param pagination
	 *            Pagination
	 * @param startsWith
	 *            Boolean
	 * @return List
	 */
	public List<Maquinas> findAllLike(Maquinas maquinas, Pagination pagination,
			Boolean startsWith) {
		return (List<Maquinas>) this.maquinasDao.findAllLike(maquinas,
				pagination, startsWith);
	}

	/**
	 * Counts rows in the Maquinas table using like.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @param startsWith
	 *            Boolean
	 * @return Long
	 */
	public Long findAllLikeCount(Maquinas maquinas, Boolean startsWith) {
		return this.maquinasDao.findAllLikeCount(maquinas, startsWith);
	}

	/**
	 * Deletes a single row in the Maquinas table.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @return
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void remove(Maquinas maquinas) {
		this.maquinasDao.remove(maquinas);
	}

	/**
	 * Deletes multiple rows in the Maquinas table.
	 * 
	 * @param maquinasList
	 *            List
	 * @return
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void removeMultiple(List<Maquinas> maquinasList) {
		for (Maquinas maquinasAux : maquinasList) {
			this.maquinasDao.remove(maquinasAux);
		}
	}

	/**
	 * Obtiene las máquinas de edificios relacionados con el usuario de XLNET.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @param pagination
	 *            Pagination
	 * @param startsWith
	 *            Boolean
	 * @return List
	 */
	public List<Maquinas> obtenerMaquinasUsuario(Maquinas maquinas,
			Pagination pagination, Boolean startsWith, String sUIDUsuario) {
		return (List<Maquinas>) this.maquinasDao.obtenerMaquinasUsuario(
				maquinas, pagination, startsWith, sUIDUsuario);
	}

	/**
	 * Obtiene las máquinas de edificios relacionados con el usuario de XLNET.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @param startsWith
	 *            Boolean
	 * @return Long
	 */
	public Long obtenerMaquinasUsuarioCount(Maquinas maquinas,
			Boolean startsWith, String sUIDUsuario) {
		return this.maquinasDao.obtenerMaquinasUsuarioCount(maquinas,
				startsWith, sUIDUsuario);
	}

	/**
	 * Finds a single row in the Maquinas table.
	 * 
	 * @param idMaquina
	 *            String
	 * @return Maquinas
	 */
	public Maquinas obtenerMaquina(String idMaquina) {
		return (Maquinas) this.maquinasDao.obtenerMaquina(idMaquina);
	}

	@SuppressWarnings("rawtypes")
	public ArrayList obtenerPlanificiacionGeneral(PlanGeneral filtroPlanGeneral) {
		return this.maquinasDao.obtenerPlanificiacionGeneral(filtroPlanGeneral);
	}

	@SuppressWarnings("rawtypes")
	public ArrayList obtenerPlanificiacionGeneral(
			PlanGeneral filtroPlanGeneral, Pagination pagination) {
		return this.maquinasDao.obtenerPlanificiacionGeneral(filtroPlanGeneral,
				pagination);
	}

	public Long obtenerPlanificiacionGeneralCount(PlanGeneral filtroPlanGeneral) {
		return this.maquinasDao
				.obtenerPlanificiacionGeneralCount(filtroPlanGeneral);
	}

	/**
	 * obtener los ID máquinas que cumplen con el filtro
	 * 
	 * @param filtroPlanGeneral
	 *            PlanGeneral
	 * @param Pagination
	 *            pagination
	 * @return ArrayList
	 */
	public ArrayList obtenerIdMaquinasPG(PlanGeneral filtroPlanGeneral,
			Pagination pagination) {
		return this.maquinasDao.obtenerIdMaquinasPG(filtroPlanGeneral,
				pagination);
	}

	/**
	 * obtener los ID máquinas que cumplen con el filtro
	 * 
	 * @param filtroPrevAnual
	 *            PrevAnual
	 * @param Pagination
	 *            pagination
	 * @return ArrayList
	 */
	public ArrayList obtenerIdMaquinasPA(PrevAnual filtroPrevAnual,
			Pagination pagination) {
		return this.maquinasDao
				.obtenerIdMaquinasPA(filtroPrevAnual, pagination);
	}

	/**
	 * obtener los ID máquinas que cumplen con el filtro
	 * 
	 * @param filtroActAnual
	 *            ActAnual
	 * @param Pagination
	 *            pagination
	 * @return ArrayList
	 */
	public ArrayList obtenerIdMaquinasAA(ActAnual filtroActAnual,
			Pagination pagination) {
		return this.maquinasDao.obtenerIdMaquinasAA(filtroActAnual, pagination);
	}

	/**
	 * obtener el número de máquinas que cumplen con el filtro
	 * 
	 * @param filtroPlanGeneral
	 *            PlanGeneral
	 * @return Long
	 */
	public Long obtenerMaquinasPGCount(PlanGeneral filtroPlanGeneral) {
		return this.maquinasDao.obtenerMaquinasPGCount(filtroPlanGeneral);
	}

	/**
	 * obtener el número de máquinas que cumplen con el filtro
	 * 
	 * @param filtroPrevAnual
	 *            PrevAnual
	 * @return Long
	 */
	public Long obtenerMaquinasPACount(PrevAnual filtroPrevAnual) {
		return this.maquinasDao.obtenerMaquinasPACount(filtroPrevAnual);
	}

	/**
	 * obtener el número de máquinas que cumplen con el filtro
	 * 
	 * @param filtroActAnual
	 *            ActAnual
	 * @return Long
	 */
	public Long obtenerMaquinasAACount(ActAnual filtroActAnual) {
		return this.maquinasDao.obtenerMaquinasAACount(filtroActAnual);
	}

	/**
	 * obtener los datos de las máquinas que cumplen con el filtro
	 * 
	 * @param filtroPlanGeneral
	 *            PlanGeneral
	 * @param idMaquinas
	 *            String
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public ArrayList obtenerPG(PlanGeneral filtroPlanGeneral, String idMaquinas) {
		return this.maquinasDao.obtenerPG(filtroPlanGeneral, idMaquinas);
	}

	/**
	 * obtener los datos de las máquinas que cumplen con el filtro
	 * 
	 * @param filtroPlanGeneral
	 *            PlanGeneral
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public ArrayList obtenerPGImprimir(PlanGeneral filtroPlanGeneral) {
		return this.maquinasDao.obtenerPGImprimir(filtroPlanGeneral);
	}

	/**
	 * obtener los datos de las máquinas que cumplen con el filtro
	 * 
	 * @param filtroPrevAnual
	 *            PrevAnual
	 * @param idMaquinas
	 *            String
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public ArrayList obtenerPA(PrevAnual filtroPrevAnual, String idMaquinas) {
		return this.maquinasDao.obtenerPA(filtroPrevAnual, idMaquinas);
	}

	/**
	 * obtener los datos de las máquinas que cumplen con el filtro
	 * 
	 * @param filtroActAnual
	 *            ActAnual
	 * @param idMaquinas
	 *            String
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public ArrayList obtenerAA(ActAnual filtroActAnual, String idMaquinas) {
		return this.maquinasDao.obtenerAA(filtroActAnual, idMaquinas);
	}

	/**
	 * obtener los datos de las máquinas que cumplen con el filtro
	 * 
	 * @param filtroActAnual
	 *            ActAnual
	 * @param idMaquinas
	 *            String
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public ArrayList obtenerAARealEdif(ActAnual filtroActAnual,
			String idMaquinas) {
		return this.maquinasDao.obtenerAARealEdif(filtroActAnual, idMaquinas);
	}

	/**
	 * obtener los datos de las máquinas que cumplen con el filtro
	 * 
	 * @param filtroPrevAnual
	 *            PrevAnual
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public ArrayList obtenerPAImprimir(PrevAnual filtroPrevAnual) {
		return this.maquinasDao.obtenerPAImprimir(filtroPrevAnual);
	}

	/**
	 * obtener los cuestionarios de las máquinas que cumplen con el filtro
	 * 
	 * @param filtroPrevAnual
	 *            PrevAnual
	 * @param idMaquinas
	 *            String
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public List<Maquinas> obtenerCuestionariosMaquinas(
			PrevAnual filtroPrevAnual, String idMaquinas) {
		return this.maquinasDao.obtenerCuestionariosMaquinas(filtroPrevAnual,
				idMaquinas);
	}

	/**
	 * Crear Parte Automático.
	 * 
	 * @param idMaquina
	 *            Integer
	 * @param sUIDUsuario
	 *            String
	 * @return String
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Ficha crearParteAutomatico(Long idMaquina, String sUIDUsuario,
			String mantenerTecnicos) {

		/****************** 1º grabar datos en la tabla FICHA ***************************/
		boolean mantenerTecnicosAnt = false;
		if (mantenerTecnicos != null && mantenerTecnicos.equals("1")) {
			mantenerTecnicosAnt = true;
		}
		Maquinas maquina = new Maquinas();
		maquina.setIdmaquina(idMaquina);
		// Obtener la fecha de siguiente mantenimiento
		maquina = this.maquinasDao.find(maquina);
		Date fechaSigMto = maquina.getSigMto();

		// Obtener los técnicos asinados a la última ficha que tiene la máquina.
		List<Fichatecnico> tecnicosUltimaFicha = this.fichatecnicoDao
				.tecnicosUltimaFichaMaquina(idMaquina);

		Ficha ficha = new Ficha();
		ficha.setIdmaquina(idMaquina);
		ficha.setFeejec(fechaSigMto);
		ficha.setEjecutado("0");
		/**
		 * MovilGmao Cuando se crea la ficha debemos meter un guid para después
		 * efectuar el envío a MovilGmao
		 */
		String randomUUIDString = "";
		UUID uuid = UUID.randomUUID();
		randomUUIDString = uuid.toString();
		ficha.setGuidficha(randomUUIDString);
		/***/

		/**
		 * Fecha planif agenda
		 */
		if (ficha.getFeejec() != null) {
			ficha.setFechaplanif(ficha.getFeejec());
		}

		ficha = this.fichaDao.add(ficha);

		/******************
		 * 2º Grabar en la tabla FICHATECNICOS un registro por cada tecnico que
		 * tiene asignados la anterior ficha de la máquina Si no hay ficha
		 * anterior o no hay tecnicos asignados a la ultima ficha Se asignan los
		 * técnicos que tiene asignados el usuario (Los que aparecen al pinchar
		 * en el botón de Ver Técnicos)
		 ***/
		Fichatecnico fichaTecnico = new Fichatecnico();
		if (!mantenerTecnicosAnt
				|| (mantenerTecnicosAnt && tecnicosUltimaFicha.size() == 0)) {
			// No hay ficha anterior o no hay tecnicos en la ficha anterior. Se
			// obtienen tecnicos asociados al usuario en TECNICOSPLANIF
			Tecnicoplanif filterTecnicoplanif = new Tecnicoplanif();
			filterTecnicoplanif.setUidPer(sUIDUsuario);
			List<Tecnicoplanif> tecnicoplanifs = this.tecnicoplanifDao.findAll(
					filterTecnicoplanif, null);

			for (int i = 0; i < tecnicoplanifs.size(); i++) {
				// Insertar en la tabla FICHATECNICOS
				fichaTecnico.setIdficha(ficha.getIdficha());
				fichaTecnico.setIdtecnico(tecnicoplanifs.get(i).getIdtecnico());
				fichaTecnico.setAceptada("1");
				fichaTecnico = this.fichatecnicoDao.add(fichaTecnico);
			}
		} else {
			// Se asignan los tecnicos de la ultima ficha. Si no tiene tecnicos
			// se deja sin asignar tecnicos
			for (int i = 0; i < tecnicosUltimaFicha.size(); i++) {
				fichaTecnico.setIdficha(ficha.getIdficha());
				fichaTecnico.setIdtecnico(tecnicosUltimaFicha.get(i)
						.getIdtecnico());
				fichaTecnico.setAceptada("1");
				fichaTecnico = this.fichatecnicoDao.add(fichaTecnico);
			}
		}

		/******************
		 * 3º Se graba en la tabla ACTUACIONES, tantas actuaciones como
		 * cuestionarios coincidan con la semana de mantenimiento que
		 * corresponda
		 ***/
		// Calcular las semanas de diferencia entre el primer mto y el siguiente
		Integer semanas = Aa20bFecha.difSemanas(maquina.getPrimerMto(),
				maquina.getSigMto());

		// Obtener los cuestionarios asociados a la gama de la máquina
		Cuestionario filterCuestionario = new Cuestionario();
		filterCuestionario.setIdgama(maquina.getIdgama());
		List<Cuestionario> cuestionarios = this.cuestionarioDao.findAll(
				filterCuestionario, null);

		Actuacion actuacion = new Actuacion();
		for (int i = 0; i < cuestionarios.size(); i++) {
			// Insertar en la tabla ACTUACION
			// para saber si coincide la semana de mantenimiento se calcula el
			// resto entre semanas y las semanas que aparecen en la tabla de
			// Cuestionarios.
			if (semanas % cuestionarios.get(i).getSemanas() == 0) {
				actuacion.setIdficha(ficha.getIdficha());
				actuacion.setIdmaquina(idMaquina);
				actuacion.setIdcuestionario(cuestionarios.get(i)
						.getIdcuestionario());
				actuacion.setFecha(maquina.getSigMto());

				actuacion = this.actuacionDao.add(actuacion);
			}
		}

		/******************
		 * 4º Se actualiza en tabla MAQUINAS la fecha de próxima revisión.
		 * SIG_MTO
		 * 
		 * Cálculo de fecha:  Se obtiene el NRO_SEMANAS que hay entre la fecha
		 * PRIMER_MTO y SIG_MTO y se suma 1 semana.
		 * 
		 *  Se obtiene DIF_MTOS de los diferentes valores de SEMANAS del
		 * cuestionario que le corresponde por la GAMA, ordenado de mayor a
		 * menor.
		 * 
		 *  Al resultado de la suma se divide entre el mayor valor de DIF_MTOS,
		 * • si resto = 0 tenemos ya la fecha de próximo mantenimiento. Se
		 * actualiza la fecha en tabla MAQUINAS, campo SIG_MTO. • Si resto <> 0,
		 * se suma 1 a NRO_SEMANAS y se vuelve a dividir. Esto hasta que resto =
		 * 0.
		 */

		// añadir dias (semanas+1 por 7 dias que tiene la semana y le sumamos un
		// dia a todo) a la fecha del primer mantenimiento
		Date fechaProx = Aa20bFecha.addDias(maquina.getPrimerMto(),
				((semanas + 1) * 7));

		// Obtener la difernecia en semanas entre las dos fechas
		Integer ds = Aa20bFecha.difSemanas(maquina.getPrimerMto(),
				Aa20bFecha.addDias(fechaProx, 1));
		// Recorremos las posibles semanas (añadiendo una semana cada vez) hasta
		// encontrar la valida
		boolean ok = false;
		while (!ok) {
			// Recorrer los cuestionarios asociados a la gama de la máquina
			for (int i = 0; i < cuestionarios.size(); i++) {
				if (ds % cuestionarios.get(i).getSemanas() == 0) {
					ok = true;
					break;
				}
			}
			if (!ok) {
				ds++;
			}
		}

		fechaProx = Aa20bFecha.addSemanas(maquina.getPrimerMto(), ds);
		// Actualizar el campo fecha siguiente mantenimiento en la tabla
		// Maquinas
		Maquinas maquinaAux = new Maquinas();
		maquinaAux.setIdmaquina(idMaquina);
		maquinaAux.setSigMto(fechaProx);
		maquina = this.maquinasDao.actualizarFechaSigMto(maquinaAux);

		return ficha;
	}

	/**
	 * Actualiza la fechas de primer y siguiente mantenimiento para una máquina.
	 * 
	 * @param maquinas
	 *            Maquinas
	 * @return Maquinas
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Maquinas actualizarFechasMto(Maquinas maquinas) {
		return this.maquinasDao.actualizarFechasMto(maquinas);
	}

}
