package org.gcube.portlets.user.reportgenerator.server.servlet;

import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.io.IOUtils;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.detect.Detector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import org.gcube.application.framework.core.session.ASLSession;
import org.gcube.application.framework.core.session.SessionManager;
import org.gcube.application.reporting.reader.ModelReader;
import org.gcube.application.rsg.client.RsgReadClient;
import org.gcube.application.rsg.client.RsgWriteClient;
import org.gcube.application.rsg.client.support.ClientException;
import org.gcube.application.rsg.service.dto.ReportEntry;
import org.gcube.application.rsg.service.dto.ReportType;
import org.gcube.application.rsg.service.dto.response.ServiceResponse;
import org.gcube.application.rsg.service.dto.response.ServiceResponseMessage;
import org.gcube.application.rsg.support.builder.exceptions.ReportBuilderException;
import org.gcube.application.rsg.support.builder.impl.ReportManagerReportBuilder;
import org.gcube.application.rsg.support.model.components.impl.CompiledReport;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.Property;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.portal.custom.scopemanager.scopehelper.ScopeHelper;
import org.gcube.portlets.d4sreporting.common.server.ServiceUtil;
import org.gcube.portlets.d4sreporting.common.shared.Model;
import org.gcube.portlets.d4sreporting.common.shared.RepTimeSeries;
import org.gcube.portlets.d4sreporting.common.shared.Table;
import org.gcube.portlets.d4sreporting.common.shared.TableCell;
import org.gcube.portlets.user.reportgenerator.client.ReportConstants;
import org.gcube.portlets.user.reportgenerator.client.ReportService;
import org.gcube.portlets.user.reportgenerator.shared.RSGAccessPoint;
import org.gcube.portlets.user.reportgenerator.shared.ReportImage;
import org.gcube.portlets.user.reportgenerator.shared.SessionInfo;
import org.gcube.portlets.user.reportgenerator.shared.UserBean;
import org.gcube.portlets.user.reportgenerator.shared.VMEReportBean;
import org.gcube.portlets.user.reportgenerator.shared.VMETypeIdentifier;
import org.gcube.portlets.user.reportgenerator.shared.VmeExportResponse;
import org.gcube.portlets.user.reportgenerator.shared.VmeResponseEntry;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.vomanagement.usermanagement.RoleManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayGroupManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeRole;
import org.gcube.vomanagement.usermanagement.model.GCubeTeam;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.gcube.vomanagement.usermanagement.model.GatewayRolesNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.liferay.portal.service.UserLocalServiceUtil;

import net.sf.csv4j.CSVFileProcessor;
import net.sf.csv4j.CSVLineProcessor;
import net.sf.csv4j.ParseException;
import net.sf.csv4j.ProcessingException;




/**
 * 
 * class implementing services
 * @author Massimiliano Assante, ISTI-CNR - massimiliano.assante@isti.cnr.it
 */
@SuppressWarnings("serial")
public class ReportServiceImpl  extends RemoteServiceServlet implements ReportService {

	private static final Logger _log = LoggerFactory.getLogger(ReportServiceImpl.class);

	protected static final String IMAGE_SERVICE_URL = "reports/DownloadService";
	/**
	 * 
	 */
	public static final String CURRENT_REPORT_ID_ATTRIBUTE = "CURRENT_REPORT_ID_ATTRIBUTE";
	/**
	 * 
	 */
	public static final String CURRENT_REPORT_INSTANCE = "myReport";
	/**
	 * 
	 */
	public static final String PREVIOUS_REPORT_INSTANCE = "myPreviousReport";
	/**
	 * 
	 */
	public static final String RSG_WS_ADDRESS = "RSG-WS-ENDPOINT";

	private static final String REPORT_IMAGES_FOLDER = "Report Images";
	public static final String TEST_USER = "test.user";
	public static final String TEST_SCOPE = "/gcube/devsec/devVRE";


	//the client for the VME-DB case
	private RsgReadClient rsgReadClient;
	private RsgWriteClient rsgWriteClient;


	/**
	 * the current ASLSession
	 * @return .
	 */
	private ASLSession getASLSession() {
		String sessionID = this.getThreadLocalRequest().getSession().getId();

		String user = (String) this.getThreadLocalRequest().getSession().getAttribute(ScopeHelper.USERNAME_ATTRIBUTE);
		if (user == null) {
			user =  getDevelopmentUser();
			if (user.compareTo(TEST_USER) != 0) {
				SessionManager.getInstance().getASLSession(sessionID, user).setScope(TEST_SCOPE);
				this.getThreadLocalRequest().getSession().setAttribute(ScopeHelper.USERNAME_ATTRIBUTE, user);			
				String email = user+"@isti.cnr.it";
				String fullName = "Andrea Rossi";
				String thumbnailURL = "images/Avatar_default.png";
				SessionManager.getInstance().getASLSession(sessionID, user).setUserEmailAddress(email);
				SessionManager.getInstance().getASLSession(sessionID, user).setUserAvatarId(thumbnailURL);
				SessionManager.getInstance().getASLSession(sessionID, user).setUserFullName(fullName);
			}

		}
		return SessionManager.getInstance().getASLSession(sessionID, user);

	}
	public String getDevelopmentUser() {
		String user = TEST_USER;
		return user;
	}
	/**
	 * 
	 * @return true if you're running into the portal, false if in development
	 */
	private boolean isWithinPortal() {
		try {
			UserLocalServiceUtil.getService();
			return true;
		} 
		catch (com.liferay.portal.kernel.bean.BeanLocatorException ex) {			
			_log.trace("Development Mode ON");
			return false;
		}			
	}
	/**
	 * 	Retrieve the user saved template names
	 * 
	 * 	@return a String[] containing the template names 
	 */
	public String[] getUserTemplateNames() {
		ServiceUtil myUtil = new ServiceUtil(getASLSession());
		Vector<String> tmp = new Vector<String>();
		String userDir = myUtil.getTemplateFolder(getVreName(), getUsername());

		_log.debug("userDir: " + userDir);

		File f  = new File(userDir);
		//checking if dir exists
		if (! f.exists()) {
			try {
				f.mkdirs();
				return new String[0];
			} catch (SecurityException ex) { 
				return new String[0];
			}
		}
		else {
			File []f2 = f.listFiles();
			for(int i = 0; i < f2.length; i++){
				if(f2[i].isDirectory()) {
					tmp.add(f2[i].getName());
				}
			}		
			return tmp.toArray(new String[0]);
		}
	}


	/**
	 *  @return a SerializableModel instance of the imported fimes xml
	 */
	public Model readImportedModel(String tempPath) {
		Model toConvert = null;

		FileInputStream fis = null;
		ObjectInputStream in = null;

		try {

			fis = new FileInputStream(tempPath);
			in = new ObjectInputStream(fis);
			toConvert = (Model) in.readObject();
			in.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		_log.debug("Converting Imported Fimes to Serializable object, num sections: " + toConvert.getSections().size());
		return (toConvert);
	}

	/**
	 * @return a SerializableModel instance of the templatename passed as parameter
	 * @param templateName : the template to read from disk
	 * @param templateObjectID the id in the basket
	 * @param isTemplate says if you're opening a template or a report
	 * @param isImporting says if your importing or youre loading a template in the UI
	 * 
	 */
	public Model readModel(String templateName, String templateObjectID, boolean isTemplate, boolean isImporting) {
		return new Model();
	}


	/**
	 * used when an image is uploaded
	 */
	@Override
	public ReportImage getUploadedImageUrlById(String fileName, String absolutePathOnServer) {
		return null;
	}

	/**
	 * 
	 * @param is
	 * @return
	 * @throws IOException 
	 * @throws MagicParseException
	 * @throws MagicMatchNotFoundException
	 * @throws MagicException
	 */
	protected static String getMimeType(InputStream is, String filenameWithExtension) throws IOException {
		TikaConfig config = TikaConfig.getDefaultConfig();
		Detector detector = config.getDetector();
		TikaInputStream stream = TikaInputStream.get(is);
		Metadata metadata = new Metadata();
		metadata.add(Metadata.RESOURCE_NAME_KEY, filenameWithExtension);
		MediaType mediaType = detector.detect(stream, metadata);
		return mediaType.getBaseType().toString();
	}
	/**
	 * used to actually display images in reports (when reading reports)
	 */
	@Override
	public ReportImage getImageUrlById(String identifier) {
		return null;
	}

	/**
	 * 
	 * @param id
	 * @return
	 */
	protected String buildImageServiceUrl(String id) {
		StringBuilder sb = new StringBuilder();

		sb.append(this.getServletContext().getContextPath()).append("/");
		sb.append(IMAGE_SERVICE_URL).append("?id=").append(id).append("&type=IMAGE");
		return sb.toString();
	}


	





	/**
	 * 
	 * @return the shared session
	 */
	public String getUsername() {
		if (! ReportConstants.isDeployed) {
			return "massimiliano.assante";
		} else {
			HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
			HttpSession session = httpServletRequest.getSession();
			String user = (String) session.getAttribute(ScopeHelper.USERNAME_ATTRIBUTE);
			if(session.getAttribute(ScopeHelper.USERNAME_ATTRIBUTE)== null)
			{
				user = "massimiliano.assante";
				_log.warn("D4ScienceSession user NULL set to: " + user);
			}
			_log.warn("ASLSession user: " + user);

			ASLSession d4session = SessionManager.getInstance().getASLSession(session.getId(), user);
			d4session.setAttribute(ScopeHelper.USERNAME_ATTRIBUTE, user);
			return user;
		}
	}

	/**
	 * 
	 * @return the current scope
	 */
	public String getVreName() {
		if (! ReportConstants.isDeployed) {
			return TEST_SCOPE;
		} else {
			HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
			HttpSession session = httpServletRequest.getSession();

			ASLSession d4session = SessionManager.getInstance().getASLSession(session.getId(), getUsername());
			String scope = d4session.getScopeName();

			if(scope == null) {
				scope = TEST_SCOPE;
				_log.warn("ASL Session scope NULL set to: " + scope);
			}

			//need to remove the initial / of the scope
			if (scope.charAt(0) == '/')
				scope = scope.substring(1, scope.length());
			_log.info("SCOPE: " + scope);
			return scope;
		}

	}

	private RSGAccessPoint getRSGWSAddress() {
		RSGAccessPoint rsgAp = (RSGAccessPoint) this.getThreadLocalRequest().getSession().getAttribute(RSG_WS_ADDRESS);
		if (rsgAp != null)
			_log.trace("getRSGWSAddress: " + rsgAp.getRestUrl());
		return rsgAp;
	}

	private void setRSGWSAddress(RSGAccessPoint rsgAp) {
		this.getThreadLocalRequest().getSession().setAttribute(RSG_WS_ADDRESS, rsgAp);
		if (rsgAp != null)
			_log.trace("setting RSG WS address to " + rsgAp.getRestUrl());
	}



	/**
	 * 
	 * @return the model previously stored in the session 
	 */
	public Model readTemplateFromSession() {
		return null;
	}


	/**
	 * recurdively delete the templates folder of the dir dir
	 * @param dir the dir to delete
	 */
	public void delTemplateDir(File dir) {
		try {
			File[] files = dir.listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory())
					delTemplateDir(files[i]);
				files[i].delete();
			}
		} catch (Exception e) {
			System.out.println("WARNING: Could not cleaning temp dir: reason unknown");
		}
	}


	/**
	 * @param model to store in the session
	 */
	public void storeTemplateInSession(Model model) {
		ASLSession d4Session =  getASLSession();
		d4Session.setAttribute(CURRENT_REPORT_INSTANCE, model);
		_log.trace("Saved in Session");
	}


	/**
	 * @param reportItemid the report itemd id in basket to store in the session
	 */
	public void storeReportItemIDInSession(String reportItemid) {
		ASLSession d4Session =  getASLSession();
		d4Session.setAttribute(CURRENT_REPORT_ID_ATTRIBUTE, reportItemid);
		_log.debug("WROTE REPORT ID IN SESSION: " + reportItemid);
	}

	/**
	 * @return the report item id in basket, or "" if doesn't exist
	 */
	public String getReportItemIDFromSession() {
		ASLSession d4Session =  getASLSession();
		if (d4Session.getAttribute(CURRENT_REPORT_ID_ATTRIBUTE) == null)
			return "";
		else 
			return d4Session.getAttribute(CURRENT_REPORT_ID_ATTRIBUTE).toString();		
	}
	/**
	 * used to save  the report in the same folder
	 */
	public void saveReport(Model toSave) {
		_log.warn("saveReport Not supported anymore");
	}



	/**
	 * @param save a report in another folder .
	 * 
	 */
	public void saveReport(Model toSave, String folderid, String newname) {
		_log.warn("saveReport Not supported anymore");
	}

	/*
	
	/**
	 * return a sample of the given TS to the client
	 * @param sTS .
	 * @return .
	 */
	public Table getSampleTimeSeries(RepTimeSeries sTS) {
		return null;	
	}

	

	/**
	 * 
	 * @param toParse the csv to parse
	 * @throws ProcessingException .
	 * @throws IOException .
	 * @throws ParseException . 
	 */
	private Table parseCSV(File toParse, final RepTimeSeries sTS) throws ParseException , IOException, ProcessingException {		

		final Table toReturn;
		final boolean isFiltered;
		final int fromLine;
		final int toLine;

		//if there is no filter
		if ( sTS.getFilter() == null) {
			toReturn = new Table(sTS.getTsMetadata().getHeaderLabels().size());
			isFiltered = false;
			fromLine = 1;
			toLine = 10;
		}
		else {
			int headers = sTS.getFilter().getColsNumberToShow().size();
			toReturn = new Table(headers);
			isFiltered = true;
			fromLine = sTS.getFilter().getFrom();
			toLine = fromLine + 10;
		}


		final CSVFileProcessor fp = new CSVFileProcessor();
		fp.processFile(toParse.getAbsolutePath() , new CSVLineProcessor() {
			boolean keepGoing = true;

			public void processHeaderLine( final int linenumber, final List<String> fieldNames )    {
				ArrayList<TableCell> toInsert = new ArrayList<TableCell>();
				for (String field : fieldNames) {
					toInsert.add(new TableCell(field));
				}
				if (! isFiltered) 
					toReturn.addRow((ArrayList<TableCell>) toInsert);
				else {
					ArrayList<String> filteredHeaders = new ArrayList<String>();
					for (Integer colNo : sTS.getFilter().getColsNumberToShow()) {
						String toAdd = sTS.getTsMetadata().getHeaderLabels().get(colNo);
						filteredHeaders.add(toAdd);
						toInsert = new ArrayList<TableCell>();
						for (String field : filteredHeaders) {
							toInsert.add(new TableCell(field));
						}
					}
					toReturn.addRow(toInsert);
				}		       		
			}


			public void processDataLine( final int linenumber, final List<String> fieldValues ) {
				if (linenumber > toLine)
					keepGoing = false;
				if (linenumber >= fromLine && linenumber <= toLine) {
					ArrayList<TableCell> toInsert = new ArrayList<TableCell>();
					for (String field : fieldValues) {
						toInsert.add(new TableCell(field));
					}
					if (! isFiltered) 
						toReturn.addRow(toInsert);
					else {
						ArrayList<String> filteredFields = new ArrayList<String>();
						for (Integer colNo : sTS.getFilter().getColsNumberToShow()) {
							String toAdd = fieldValues.get(colNo);
							filteredFields.add(toAdd);
							toInsert = new ArrayList<TableCell>();
							for (String field : filteredFields) {
								toInsert.add(new TableCell(field));
							}
						}
						toReturn.addRow(toInsert);
					}		    
				}
			}
			public boolean continueProcessing() {				
				return keepGoing;
			}
		} );
		return toReturn;
	}


	


	/**
	 * each portlet instance runs in a scope
	 * each portlet instance is used by a unique username from within the portal
	 * @param currentHost .
	 * @return a SessionInfo bean containing the username  the scope andis opening a workflow document or not
	 */
	public SessionInfo getSessionInfo(String currentHost) {
		boolean isVME = isReportsStoreGatewayAvailable();
		String rsgEndpoint = "";
		if (getRSGWSAddress() != null)
			rsgEndpoint = ((RSGAccessPoint) getRSGWSAddress()).getRestUrl();
		return new SessionInfo(getUserBean(), getVreName(), false, false, isVME, rsgEndpoint);



	}	
	/**
	 * 
	 * @return the info about the current user
	 */
	private UserBean getUserBean() {
		try {

			String username = getASLSession().getUsername();
			String email = username+"@isti.cnr.it";
			String fullName = username+" FULL";
			String thumbnailURL = "images/Avatar_default.png";

			if (isWithinPortal()) {

				GCubeUser user = new LiferayUserManager().getUserByUsername(username);
				thumbnailURL = user.getUserAvatarURL();
				fullName = user.getFullname();
				email = user.getEmail();
				UserBean toReturn = new UserBean(username, fullName, thumbnailURL, email);
				_log.debug("Returning USER: " + toReturn);
				return toReturn;
			}
			else {
				UserBean toReturn = new UserBean(getASLSession().getUsername(), fullName, thumbnailURL, email);
				_log.debug("Returning test USER: " + toReturn);
				return toReturn;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return new UserBean();
	}
	/**
	 */
	byte[] getBytesFromInputStream(InputStream is) {
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		try {
			IOUtils.copy(is, os);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return os.toByteArray();
	}
	
	

	@Override
	public void renewHTTPSession() {
		HttpSession session = this.getThreadLocalRequest().getSession();
		_log.info("HTTP Session renewed" + new Date(session.getLastAccessedTime()));
	}

	private RsgReadClient getRsgClient() {
		RSGAccessPoint rsgWsAddr = getRSGWSAddress();
		if (rsgReadClient == null) {
			rsgReadClient = new RsgReadClient(rsgWsAddr.getRestUrl());
			_log.info("rsgReadClient = new RsgReadClient(rsgWsAddr.getRestUrl()"+rsgWsAddr.getRestUrl());
		}
		return rsgReadClient;
	}

	private RsgWriteClient getRsgSecureClient() {
		RSGAccessPoint rsgWsAddr = getRSGWSAddress();
		if (rsgWriteClient == null) {
			rsgWriteClient = new RsgWriteClient(rsgWsAddr.getRestUrl()+"/write");

			try {
				rsgWriteClient.secureWithPlainTokenSecurity(rsgWsAddr.getTokenUrl());
				_log.info("rsgWriteClient.secureWithPlainTokenSecurity(rsgWsAddr.getTokenUrl())"+rsgWsAddr.getTokenUrl());
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
		return rsgWriteClient;
	}
	/**
	 * the list of Regional Fishery Management Organizations (RFMO) associated to the current user is constructed by looking at the roles
	 * of the current user. 
	 * 
	 * @returnt the list of Regional Fishery Management Organizations (RFMO) associated to the current user.
	 */
	private ArrayList<String> getUserRFMOs() {
		if (! isWithinPortal()) 
			return new ArrayList<String>();
		ArrayList<String> toReturn = new ArrayList<String>();
		RoleManager rm = new LiferayRoleManager();
		ASLSession session = getASLSession();
		try {
			GCubeUser theUser = new LiferayUserManager().getUserByUsername(session.getUsername());
			long groupId = new LiferayGroupManager().getGroupIdFromInfrastructureScope(session.getScope());
			List<GCubeTeam> roles = rm.listTeamsByUserAndGroup(theUser.getUserId(), groupId);
			for (GCubeTeam team : roles) {
				_log.info("VRE Group " + team.getTeamName() + " Adding RFMO");
				if (team.getTeamName().endsWith("-Editor")) {
					String[] splits = team.getTeamName().split("-");
					toReturn.add(splits[0]);
					_log.info("Added grant for RFMO="+splits[0]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return toReturn;
	}
	/**
	 * 
	 * @return whether the user is a VRE Manager for this VRE or not.
	 */
	private boolean isVREManager() {
		if (isWithinPortal()) {
			RoleManager rm = new LiferayRoleManager();
			ASLSession session = getASLSession();

			try {
				long groupId = new LiferayGroupManager().getGroupIdFromInfrastructureScope(session.getScope());
				GCubeUser theUser = new LiferayUserManager().getUserByUsername(session.getUsername());
				List<GCubeRole> roles = rm.listRolesByUserAndGroup(theUser.getUserId(), groupId);
				for (GCubeRole role : roles) 
					if (role.getRoleName().equals(GatewayRolesNames.VRE_MANAGER.getRoleName()))	return true;
			} 
			catch (Exception e) {
				e.printStackTrace();
			} 
			return false;
		} else {
			_log.warn("Working in Eclipse, returning all rights");
			return true;
		}
	}

	@Override
	public ArrayList<VMEReportBean> listVMEReports() {
		ArrayList<VMEReportBean> toReturn = new ArrayList<VMEReportBean>();
		ReportType type = new ReportType();
		type.setTypeIdentifier("Vme");

		_log.info("listVMEReports() instantiating secure rsgClient ...");
		rsgReadClient = getRsgClient();		
		_log.info("listVMEReports() securedWithEncryptedToken completed");

		ReportEntry[] reports = null;
		try {
			_log.info("calling rsgClient#listReports... ");
			reports = rsgReadClient.listReports(type);
			_log.info("got the reports list");
		} catch (ClientException e) {
			_log.error("failed to get the list of VME Reports: " + e.getMessage());
		}
		if (isVREManager()) {
			for (ReportEntry re : reports) {
				String rfmo = re.getOwner();
				String name = re.getIdentifier();
				toReturn.add(new VMEReportBean(""+re.getId(), rfmo, name));		
			}	
		} else {
			ArrayList<String> allowedRFMOs = getUserRFMOs();
			for (ReportEntry re : reports) {
				String rfmo = re.getOwner().trim();
				String name = re.getIdentifier();
				for (String allowedRFMO : allowedRFMOs) {
					if (allowedRFMO.compareTo(rfmo) == 0) {
						toReturn.add(new VMEReportBean(""+re.getId(), rfmo, name));
						_log.debug("Added " + rfmo + " - " + name);
					}
				}

			}	
		}	

		return toReturn;
	}

	@Override
	public ArrayList<VMEReportBean> listVMEReportRefByType(VMETypeIdentifier refType) {
		if (refType == VMETypeIdentifier.Vme)
			throw new IllegalArgumentException("VME Type is not a reference");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
		}
		ArrayList<VMEReportBean> toReturn = new ArrayList<VMEReportBean>();
		ReportType type = new ReportType();
		type.setTypeIdentifier(refType.toString());
		rsgReadClient = getRsgClient();	

		if (isVREManager()) {
			for (ReportEntry re :rsgReadClient.listReports(new ReportType(refType.getId()))) {
				String rfmo = re.getOwner();
				String name = re.getIdentifier();
				toReturn.add(new VMEReportBean(""+re.getId(), rfmo, name));			
			}	
		} else {
			ArrayList<String> allowedRFMOs = getUserRFMOs();
			for (ReportEntry re :rsgReadClient.listReports(new ReportType(refType.getId()))) {
				String rfmo = re.getOwner();
				String name = re.getIdentifier();
				if (rfmo == null) { //when getting a RFMO refType the Owner is null
					rfmo = name;
				}				
				for (String allowedRFMO : allowedRFMOs) {
					if (allowedRFMO.compareTo(rfmo) == 0) {						
						toReturn.add(new VMEReportBean(""+re.getId(), rfmo, name));
						_log.debug("Added ref report " + rfmo + " - " + name);
					}
				}
			}	
		}


		return toReturn;		
	}


	@Override
	public Model importVMEReport(String id, String name, VMETypeIdentifier refType) {
		rsgReadClient = getRsgClient();	


		CompiledReport cr = null;
		if (refType == VMETypeIdentifier.Vme) {
			_log.info("Importing VME id=" + id +  " name=" + name);
			cr = rsgReadClient.getReportById(new ReportType(refType.getId()), id);
		} 
		else {
			_log.info("Importing Ref type= " + refType.getId() + " id=" + id +  " name=" + name);
			cr = rsgReadClient.getReferenceReportById(new ReportType(refType.getId()), id);

		}
		Model model = null;
		try {
			model = new ReportManagerReportBuilder().buildReport(cr);
			model.setTemplateName(name);
			//ReportsReader.readReportStructure(model);			
		} catch (ReportBuilderException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		ModelReader reader = new ModelReader(model);
		System.out.println(reader);
		return model;
	}

	@Override
	public Model getVMEReportRef2Associate(String id, VMETypeIdentifier refType) {
		rsgReadClient = getRsgClient();	


		_log.info("Importing Ref type= " + refType.getId() + " id=" + id);
		CompiledReport cr = rsgReadClient.getReferenceReportById(new ReportType(refType.getId()), id);
		Model model = null;
		try {
			model = new ReportManagerReportBuilder().buildReferenceReport(cr);
		} catch (ReportBuilderException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return model;
	}

	@Override
	public Model importVMETemplate(VMETypeIdentifier refType) {
		rsgReadClient = getRsgClient();	

		CompiledReport cr = null;
		if (refType == VMETypeIdentifier.Vme) {
			_log.info("Importing VME Template");
			cr = rsgReadClient.getTemplate(new ReportType(refType.getId()));			
		} 
		else {
			_log.info("Importing Ref type= " + refType.getId());
			cr = rsgReadClient.getTemplate(new ReportType(refType.getId()));	

		}
		Model model = null;
		try {
			model = new ReportManagerReportBuilder().buildReport(cr);			
			model.setTemplateName("New " + refType.getDisplayName());
		} catch (ReportBuilderException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return model;
	}

	@Override
	public VmeExportResponse exportReportToRSG(VMETypeIdentifier refType, Model model) {
		System.out.println(new ModelReader(model).toString());

		rsgReadClient = getRsgClient();	
		rsgWriteClient = getRsgSecureClient();	

		//Use the RSG client to get a template for the report whose type is the last token (i.e. the corresponding class' 'simple name') 
		//appearing in the VME model class name as stored in the 'type' metadata

		CompiledReport template = null;
		if (refType == VMETypeIdentifier.Vme) { 
			_log.info("getTemplate for VME Report");
			template = rsgReadClient.getTemplate(new ReportType(refType.getId()));
		}
		else {
			_log.info("getTemplate for Ref Report");
			template = rsgReadClient.getRefTemplate(new ReportType(refType.getId()));
		}
		CompiledReport toSend = null;
		try {
			toSend = new ReportManagerReportBuilder().extract(template, model);			
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			//Actual RSG client interface exposes different methods (publish / publishDelta etc.) that need to be updated
			ServiceResponse res = null;
			if (refType == VMETypeIdentifier.Vme) {
				_log.info("Exporting VME Report");
				res = rsgWriteClient.update(toSend);
			} 
			else {
				_log.info("Exporting Ref type= " + refType.getId());
				res = rsgWriteClient.updateRef(toSend);
			}
			return getClientResponse(res);
		} catch (RuntimeException ex) {
			ex.printStackTrace();
			return new VmeExportResponse(new VmeResponseEntry("RUNTIME_EXCEPTION", "Sorry, there was an error on the Server, please try again in few minutes or report an Issue."));
		}
	}

	@Override
	public VmeExportResponse deleteReportFromRSG(VMETypeIdentifier refType,	String idToDelete) {
		RsgWriteClient rsgClient = getRsgSecureClient();	

		try {
			ServiceResponse res = null;
			if (refType == VMETypeIdentifier.Vme) {
				_log.info("Deleting VME Report id = " + idToDelete);
				res = rsgClient.deleteById(new ReportType(refType.getId()), idToDelete);
			} 
			else {
				_log.info("Deleting VME Reference Report of Type " + refType + " having id = " + idToDelete);
				res = rsgClient.deleteReferenceById(new ReportType(refType.getId()), idToDelete);
			}
			return getClientResponse(res);
		} catch (RuntimeException ex) {
			ex.printStackTrace();
			return new VmeExportResponse(new VmeResponseEntry("RUNTIME_EXCEPTION", "Sorry, there was an error on the Server, we could not delete. Please try again in few minutes or report an Issue."));
		}
	}

	/**
	 * this method look for a ReportsStoreGateway WS available in the infrastructure
	 * @return true if an instance of the ReportsStoreGateway is available in the infrastructure
	 * @throws Exception 
	 */
	private boolean isReportsStoreGatewayAvailable(){
		String user =  PortalContext.getConfiguration().getCurrentUser(getThreadLocalRequest()).getUsername();
		if (user == null && isWithinPortal()) {
			_log.warn("Session expired, returning ReportsStoreGateway not available");
			return false;
		}
		String scope = PortalContext.getConfiguration().getCurrentScope(getThreadLocalRequest());
		_log.info("Looking for a running ReportsStoreGateway WS in " + scope);		
		ScopeProvider.instance.set(scope);
		SimpleQuery query = queryFor(ServiceEndpoint.class);
		query.addCondition("$resource/Profile/Category/string() eq 'Service'");
		query.addCondition("$resource/Profile/Name/string() eq 'ReportsStoreGateway'");

		DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
		List<ServiceEndpoint> list = client.submit(query);


		if (list.size() > 1) {
			_log.warn("Multiple ReportsStoreGateway Service Endpoints available in the scope, should be only one.");
			return false;
		}
		else if (list.size() == 1) {
			ServiceEndpoint se = list.get(0);
			String host = se.profile().runtime().hostedOn();
			AccessPoint ap = se.profile().accessPoints().iterator().next();
			String address =  ap.address();
			String password = "";
			String iMarineSkrURL = "";
			String vmeSkrURL = "";
			try {
				password = StringEncrypter.getEncrypter().decrypt(ap.password());
				for (Property property : ap.properties()) {
					if (property.name().compareTo(RSGAccessPoint.IMARINE_SECURE_KEYRING_NAME) == 0) 
						iMarineSkrURL = StringEncrypter.getEncrypter().decrypt(property.value());
					if (property.name().compareTo(RSGAccessPoint.VME_SECURE_KEYRING_NAME) == 0) 
						vmeSkrURL = StringEncrypter.getEncrypter().decrypt(property.value());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			RSGAccessPoint rsgAp = new RSGAccessPoint(host+address, iMarineSkrURL, vmeSkrURL, password);
			setRSGWSAddress(rsgAp);

			new RsgReadClient(rsgAp.getRestUrl());
			return true;
		}
		else return false;

	}

	private VmeExportResponse getClientResponse(ServiceResponse rsgResponse) {
		VmeExportResponse toReturn = new VmeExportResponse();
		for (ServiceResponseMessage entry : rsgResponse.getResponseMessageList()) {
			String entryCode = entry.getResponseCode() == null ? "no-code" : entry.getResponseCode().toString();
			String entryMessage = entry.getResponseMessage() == null ? "no response message" : entry.getResponseMessage();
			toReturn.getResponseMessageList().add(new VmeResponseEntry(entryCode, entryMessage));
		}
		toReturn.setGloballySucceded(rsgResponse.isGloballySucceeded());
		return toReturn;
	}




}
