/*
 * $Id: RequestUtils.java 394468 2006-04-16 12:16:03Z tmjee $
 *
 * Copyright 2006 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.k_int.aggregator.dpp.actions;

import java.io.OutputStream;
import java.security.Principal;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.entity.ContentType;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
import com.k_int.aggregator.datamodel.ResourceInstanceHDO;
import com.k_int.euinside.client.module.preview.Preview;
import com.k_int.svc.identity.service.*;

public class ResourceStreamAction extends ActionSupport implements ServletResponseAware, ServletRequestAware {
	private static final long serialVersionUID = 1L;
	private static final String STREAM_TYPE_EUROPEANA = "europeana";
	private static final String STREAM_TYPE_STREAM = "stream";
	private static Log log = LogFactory.getLog(ResourceStreamAction.class);
 
	private HttpServletResponse response;
	private HttpServletRequest request;

	private SessionFactory factory;
	private String resource_id;
	private String streamType = STREAM_TYPE_STREAM;
	private String resourceType;
	private String provider;
	private String providerResourceId;
	private boolean secure = false;
	private IdentityService identity_service = null;

	public void setServletRequest(HttpServletRequest request) {
		this.request = request;
	}
	
	public void setServletResponse(HttpServletResponse response) {
		this.response = response;
	}
	
	public void setSessionFactory(org.hibernate.SessionFactory factory) {
		this.factory = factory;
	}
	
	public void setResourceId(String resource_id) {
		this.resource_id = resource_id;
	}
	
	public void setResourceType(String resourceType) {
		this.resourceType = resourceType;
	}
	
	public void setStreamType(String streamType) {
		this.streamType = streamType;
	}

	public void setProvider(String provider) {
		this.provider = provider;
	}

	public void setProviderResourceId(String providerResourceId) {
		this.providerResourceId = providerResourceId;
	}

	public boolean getSecure() {
		return(secure);
	}
	
	public void setSecure(boolean secure) {
		this.secure = secure;
	}

	public void setIdentityService(IdentityService identity_service) {
		this.identity_service = identity_service;
	}

	public IdentityService getIdentityService() {
		return identity_service;
	}

	public String execute() throws Exception {
		log.debug("execute");
   
		if (secure) {
			// User must either be logged in and be a provider *or* have an API key
			Principal principal = request.getUserPrincipal();
			if (((principal != null) && 
				 (request.isUserInRole("com.k_int.aggregator.roles.Depositor") ||
				  (request.isUserInRole("SYSTEM.admin")))) || 
				(verifyToken(request.getParameter("apikey")))) {
				log.debug("OAI Set to secure mode, apikey verified");
			} else {
				return("security");
			}
		}

		Session sess = null;
		try {
			sess = factory.openSession();
			if ((resourceType != null) && 
			    !resourceType.isEmpty()) {
				Query q = null;
				if ((providerResourceId != null) &&
					(provider != null)) {
					// We have provider and providerResourceId
					q = sess.createQuery("select r from ResourceInstanceHDO r, CultureGrid_ItemHDO i where r.resource.id = i.resource.id and i.identifier = ? and i.resource.source.identifier = ? and r.resourceType.identifier = ?");
					q.setParameter(0, providerResourceId);
					q.setParameter(1, provider);
					q.setParameter(2, resourceType);
				} else if (resource_id != null) {
					long id = Long.parseLong(resource_id);
					q = sess.createQuery("from ResourceInstanceHDO r where r.resource.id=? and r.resourceType.identifier=?");
					q.setParameter(0, id);
					q.setParameter(1, resourceType);
				}
				if (q != null) {
					ResourceInstanceHDO instance = (ResourceInstanceHDO) q.uniqueResult();
					if (instance != null) {
						switch (streamType) {
							case STREAM_TYPE_STREAM:
								streamResponse(response, instance.getContent(), instance.getResourceType().getMimeType());
								break;
								
							case STREAM_TYPE_EUROPEANA:
								// We will assume that the eckcore URL has already been set by the europeana class
								byte [] previewHTML = Preview.sendBytes(Preview.DEFAULT_PROVIDER, Preview.NOT_BATCH, instance.getContent());
								if (previewHTML != null) {
									// The records at te moment are coming back as xml instead of html, when they come back as html use TEXT_HTML, temporarily using APPLICATION_XML
									streamResponse(response, previewHTML, ContentType.TEXT_HTML.getMimeType() + "; charset=utf-8");
								}
								break;
						}
					}  
				} else {
					log.error("resource identifier or (provider identifier and provider resource identifier) not supplied");
				}
			} else {
				log.error("resource type not supplied");
			}
			sess.clear();
		} catch (HibernateException he ) {
			log.error("Problem with looking up the resource instance for id: " + ((resource_id == null) ? providerResourceId : resource_id), he);
		} finally {
			if (sess != null) {
				try {
					sess.close();
				} catch (Exception e) {
				}
			}
		}
		return Action.NONE;
	}
  
	private void streamResponse(HttpServletResponse response, byte[] content, String contentType) {
		try
		{
			OutputStream out = response.getOutputStream();
			response.setContentType(contentType);
			IOUtils.write(content,  out);
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			this.addActionError("Sorry, downloading of the converted content package failed because of " + e.getMessage());
		}
	}

	protected boolean verifyToken(String api_key) {
		if ((api_key != null) && (identity_service != null)) {
			try {
				SystemUserDTO user = identity_service.authenticate(api_key);
				if (user != null) {
					return true;
				}
			} catch (com.k_int.svc.identity.service.IdentityServiceException ise) {
				log.error("User session rejected",ise);
			}
		} else {
			log.info("User session rejected because identity service not configured in secure mode");
		}
		return(false);
	}
}
