package eu.dnetlib.enabling.ui.server;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.common.collect.Lists;

import eu.dnetlib.enabling.ui.common.beans.RepositoryStatusInfo;
import eu.dnetlib.enabling.ui.common.services.MyGwtException;
import eu.dnetlib.enabling.ui.server.auth.ExtendedPrincipal;
import eu.dnetlib.enabling.ui.server.auth.Principal;
import eu.dnetlib.miscutils.datetime.DateUtils;

/**
 * This servlet lets a provider view all and only its own registered repositories.
 * 
 * @author alessia
 * 
 */
public class HopeLookupServlet extends LookupServlet {

	private static final long serialVersionUID = 715039691508965386L;
	private static final Log log = LogFactory.getLog(HopeLookupServlet.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * List of users that can see all repositories.
	 */
	private List<String> superUsers = Lists.newArrayList("isti.cnr", "sandro.labruzzo", "michele artini", "claudio atzori");
	private String orgProperty = "o";

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.ui.server.LookupServlet#listRepositoriesForUser(java.lang.String, boolean)
	 */
	@Override
	public List<RepositoryStatusInfo> listRepositoriesForUser(String session, boolean withTransformator) throws MyGwtException {
		Principal principal = getSessionManager().getPrincipal(session);
		if (this.superUsers.contains(principal.getUserName()))
			return super.listRepositoriesForUser(session, withTransformator);
		else {
			if (principal instanceof ExtendedPrincipal) {
				ExtendedPrincipal extPrinc = (ExtendedPrincipal) principal;
				String cpName = extPrinc.getProperties().get(orgProperty);
				return this.listRepositoriesForCP(cpName);
			}
		}
		return Lists.newArrayList();
	}

	private String createCPFilter(String xqueryVar, String cpName) {
		return " where " + xqueryVar + "//REPOSITORY_INSTITUTION = '" + cpName + "' ";
	}

	private List<RepositoryStatusInfo> listRepositoriesForCP(String cpName) {
		log.info("listing repos for cp: " + cpName);
		List<RepositoryStatusInfo> repos = Lists.newArrayList();
		if (cpName == null)
			return repos;
		String filterRepoByCP = this.createCPFilter("$e", cpName);
		String xquery = "for $e in collection('/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType')"
				+ filterRepoByCP
				+ " return concat('0',' | ',$e//RESOURCE_IDENTIFIER/@value/string(),' | ',$e//OFFICIAL_NAME,' | ',$e//COUNTRY,' | ',$e//NUMBER_OF_OBJECTS,' | ',$e//LATITUDE,' | ',$e//LONGITUDE,' | ',$e//EXTRA_FIELDS/FIELD[./key='aggregatorName']/value,' | ',$e//DATE_OF_CREATION/@value,' | ')"
				+ ", "
				+ "for $e in collection('/db/DRIVER/PendingRepositoryResources/RepositoryServiceResourceType')"
				+ filterRepoByCP
				+ " return concat('1',' | ',$e//RESOURCE_IDENTIFIER/@value/string(),' | ',$e//OFFICIAL_NAME,' | ',$e//COUNTRY,' | ',$e//NUMBER_OF_OBJECTS,' | ',$e//LATITUDE,' | ',$e//LONGITUDE,' | ',$e//EXTRA_FIELDS/FIELD[./key='aggregatorName']/value,' | ',$e//DATE_OF_CREATION/@value,' | ')";

		List<String> elems = executeQuery(xquery);
		String xqueryIndexed = "for $x in collection('/db/DRIVER/ManagerServiceMapDSResources/ManagerServiceMapDSResourceType') return $x//INDEX/MDSTORE/@id/string()";

		Map<String, String> statusImages = null;
		filterRepoByCP = this.createCPFilter("$r", cpName);
		String xqueryStored = "for $r in collection('/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType')" + " let $harv := ( "
				+ "	for $h in collection('/db/DRIVER/HarvestingDSResources/HarvestingDSResourceType') "
				+ "	where $h//CONFIGURATION/REPOSITORY_SERVICE_IDENTIFIER = $r//RESOURCE_IDENTIFIER/@value "
				+ "	return concat($h//METADATA_FORMAT,'|',$h//DATA_SINK)  " + ") " + "let $tran := ( "
				+ "	for $h in collection('/db/DRIVER/TransformationDSResources/TransformationDSResourceType') "
				+ "	where $h//CONFIGURATION/REPOSITORY_SERVICE_IDENTIFIER = $r//RESOURCE_IDENTIFIER/@value "
				+ "	return concat($h//SINK_METADATA_FORMAT/@name,'|',$h//DATA_SINK) " + ") " + filterRepoByCP
				+ " return concat($r//RESOURCE_IDENTIFIER/@value,'|',$harv[1],'|', string-join($tran,'|')) ";

		statusImages = this.calculateStatusImages(executeQuery(xqueryStored), executeQuery(xqueryIndexed));
		for (String s : elems) {
			RepositoryStatusInfo repo = new RepositoryStatusInfo();
			String[] arr = s.split("\\|");
			if (arr[0].trim().equals("0"))
				repo.setPending(false);
			else
				repo.setPending(true);
			repo.setIdentifier(arr[1].trim());
			repo.setName(arr[2].trim());
			repo.setCountry(arr[3].trim());
			repo.setSize(Integer.parseInt(arr[4].trim()));
			repo.setLat(Float.parseFloat(arr[5].trim()));
			repo.setLng(Float.parseFloat(arr[6].trim()));
			repo.setAggregator(arr[7].trim());
			try {
				repo.setLastUpdate(new DateUtils().parse(arr[8].trim()));
			} catch (Exception e) {
				log.error("Error parsing date '" + arr[8].trim() + "' in repository profile: " + repo.getIdentifier());
				repo.setLastUpdate(new Date(0));
			}

			repo.setDeleted(false);
			if (repo.isPending())
				repo.setStatusImage(0 + getMdHarvFormat() + ".0" + getMdAggrFormat());
			else if (statusImages.containsKey(arr[1].trim()))
				repo.setStatusImage(statusImages.get(arr[1].trim()));
			else
				repo.setStatusImage(2 + getMdHarvFormat() + ".2" + getMdAggrFormat());
			repos.add(repo);
		}
		return repos;

	}

	private Map<String, String> calculateStatusImages(List<String> list, List<String> indexed) {
		Map<String, String> res = new HashMap<String, String>();

		for (String line : list) {
			String[] arr = line.split("\\|");
			String repoId = arr[0];
			log.debug("Processing image for repo: " + repoId);
			//boolean mdHarvFormatFound = false;
			boolean mdAggrFormatFound = false;
			String image = "";

			for (int i = 1; i < arr.length - 1; i += 2) {
				String mdFormat = arr[i];
				String mdId = arr[i + 1];
				//				if (mdFormat.equals(getMdHarvFormat()))
				//					mdHarvFormatFound = true;
				if (mdFormat.equals(getMdAggrFormat()))
					mdAggrFormatFound = true;
				if (mdId.startsWith("dnet://MDStoreDS/")) {
					mdId = mdId.substring("dnet://MDStoreDS/".length(), mdId.indexOf("?"));
				}
				log.debug(" - mdID : " + mdId);
				String stHarv = indexed.contains(mdId) ? "1" : "2";
				image += stHarv + mdFormat + ".";
			}

			//			if (!mdHarvFormatFound) {
			//				image += "0" + getMdHarvFormat() + ".";
			//			}
			if (!mdAggrFormatFound) {
				image += "0" + getMdAggrFormat() + ".";
			}

			if (image.endsWith("."))
				image = image.substring(0, image.length() - 1);
			log.debug(" - image : " + image);
			res.put(repoId, image);
		}

		return res;
	}

	public List<String> getSuperUsers() {
		return superUsers;
	}

	public void setSuperUsers(List<String> superUsers) {
		this.superUsers = superUsers;
	}

	public String getOrgProperty() {
		return orgProperty;
	}

	public void setOrgProperty(String orgProperty) {
		this.orgProperty = orgProperty;
	}

}
