/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.richfaces.realworld.ui;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Date;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.core.Events;
import org.richfaces.event.UploadEvent;
import org.richfaces.model.UploadItem;
import org.richfaces.realworld.domain.Image;
import org.richfaces.realworld.manager.FileManager;
import org.richfaces.realworld.manager.ImageManager;
import org.richfaces.realworld.manager.Model;
import org.richfaces.realworld.manager.NavigationEnum;
import org.richfaces.realworld.service.Constants;
import org.richfaces.realworld.service.FlushStrategy;
import org.richfaces.realworld.service.IImageAction;

import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.jpeg.JpegDirectory;

/**
 * @author $Autor$
 * 
 */
@Name("fileUploadBean")
@Scope(ScopeType.CONVERSATION)
public class FileUploadBean implements Serializable {
	
	@In("#{messages['file_processing_error']}")
	private String FILE_PROCESSING_ERROR;

	@In("#{messages['file_saving_error']}")
	private String FILE_SAVE_ERROR;
	
	@In IImageAction imageAction;
	@In @Out
	FileWrapper fileWrapper;

	@In Model model;
	@In private FileManager fileManager;

	@In("#{messages['samplename']}")
	private String SAMPLE_NAME;

	@In("#{messages['sampledesc']}")
	private String SAMPLE_DESCRIPTION;
	
	private static final long serialVersionUID = 4969087557225414955L;

	public synchronized void listener(UploadEvent event) throws Exception {
		UploadItem item = event.getUploadItem();
		Image image = constructImage(item);
		try {
			extractMetadata(item, image);
		} catch (JpegProcessingException e1) {
			Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, new Exception(FILE_PROCESSING_ERROR));
			return;
		} catch (MetadataException me) {
			Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, new Exception(FILE_PROCESSING_ERROR));
			return;
		}
		image.setAlbum(model.getSelectedAlbum());
		if(model.getSelectedAlbum() == null){
			Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, new Exception("Please specify album to download"));
			return;
		}
		String newPath = "/" +model.getSelectedAlbum().getOwner().getLogin() + "/" + model.getSelectedAlbum().getId() + "/" +item.getFileName();
		image.setPath(newPath);
		
		//TODO nick - file manager should be protected from another users accessing images of another people
		if(!fileManager.addImage(newPath, item.getFile().getPath())){
			Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, new Exception(FILE_SAVE_ERROR));
			item.getFile().delete();
			return;
		}
		fileWrapper.getFiles().add(0, image);
		//TODO nick - what's the point of storing image if image file save failed?
		imageAction.addImage(image);
		Events.instance().raiseEvent("imageAdded");
		item.getFile().delete();
		image.getAlbum().getUnvisitedImages().add(image);
		image.getAlbum().getShelf().getUnvisitedImages().add(image);
	}

	private Image constructImage(UploadItem item) {
		Image image = new Image();
		image.setUploaded(new Date());
		image.setDescription(SAMPLE_DESCRIPTION);
		image.setName(SAMPLE_NAME);
		image.setSize(item.getFileSize());
		image.setAllowComments(true);
		return image;
	}

	private void extractMetadata(UploadItem item, Image image)
			throws JpegProcessingException, MetadataException, IOException {
		InputStream in = new FileInputStream(item.getFile());
		//TODO nick - close "in"?
		Metadata metadata = JpegMetadataReader.readMetadata(in);
		Directory exifDirectory = metadata.getDirectory(ExifDirectory.class);
		Directory jpgDirectory = metadata.getDirectory(JpegDirectory.class);
		setupCameraModel(image, exifDirectory);
		setupDimensions(image, exifDirectory, jpgDirectory);
		setupCreatedDate(image, exifDirectory);
		in.close();
	}

	private void setupCreatedDate(Image image, Directory exifDirectory)
			throws MetadataException {
		if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME_ORIGINAL)) {
			Date time = exifDirectory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL);
			image.setCreated(time);
		}
	}

	private void setupDimensions(Image image, Directory exifDirectory,
			Directory jpgDirectory) throws MetadataException {
		if (exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_WIDTH) && exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) {
			int width = exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH);
			image.setWidth(width);
			int height = exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT);
			image.setHeight(height);
		} else {
			if (jpgDirectory.containsTag(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT)) {
				int width = jpgDirectory.getInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
				image.setWidth(width);
				int height = jpgDirectory.getInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
				image.setHeight(height);
			}
		}
	}

	private void setupCameraModel(Image image, Directory exifDirectory) {
		if (exifDirectory.containsTag(ExifDirectory.TAG_MODEL)) {
			String cameraModel = exifDirectory.getString(ExifDirectory.TAG_MODEL);
			image.setCameraModel(cameraModel);
		}else{
			image.setCameraModel("");
		}
	}
}