package com.ejie.y42b.control;

import java.sql.Blob;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.rowset.serial.SerialBlob;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.ejie.x38.control.exception.ControlException;
import com.ejie.x38.control.exception.MethodFailureException;
import com.ejie.x38.control.exception.ResourceNotFoundException;
import com.ejie.x38.control.exception.ServiceUnavailableException;
import com.ejie.x38.dto.JQGridJSONModel;
import com.ejie.x38.dto.Pagination;
import com.ejie.x38.util.ObjectConversionManager;
import com.ejie.y42b.model.Adjunto;
import com.ejie.y42b.model.Envio;
import com.ejie.y42b.service.AdjuntoService;
import com.ejie.y42b.utils.Y42bUIDGenerator32;

/**
 * * AdjuntoController  
 * 
 *  
 */

@Controller()
@RequestMapping(value = "/adjunto")
public class AdjuntoController {

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

	@Autowired()
	private AdjuntoService adjuntoService;

	@Autowired()
	private Properties appConfiguration;

	/**
	 * Method 'getCreateForm'.
	 * 
	 * @param model
	 *            Model
	 * @return String
	 */
	@RequestMapping(value = "maint", method = RequestMethod.GET)
	public ModelAndView getCreateForm(Model model) {
		model.addAttribute("defaultLanguage",
				this.appConfiguration.get("y42bVistaWar.default.language"));
		model.addAttribute("defaultLayout",
				this.appConfiguration.get("y42bVistaWar.default.layout"));
		return new ModelAndView("adjunto", "model", model);
	}

	/**
	 * Method 'getById'.
	 * 
	 * @param adjuntoId
	 *            String
	 * @param envioId
	 *            String
	 * @return String
	 */
	@RequestMapping(value = "/{adjuntoId}/{envioId}", method = RequestMethod.GET)
	public @ResponseBody()
	Adjunto getById(@PathVariable() String adjuntoId,
			@PathVariable() String envioId) {
		try {

			Adjunto adjunto = null;

			if ("subida".equals(adjuntoId)) {
				adjunto = new Adjunto();
				adjunto.setEnvio(new Envio());
				adjunto.setNombre(envioId);
				List<Adjunto> adjuntos = this.adjuntoService.findAllLike(
						adjunto, null, false);
				Integer tamano = adjuntos.size();
				adjunto = adjuntos.get(tamano - 1);

			} else {
				adjunto = new Adjunto();
				adjunto.setEnvio(new Envio());
				adjunto.setAdjuntoId(adjuntoId);
				adjunto.getEnvio().setEnvioId(envioId);
				adjunto = this.adjuntoService.find(adjunto);
			}
			if (adjunto == null) {
				throw new Exception(adjuntoId.toString() + envioId.toString());
			}
			return adjunto;
		} catch (Exception e) {
			throw new ResourceNotFoundException(adjuntoId.toString()
					+ envioId.toString());
		}
	}

	/**
	 * Method 'getAll'.
	 * 
	 * @param adjuntoId
	 *            String
	 * @param envioId
	 *            String
	 * @param nombre
	 *            String
	 * @param request
	 *            HttpServletRequest
	 * @param contentType
	 *            String
	 * @return String
	 */
	@RequestMapping(method = RequestMethod.GET)
	public @ResponseBody()
	Object getAll(
			@RequestParam(value = "adjuntoId", required = false) String adjuntoId,
			@RequestParam(value = "envioId", required = false) String envioId,
			@RequestParam(value = "nombre", required = false) String nombre,
			@RequestParam(value = "contentType", required = false) String contentType,
			HttpServletRequest request) {
		try {
			Adjunto filterAdjunto = new Adjunto(adjuntoId, new Envio(envioId,
					null, null, null, null, null, null, null, null, null, null,
					null, null, null, null, null, null, null, null, null, null,
					null, null, null, null, null), nombre, null, contentType);
			Pagination pagination = null;
			if (request.getHeader("JQGridModel") != null
					&& request.getHeader("JQGridModel").equals("true")) {
				pagination = new Pagination();
				pagination.setPage(Long.valueOf(request.getParameter("page")));
				pagination.setRows(Long.valueOf(request.getParameter("rows")));
				pagination.setSort(request.getParameter("sidx"));
				pagination.setAscDsc(request.getParameter("sord"));
				List<Adjunto> adjuntos = this.adjuntoService.findAll(
						filterAdjunto, pagination);

				if (adjuntos == null) {
					throw new Exception("No data Found.");
				}

				Long total = this.getAllCount(filterAdjunto, request);
				JQGridJSONModel data = new JQGridJSONModel();
				data.setPage(request.getParameter("page"));
				data.setRecords(total.intValue());
				data.setTotal(total, pagination.getRows());
				data.setRows(adjuntos);
				return data;
			} else {
				List<Adjunto> adjuntos = this.adjuntoService.findAll(
						filterAdjunto, pagination);
				if (adjuntos == null) {
					throw new Exception("No data Found.");
				}
				return adjuntos;
			}
		} catch (Exception e) {
			throw new ResourceNotFoundException("No data Found.");
		}
	}

	/**
	 * Method 'getAllCount'.
	 * 
	 * @param filterAdjunto
	 *            Adjunto
	 * @param request
	 *            HttpServletRequest
	 * @return Long
	 */
	@RequestMapping(value = "/count", method = RequestMethod.GET)
	public @ResponseBody()
	Long getAllCount(
			@RequestParam(value = "adjunto", required = false) Adjunto filterAdjunto,
			HttpServletRequest request) {
		try {
			return this.adjuntoService
					.findAllCount(filterAdjunto != null ? filterAdjunto
							: new Adjunto());
		} catch (Exception e) {
			throw new ServiceUnavailableException(
					"Count Service is not responding.");
		}
	}

	/**
	 * Method 'edit'.
	 * 
	 * @param adjunto
	 *            Adjunto
	 * @param response
	 *            HttpServletResponse
	 * @return Adjunto
	 */
	@RequestMapping(method = RequestMethod.PUT)
	public @ResponseBody()
	Adjunto edit(@RequestBody() Adjunto adjunto, HttpServletResponse response) {
		try {
			Adjunto adjuntoAux = this.adjuntoService.update(adjunto);
			AdjuntoController.logger.info("Entity correctly inserted!");
			return adjuntoAux;
		} catch (Exception e) {
			throw new MethodFailureException("Method failed");
		}
	}

	/**
	 * Method 'add'.
	 * 
	 * @param adjunto
	 *            Adjunto
	 * @return Adjunto
	 */
	@RequestMapping(method = RequestMethod.POST)
	public @ResponseBody()
	Adjunto add(@RequestBody() Adjunto adjunto) {
		try {
			Adjunto adjuntoAux = this.adjuntoService.add(adjunto);
			AdjuntoController.logger.info("Entity correctly inserted!");
			return adjuntoAux;
		} catch (Exception e) {
			throw new MethodFailureException("Method failed");
		}
	}

	/**
	 * Method 'add'.
	 * 
	 * @param file
	 *            MultipartFile
	 * @param response
	 *            HttpServletResponse
	 * @param request
	 *            HttpServletRequest
	 * @return Adjunto
	 */

	@RequestMapping(value = "subida", method = RequestMethod.POST)
	public @ResponseBody()
	List<Map<String, Object>> add(
			@RequestParam(value = "files[]", required = false) MultipartFile file,
			HttpServletResponse response, HttpServletRequest request) { // uploadService.saveToDisk(file,
																		// URL_UPLOAD_BASE_DIR);
		String envioId = "";
		Adjunto adjuntoAux = null;
		// MultipartFile adjuntoFil=null;
		try {
			envioId = request.getParameter("senMailEnvioId");
			// adjuntoFil= (MultipartFile) request.getParameter("adjunto");
			// Para hacer pruebas
			// envioId="C0CA226FFBE321EDA60A4AD9DF200820";

			Adjunto adjunto = new Adjunto();
			Envio envio = new Envio();
			envio.setEnvioId(envioId);
			adjunto.setNombre(file.getOriginalFilename().replace(" ", "_"));
			adjunto.setEnvio(envio);
			adjunto.setAdjuntoId(Y42bUIDGenerator32.getInstance().generateId());
			// Carga del BLOB
			Blob blob = new SerialBlob(file.getBytes());
			adjunto.setAdjunto(blob);
			adjunto.setContentType(file.getContentType());

			adjuntoAux = this.adjuntoService.add(adjunto);

			AdjuntoController.logger.info("Entity correctly inserted!"
					+ adjuntoAux);

		} catch (Exception e) {

			throw new MethodFailureException("Method failed");
		}

		List<Map<String, Object>> filesMetaInfo = new ArrayList<Map<String, Object>>();
		filesMetaInfo.add(this.getFileReturnMap(file,
				adjuntoAux.getAdjuntoId(), adjuntoAux.getEnvio().getEnvioId()));
		return filesMetaInfo;
	}

	/**
	 * Method 'download'.
	 * 
	 * @param fileName
	 *            String
	 * @param adjuntoId
	 *            String
	 * @param envioId
	 *            String
	 * @param response
	 *            m
	 * @throws Exception
	 *             d
	 */
	@RequestMapping(value = "{fileName}/{adjuntoId}/{envioId}", method = RequestMethod.GET)
	@ResponseStatus(HttpStatus.OK)
	public void download(@PathVariable() String fileName,
			@PathVariable() String adjuntoId, @PathVariable() String envioId,
			HttpServletResponse response) throws Exception {

		Adjunto filterAdjunto = new Adjunto(adjuntoId, new Envio(envioId, null,
				null, null, null, null, null, null, null, null, null, null,
				null, null, null, null, null, null, null, null, null, null,
				null, null, null, null), fileName, null, null);

		List<Adjunto> adjuntos = this.adjuntoService.findAll(filterAdjunto,
				null);
		if (adjuntos == null) {
			throw new Exception("No data Found.");
		}
		Adjunto adjuntoAux = new Adjunto();
		adjuntoAux = adjuntos.get(0);
		Blob contenido = adjuntoAux.getAdjunto();
		byte[] bContenido = contenido.getBytes(1, (int) contenido.length());

		// Cambiamos el objeto Response para visualizar el contenido del
		// archivo
		response.setHeader("Content-Disposition", "attachment; filename="
				+ fileName + "");
		response.setContentType(adjuntoAux.getContentType());
		response.getOutputStream().write(bContenido);

		// Vaciamos el stream
		response.getOutputStream().flush();
	}

	/**
	 * Method 'remove'.
	 * 
	 * @param fileName
	 *            String
	 * @param response
	 *            HttpServletResponse
	 * @param request
	 *            HttpServletRequest
	 */

	@RequestMapping(value = "{fileName}", method = RequestMethod.DELETE)
	@ResponseStatus(HttpStatus.OK)
	public void remove(@PathVariable() String fileName,
			HttpServletResponse response, HttpServletRequest request) {// uploadService.deleteFromDisk(URL_UPLOAD_BASE_DIR,
																		// fileName);
	}

	/**
	 * Method 'remove'.
	 * 
	 * @param adjuntoId
	 *            String
	 * @param envioId
	 *            String
	 * @param response
	 *            HttpServletResponse
	 * @param request
	 *            HttpServletRequest
	 * @return
	 */
	@RequestMapping(value = "/{adjuntoId}/{envioId}", method = RequestMethod.DELETE)
	public void remove(@PathVariable() String adjuntoId,
			@PathVariable() String envioId, HttpServletResponse response,
			HttpServletRequest request) {
		response.setContentType("text/javascript;charset=utf-8");
		response.setHeader("Pragma", "cache");
		response.setHeader("Expires", "0");
		response.setHeader("Cache-Control", "private");
		try {

			Adjunto adjunto = new Adjunto();
			adjunto.setEnvio(new Envio());
			adjunto.setAdjuntoId(adjuntoId);
			adjunto.getEnvio().setEnvioId(envioId);

			if ("adjuntoId".equals(adjuntoId)) {
				this.adjuntoService.removeAdjunto(adjunto);
			} else if ("subida".equals(adjuntoId)) {
				Adjunto adjuntoAux = new Adjunto();
				adjuntoAux.setNombre(envioId);
				adjuntoAux.setEnvio(new Envio());
				List<Adjunto> adjuntos = this.adjuntoService.findAllLike(
						adjuntoAux, null, false);
				Integer tamano = adjuntos.size();
				// adjuntos.get(tamano);
				// for (Adjunto adjuntoL : adjuntos) {
				if (tamano > 0) {
					this.adjuntoService.remove(adjuntos.get(tamano - 1));
				}

				// }
			}
			response.setStatus(HttpServletResponse.SC_OK);
		} catch (Exception e) {
			AdjuntoController.logger.error("Unable to delete " + adjuntoId
					+ envioId);
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			throw new MethodFailureException("Method failed");
		}
	}

	/**
	 * Method 'removeAll'.
	 * 
	 * @param adjuntoIds
	 *            ArrayList
	 * @param response
	 *            HttpServletResponse
	 * @return
	 */
	@RequestMapping(value = "/deleteAll", method = RequestMethod.POST)
	public void removeMultiple(
			@RequestBody() ArrayList<ArrayList<String>> adjuntoIds,
			HttpServletResponse response) {
		response.setContentType("text/javascript;charset=utf-8");
		response.setHeader("Pragma", "cache");
		response.setHeader("Expires", "0");
		response.setHeader("Cache-Control", "private");
		ArrayList<Adjunto> adjuntoList = new ArrayList<Adjunto>();
		try {
			Adjunto adjunto = new Adjunto();
			Envio nwEnvio = new Envio();
			for (ArrayList<String> adjuntoId : adjuntoIds) {
				Iterator<String> iterator = adjuntoId.iterator();

				adjunto.setEnvio(nwEnvio);
				adjunto.setAdjuntoId(ObjectConversionManager.convert(
						iterator.next(), String.class));
				adjunto.getEnvio().setEnvioId(
						ObjectConversionManager.convert(iterator.next(),
								String.class));
				adjuntoList.add(adjunto);
			}
			this.adjuntoService.removeMultiple(adjuntoList);
			response.setStatus(HttpServletResponse.SC_OK);
		} catch (Exception e) {
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			throw new MethodFailureException("Method failed");
		}
	}

	/**
	 * 
	 * @param file
	 *            Archivo
	 * @param adjuntoId
	 *            AdjuntoId
	 * @param envioId
	 *            EnvioId
	 * @return mapa
	 */
	private Map<String, Object> getFileReturnMap(MultipartFile file,
			String adjuntoId, String envioId) {
		Map<String, Object> mapaRetorno = new HashMap<String, Object>();
		mapaRetorno.put("url", "../adjunto/"
				+ file.getOriginalFilename().replace(" ", "_") + "/"
				+ adjuntoId + "/" + envioId);
		mapaRetorno.put("name", file.getOriginalFilename().replace(" ", "_"));
		mapaRetorno.put("type", file.getContentType());
		mapaRetorno.put("size", file.getSize());
		mapaRetorno.put("adjuntoId", adjuntoId);
		mapaRetorno.put("envioId", envioId);
		mapaRetorno.put("delete_url", "../adjunto/subida/"
				+ file.getOriginalFilename().replace(" ", "_"));
		mapaRetorno.put("delete_type", "DELETE");
		return mapaRetorno;
	}

	/**
	 * Method 'handle'.
	 * 
	 * @param e
	 *            ControlException
	 * @return String
	 */
	@ExceptionHandler()
	public @ResponseBody()
	String handle(ControlException e) {
		AdjuntoController.logger.warn(e.getMessage());
		return e.getMessage();
	}

	/**
	 * Method 'getAdjuntoService'.
	 * 
	 * @return AdjuntoService
	 */
	protected AdjuntoService getAdjuntoService() {
		return this.adjuntoService;
	}

	/**
	 * Method 'setAdjuntoService'.
	 * 
	 * @param adjuntoService
	 *            AdjuntoService
	 * @return
	 */
	public void setAdjuntoService(AdjuntoService adjuntoService) {
		this.adjuntoService = adjuntoService;
	}

	/**
	 * Method 'getAppConfiguration'.
	 * 
	 * @return appConfiguration
	 */
	public Properties getAppConfiguration() {
		return this.appConfiguration;
	}

	/**
	 * Method 'setAppConfiguration'.
	 * 
	 * @param appConfiguration
	 *            Properties
	 * @return
	 */
	public void setAppConfiguration(Properties appConfiguration) {
		this.appConfiguration = appConfiguration;
	}

	/**
	 * Method 'remove'.
	 * 
	 * @param adjuntoId
	 *            String
	 * @param envioId
	 *            String
	 * @param response
	 *            HttpServletResponse
	 * @param request
	 *            HttpServletRequest
	 * @return
	 */
	@RequestMapping(value = "/removeAdjunto/{adjuntoId}/{envioId}", method = RequestMethod.DELETE)
	public void removeAdjunto(@PathVariable() String adjuntoId,
			@PathVariable() String envioId, HttpServletResponse response,
			HttpServletRequest request) {
		response.setContentType("text/javascript;charset=utf-8");
		response.setHeader("Pragma", "cache");
		response.setHeader("Expires", "0");
		response.setHeader("Cache-Control", "private");
		try {

			Adjunto adjunto = new Adjunto();
			adjunto.setEnvio(new Envio());
			adjunto.setAdjuntoId(adjuntoId);
			adjunto.getEnvio().setEnvioId(envioId);

			this.adjuntoService.remove(adjunto);
		} catch (Exception e) {
			AdjuntoController.logger.error("Unable to delete " + adjuntoId
					+ envioId);
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			throw new MethodFailureException("Method failed");
		}
	}

	// @RequestMapping(method = RequestMethod.POST)
	//
	// public @ResponseBody List<Map<String, Object>> add1(
	//
	// @RequestParam(value = "filename", required = false) String filename,
	//
	// @RequestParam(value = "nombre", required = false) String nombre,
	//
	// @RequestParam(value = "files[]", required = false) MultipartFile file,
	// HttpServletResponse response, HttpServletRequest request) {
	//
	// if (!file.isEmpty()) { //
	// //uploadService.saveToDisk(file,AppConfiguration.getProperty
	// ("fileUpload.path"));
	// File fileToDisk = new File(
	// appConfiguration.getProperty("fileUpload.path"),
	// file.getOriginalFilename()); try {
	// FileUtils.writeByteArrayToFile(fileToDisk, file.getBytes()); } catch
	// (IOException e) { e.printStackTrace(); // return Boolean.FALSE; }
	//
	// // return Boolean.TRUE; }
	//
	// List<Map<String, Object>> filesMetaInfo = new ArrayList<Map<String,
	// Object>>(); filesMetaInfo.add(this.getFileReturnMap1(file));
	//
	// return filesMetaInfo; }

	// private Map<String, Object> getFileReturnMap1(MultipartFile file) {
	//
	// Map<String, Object> mapaRetorno = new HashMap<String, Object>();
	//
	// mapaRetorno.put("url",
	// "../upload?fileName=" + file.getOriginalFilename());
	// mapaRetorno.put("name", file.getOriginalFilename());
	// mapaRetorno.put("type", file.getContentType());
	// mapaRetorno.put("size", file.getSize());
	// mapaRetorno.put("delete_url",
	// "../upload?fileName=" + file.getOriginalFilename());
	// mapaRetorno.put("delete_type", "DELETE");
	//
	// return mapaRetorno;
	//
	// }

}
