package eu.dnetlib.enabling.ui.server;

import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.ui.common.beans.MDStoreInfo;
import eu.dnetlib.enabling.ui.common.beans.RepositoryDetailsInfo;
import eu.dnetlib.enabling.ui.common.beans.RepositoryMDStoreInfo;
import eu.dnetlib.enabling.ui.common.services.MyGwtException;
import eu.dnetlib.miscutils.datetime.DateUtils;

public class Common {
	private static final Log log = LogFactory.getLog(Common.class); // NOPMD by marko on 11/24/08 5:02 PM

	public static MDStoreInfo getMDStoreInfo(String id, ISLookUpService lu) throws MyGwtException {

		SAXReader xmlParser = new SAXReader();
		MDStoreInfo info = new MDStoreInfo();

		try {

			String prof = lu.getResourceProfile(id);
			Document doc = xmlParser.read(new StringReader(prof));

			String mdName = doc.valueOf("//CONFIGURATION/METADATA_FORMAT");
			int mdSize = Integer.parseInt(doc.valueOf("//STATUS/NUMBER_OF_RECORDS"));
			String mdLastDate = doc.valueOf("//STATUS/LAST_STORAGE_DATE");

			URL url = new URL(doc.valueOf("//RESOURCE_URI/@value"));

			info.setIdentifier(id);
			info.setAddress(url.getHost() + ":" + url.getPort());
			info.setMdName(mdName);
			info.setSize(mdSize);
			info.setLastDate(mdLastDate);

			String idIndexQuery = "for $x in collection('/db/DRIVER/ManagerServiceMapDSResources/ManagerServiceMapDSResourceType') return $x//INDEX[./MDSTORE/@id/string() = '"
				+ id + "']/@id/string()";

			// prepare in case of failure
			info.setIndex("");
			info.setIndexSize(0);
			info.setIndexUpdated(false);

			try {
				String idIndex = lu.getResourceProfileByQuery(idIndexQuery);
				String indexProf = lu.getResourceProfile(idIndex);

				Document docIndex = xmlParser.read(new StringReader(indexProf));
				int indexSize = 0;
				String size = docIndex.valueOf("//CONFIGURATION/INDEX_SIZE");
				if (size != null) {
					indexSize = Integer.parseInt(size);
				}
				Date idxDate = (new DateUtils()).parse(docIndex.valueOf("//STATUS/INDEX_LAST_UPDATE"));

				info.setIndex(idIndex);
				info.setIndexSize(indexSize);
				if(idxDate != null)
					info.setIndexUpdated(idxDate.after((new DateUtils()).parse(mdLastDate)) && (indexSize <= mdSize));
			} catch (ISLookUpDocumentNotFoundException e) {
				if (log.isDebugEnabled())
					log.debug("index for " + mdName + " store " + id + " not found");
			} catch (Exception e) {
				log.error("cannot fetch index details for " + id, e);
			}

		} catch (Exception e) {
			log.error("Failed MDStoreInfo: " + id, e);
			throw (new MyGwtException(e.getMessage(), "Retry later"));
		}
		return info;
	}

	public static RepositoryDetailsInfo getRepoDetails(String id, boolean withTransformator, ISLookUpService lu) throws MyGwtException {
		RepositoryDetailsInfo info = new RepositoryDetailsInfo();
		// prepare in case of failure
		info.setAggrURL("");
		info.setAggrName("");
		info.setHiid("");
		info.setFormats(new ArrayList<RepositoryMDStoreInfo>());

		SAXReader xmlParser = new SAXReader();

		try {
			String prof = lu.getResourceProfile(id);
			Document doc = xmlParser.read(new StringReader(prof));
			info.setStatus("-");
			info.setIdentifier(id);
			info.setName(doc.valueOf("//OFFICIAL_NAME"));
			info.setEnglishName(doc.valueOf("//ENGLISH_NAME"));
			info.setInstitution(doc.valueOf("//REPOSITORY_INSTITUTION"));
			info.setCountry(doc.valueOf("//COUNTRY"));
			info.setSize(Integer.parseInt(doc.valueOf("//NUMBER_OF_OBJECTS")));
			info.setLat(Float.parseFloat(doc.valueOf("//LATITUDE")));
			info.setLng(Float.parseFloat(doc.valueOf("//LONGITUDE")));
			info.setTimezone(Float.parseFloat(doc.valueOf("//TIMEZONE")));
			//			repo.setStatusImage(calculateStatusImage(id));
			info.setUrl(doc.valueOf("//REPOSITORY_WEBPAGE"));
			info.setIcon(doc.valueOf("//ICON_URI"));
			info.setEmail(doc.valueOf("//ADMIN_INFO"));
			
			for (Object o : doc.selectNodes("//EXTRA_FIELDS/FIELD")) {
				String key = ((Element) o).valueOf("./key");
				String value = ((Element) o).valueOf("./value");
				info.getExtraFields().put(key, value);
			}
			
			info.setEmail(doc.valueOf("//ADMIN_INFO"));
			info.setPlatform(doc.valueOf("//TYPOLOGY"));
			info.setIcon(doc.valueOf("//ICON_URI"));
			info.setLastDate(doc.valueOf("//STATUS/LAST_STORAGE_DATE"));
			
			Element ifcHarv = (Element) doc.selectSingleNode("//INTERFACE[.//FORMAT != 'fulltext']");
			info.setBaseUrl(ifcHarv.valueOf("./BASE_URL"));
			info.setHarvProtocol(ifcHarv.valueOf("./ACCESS_PROTOCOL"));
			info.setHarvMetadataFormat(ifcHarv.valueOf("./FORMATS/FORMAT"));
					
			List<String> sets = new ArrayList<String>();
			for (Object o : ifcHarv.selectNodes("./SETS/SET")) {
				sets.add(((Element) o).getTextTrim());
			}
			info.setHarvSets(sets);
			
			info.setHarvUsername(ifcHarv.valueOf("./ACCESS_PROTOCOL/@username"));
			info.setHarvPassword(ifcHarv.valueOf("./ACCESS_PROTOCOL/@password"));
			info.setHarvFilter(ifcHarv.valueOf("./ACCESS_PROTOCOL/@filter"));
			
			Element fulltextHarv = (Element) doc.selectSingleNode("//INTERFACE[.//FORMAT = 'fulltext']");
			if (fulltextHarv != null) {
				info.setFulltextUrl     (fulltextHarv.valueOf("./BASE_URL"));
				info.setFulltextProtocol(fulltextHarv.valueOf("./ACCESS_PROTOCOL"));
				info.setFulltextUsername(fulltextHarv.valueOf("./ACCESS_PROTOCOL/@username"));
				info.setFulltextPassword(fulltextHarv.valueOf("./ACCESS_PROTOCOL/@password"));
				info.setFulltextFilter  (fulltextHarv.valueOf("./ACCESS_PROTOCOL/@filter"));
			}
		} catch (Exception e) {
			log.error("Invalid Repository profile: " + id , e);
			throw(new MyGwtException());
		}



		if (withTransformator) {
			List<RepositoryMDStoreInfo> mdf = new ArrayList<RepositoryMDStoreInfo>();
			
			try {
				String prof = lu.getResourceProfileByQuery("for $x in collection('/db/DRIVER/HarvestingDSResources/HarvestingDSResourceType') where $x//CONFIGURATION/REPOSITORY_SERVICE_IDENTIFIER/text() = '" + id + "' return $x");
				Document doc = xmlParser.read(new StringReader(prof));
				String hiid = doc.valueOf("//RESOURCE_IDENTIFIER/@value");
				info.setHiid(hiid);
				
				RepositoryMDStoreInfo mdInfo = new RepositoryMDStoreInfo();
				mdInfo.setMdName(doc.valueOf("//METADATA_FORMAT"));
				
				String mdid = doc.valueOf("//DATA_SINK");
				mdid = mdid.substring("dnet://MDStoreDS/".length(), mdid.indexOf("?"));
				mdInfo.setMdstoreId(mdid);

				mdInfo.setType("HARV");
				mdInfo.setSize(0);
				mdf.add(mdInfo);

				String hmsID = doc.valueOf("//HARVESTING_MANAGER_SERVICE_IDENTIFIER");
				if (hmsID != null && hmsID.length() > 0) {
					try {
						Document docHMS = xmlParser.read(new StringReader(lu.getResourceProfile(hmsID)));
						info.setHarvestingURL(docHMS.valueOf("//SERVICE_PROPERTIES/PROPERTY[@key='url']/@value") + "?id=" + hiid);
					} catch (Exception e) {
						log.error("Harvesting manager service profile not found", e);
					}
				}
			} catch (Exception e) {
				log.error("HarvestingDSResources not found for repo " + id);
			}

			try {
				String prof = lu.getResourceProfileByQuery("for $x in collection('/db/DRIVER/TransformationDSResources/TransformationDSResourceType') where $x//CONFIGURATION/REPOSITORY_SERVICE_IDENTIFIER/text() = '" + id + "' return $x");
				Document doc = xmlParser.read(new StringReader(prof));
				String tid = doc.valueOf("//RESOURCE_IDENTIFIER/@value");
				info.setTransformatorId(tid);
				RepositoryMDStoreInfo mdInfo = new RepositoryMDStoreInfo();
				mdInfo.setMdName(doc.valueOf("//SINK_METADATA_FORMAT/@name"));
			
				String mdid = doc.valueOf("//DATA_SINK");
				mdid = mdid.substring("dnet://MDStoreDS/".length(), mdid.indexOf("?"));
				mdInfo.setMdstoreId(mdid);

				mdInfo.setType("TRANS");
				mdInfo.setSize(0);
				mdf.add(mdInfo);

				
				String tsID = doc.valueOf("//TRANSFORMATION_MANAGER_SERVICE_IDENTIFIER");
				if (tsID != null && tsID.length() > 0) {
					try {
						Document docTS = xmlParser.read(new StringReader(lu.getResourceProfile(tsID)));
						info.setTransformatorUrl(docTS.valueOf("//SERVICE_PROPERTIES/PROPERTY[@key='url']/@value") + "?id=" + tid);
					} catch (Exception e) {
						log.error("Harvesting manager service profile not found", e);
					}
				}
			} catch (Exception e) {
				log.error("TransformationDSResources not found for repo " + id);
			}
			info.setFormats(mdf);


		} else {

			try {
				String prof = lu.getResourceProfileByQuery("for $x in collection('/db/DRIVER/HarvestingInstanceDSResources/HarvestingInstanceDSResourceType') where $x//CONFIGURATION/REPOSITORY_SERVICE_IDENTIFIER/text() = '" + id + "' return $x");

				Document doc = xmlParser.read(new StringReader(prof));
				String aggrID = doc.valueOf("//AGGREGATOR_SERVICE_IDENTIFIER");
				info.setHiid(doc.valueOf("//RESOURCE_IDENTIFIER/@value"));

				List<RepositoryMDStoreInfo> mdf = new ArrayList<RepositoryMDStoreInfo>();
				for (Object unit : doc.selectNodes("//HARVESTING_UNITS/HARVESTING_UNIT")) {
					RepositoryMDStoreInfo mdInfo = _mdInfoFromAggrUnit((Element) unit, "HARV");
					mdf.add(mdInfo);
				}

				for (Object unit : doc.selectNodes("//AGGREGATING_UNITS/AGGREGATING_UNIT")) {
					RepositoryMDStoreInfo mdInfo = _mdInfoFromAggrUnit((Element) unit, "AGGR");
					mdf.add(mdInfo);
				}

				for (Object unit : doc.selectNodes("//REPLICA_UNITS/REPLICA_UNIT")) {
					RepositoryMDStoreInfo mdInfo = _mdInfoFromAggrUnit((Element) unit, "REPL");
					mdf.add(mdInfo);
				}
				info.setFormats(mdf);

				if (aggrID.length() > 0) {
					try {
						Document doc2 = xmlParser.read(new StringReader(lu.getResourceProfile(aggrID)));
						info.setAggrURL(doc2.valueOf("//SERVICE_PROPERTIES/PROPERTY[@key='url']/@value"));
						info.setAggrName(doc2.valueOf("//SERVICE_PROPERTIES/PROPERTY[@key='name']/@value"));
					} catch (Exception e) {
						log.error("Aggregator profile not found", e);
					}
				}
			} catch (Exception e) {
				log.error("Problem (missing HI?) obtaining info of repo " + id, e);
			}
		}


		return info;
	}

	private static RepositoryMDStoreInfo _mdInfoFromAggrUnit(Element unit, String type) {
		RepositoryMDStoreInfo mdInfo = new RepositoryMDStoreInfo();
		mdInfo.setMdName(unit.valueOf("./METADATA_FORMAT"));
		mdInfo.setMdstoreId(unit.valueOf("./MDSTORE_DS_IDENTIFIER"));
		mdInfo.setType(type);
		mdInfo.setSize(0);
		if (type.equals("HARV"))      mdInfo.setLastDate(unit.valueOf("./LAST_HARVESTING_DATE"));
		else if (type.equals("AGGR")) mdInfo.setLastDate(unit.valueOf("./LAST_AGGREGATING_DATE"));
		else if (type.equals("REPL")) mdInfo.setLastDate(unit.valueOf("./LAST_REPLICA_DATE"));
		return mdInfo;
	}
}
