package eu.dnetlib.repos;

import eu.dnetlib.api.data.DatasourceManagerService;
import eu.dnetlib.api.data.DatasourceManagerServiceException;
import eu.dnetlib.domain.data.Repository;
import eu.dnetlib.domain.data.RepositoryInterface;
import gr.uoa.di.driver.util.ServiceLocator;
import org.apache.log4j.Logger;

import java.util.*;

public class RepoApiDmsImpl implements RepoApi {
    private static Logger logger = Logger.getLogger(RepoApiDmsImpl.class);
    private final String[] filterKeys = {"openaire____::opendoar", "openaire____::re3data", "infrastruct_::openaire"};

    private ServiceLocator<DatasourceManagerService> dmService = null;

    @Override
    public Repository getRepository(String id) throws Exception {
        return this.getRepository(null, id);
    }

    @Override
    public Repository getRepository(String officialName, String id) throws Exception {
        logger.info("getting repository with name " + officialName + " and id: " + id + " from dms");
        Repository retRepo = null;
        try {
            retRepo = dmService.getService().getDatasource(id);
        } catch (DatasourceManagerServiceException e) {
            logger.error("Error getting repository with name " + officialName + " and id: " + id + " from dms", e);
        }
        return retRepo;
    }

    @Override
    public void getRepositoryStats(Repository repo) throws Exception {
        logger.info("getting repository stats for : " + repo.getOfficialName() + " from dms");

        try {
            dmService.getService().findNextScheduledExecution(repo.getId(), repo.getInterfaces().get(0).getId());

        } catch (DatasourceManagerServiceException e) {
            logger.error("Error getting repo stats for : " + repo.getOfficialName() + " from openaire db", e);
        }
    }

    @Override
    public String getListLatestUpdate(String mode) throws Exception {
        String date = null;
        try {
            logger.info("getting last collection date for " + mode);

            date = dmService.getService().getDatasource("openaire____::" + mode).getInterfaces().get(0).getExtraFields().get("last_collection_date");
            logger.debug("last collection date for opendoar: " + date);

        } catch (DatasourceManagerServiceException e) {
            logger.error("Error getting last update date", e);
        }
        return date;
    }

    @Override
    public String getNextScheduledExecution(String mode) throws Exception {
        String date = null;
        try {
            date = dmService.getService().getDatasource("openaire____::" + mode).getInterfaces().get(0).getExtraFields().get("last_collection_date");
            logger.debug("last collection date for opendoar: " + date);

//				Date date1 = dmService.getService().findNextScheduledExecution("openaire____::opendoar", "api_________::opendoar::0");
            Date date1 = dmService.getService().findNextScheduledExecution("opendoar____::2367", "api_________::opendoar____::2367::0");

            logger.debug("next scheduled for opendoar: " + date1);

        } catch (DatasourceManagerServiceException e) {
            logger.error("Error getting repo stats for opendoar", e);
        }
        return date;
    }

    @Override
    public String storeRepository(Repository repo, String datatype, List<RepositoryInterface> interfacesToRegister) throws Exception {
        String retMessage = null;
        logger.info("storing " + datatype + " repository with id: " + repo.getId());
        try {
            java.util.Date utilDate = new java.util.Date();
            java.sql.Timestamp date = new java.sql.Timestamp(utilDate.getTime());

            if (datatype.equalsIgnoreCase("opendoar") || datatype.equalsIgnoreCase("re3data")) {

                String updateQuery = "UPDATE datasources SET englishname = '" + repo.getEnglishName() + "'," +
                        " logourl = '" + repo.getLogoUrl() + "'," +
                        " timezone = '" + repo.getTimezone() + "'," +
                        " registeredby = '" + repo.getRegisteredBy() + "'," +
                        " activationid = '" + repo.getActivationId() + "'," +
                        " contactemail = '" + repo.getContactEmail() + "'," +
                        " datasourceclass = '" + repo.getDatasourceClass() + "'" +
                        " WHERE id = '" + repo.getId() + "'";

                if (dmService.getService().updateSQL(repo.getId(), updateQuery, false))
                    logger.debug("updated successfully");
                else
                    logger.error("error while updating: " + updateQuery);

            } else if (datatype.equalsIgnoreCase("journal") || datatype.equalsIgnoreCase("aggregator")) {

                logger.debug("looking if " + datatype + " " + repo.getOfficialName() + " is already in datasources");
                if (dmService.getService().getDatasource(repo.getId()) != null) {
                    retMessage = datatype + " '" + repo.getOfficialName() + "' is already in datasources.";
                    repo.getInterfaces().clear();
                    logger.debug(retMessage);
                } else {
                    logger.debug(datatype + " " + repo.getOfficialName() + " is not in datasources. Inserting..");

                    repo.setDateOfCollection(date);
                    repo.setAggregator("OPENAIRE");
                    try {
                        if (dmService.getService().addDatasource(repo))
                            logger.debug("inserted successfully");
                        else
                            logger.error("error while inserting");
                    } catch (DatasourceManagerServiceException e) {
                        logger.error("error while inserting" + e);
                    }
                }
            }
            logger.debug("Inserting Interfaces");
            for (RepositoryInterface iFace : repo.getInterfaces()) {
                if (!iFace.getBaseUrl().isEmpty() && !iFace.getDesiredCompatibilityLevel().isEmpty()) {
                    if (iFace.getId() != null && !iFace.getId().isEmpty()) {
                        logger.debug("updating iface..");
                        dmService.getService().updateBaseUrl(repo.getId(), iFace.getId(), iFace.getBaseUrl());
                        if (!iFace.getAccessSet().isEmpty()) {
                            logger.debug("set not empty: " + iFace.getAccessSet());
                            dmService.getService().updateAccessParam(repo.getId(), iFace.getId(), "set", iFace.getAccessSet(), false);
                        } else
                            dmService.getService().deleteAccessParamOrExtraField(repo.getId(), iFace.getId(), "set");

                        dmService.getService().updateContentDescription(repo.getId(), iFace.getId(), "metadata");
                        if (datatype.equals("re3data")) {
                            dmService.getService().updateAccessParam(repo.getId(), iFace.getId(), "format", "oai_datacite", false);
                            iFace.setAccessFormat("oai_datacite");
                        } else {
                            dmService.getService().updateAccessParam(repo.getId(), iFace.getId(), "format", "oai_dc", false);
                            iFace.setAccessFormat("oai_dc");
                        }

                        logger.debug("updated successfully");
                    } else {
                        logger.debug("adding new iface..");
                        iFace.setContentDescription("metadata");
                        iFace.setCompliance("UNKNOWN");
                        if (datatype.equals("re3data"))
                            iFace.setAccessFormat("oai_datacite");
                        else
                            iFace.setAccessFormat("oai_dc");
                        if (repo.getDatasourceClass() != null && !repo.getDatasourceClass().isEmpty())
                            iFace.setTypology(repo.getDatasourceClass());
                        else {
                            if (datatype.equalsIgnoreCase("journal"))
                                iFace.setTypology("pubsrepository::journal");
                            else if (datatype.equalsIgnoreCase("aggregator"))
                                iFace.setTypology("aggregator::pubsrepository::unknown");
                            else if (datatype.equalsIgnoreCase("opendoar"))
                                iFace.setTypology("pubsrepository::unknown");
                            else if (datatype.equalsIgnoreCase("re3data"))
                                iFace.setTypology("datarepository::unknown");
                        }
                        iFace.setRemovable(true);
                        iFace.setAccessProtocol("oai");
                        iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
                        iFace.setId("api_________::" + repo.getId() + "::" + UUID.randomUUID().toString().substring(0, 8));
                        if (iFace.getAccessSet().isEmpty()) {
                            logger.debug("set is empty: " + iFace.getAccessSet());
                            iFace.removeAccessSet();
                        }
                        logger.debug("new ifaceId :" + iFace.getId());
                        if (dmService.getService().addInterface(repo.getId(), iFace))
                            logger.debug("added successfully");
                        else
                            logger.error("error while adding");
                    }
                    interfacesToRegister.add(iFace);
                }
            }
        } catch (Exception e) {
            logger.error("Error storing repo " + repo.getOfficialName() + " in dms", e);
            throw e;
        }
        logger.debug("Finished storing " + datatype + " repository with id: " + repo.getId());
        return retMessage;
    }

    @Override
    public String editRepository(Repository repo, String officialNameOld, String idOld, String datatype) throws Exception {
        throw new UnsupportedOperationException();
    }

    public List<Repository> getRepositories(String collectedFrom) throws Exception {
        List<Repository> repoList = new ArrayList<Repository>();
        try {
            logger.info("getting repos from dms with collected from value: " + collectedFrom);

            repoList = dmService.getService().listDatasourcesUsingFilter(null, null, null, collectedFrom);

        } catch (DatasourceManagerServiceException e) {
            logger.error("Error getting repos from dms with collected from value: " + collectedFrom, e);
            throw e;
        }
        return repoList;
    }

    public Map<String, Repository> getRepositoriesAsMap(String collectedFrom) throws Exception {
        List<Repository> repoList = new ArrayList<Repository>();
        Map<String, Repository> repoMap = new HashMap<String, Repository>();
        try {
            logger.info("getting repos from dms with collected from value: " + collectedFrom);

            repoList = dmService.getService().listDatasourcesUsingFilter(null, null, null, collectedFrom);
            for (Repository repo : repoList) {
                repoMap.put(repo.getId(), repo);
            }

        } catch (DatasourceManagerServiceException e) {
            logger.error("Error getting repos from dms with collected from value: " + collectedFrom, e);
            throw e;
        }
        return repoMap;
    }

    @Override
    public List<Map<String, String>> getRegisteredReposByOthers(String user_mail) {
        List<Map<String, String>> res = new ArrayList<Map<String, String>>();

        try {
            logger.info("getting repos by others for user : " + user_mail);

            res = this.getReposAsMap(user_mail, true);
        } catch (Exception e) {
            logger.error("Error getting repos by others for user : " + user_mail, e);

        }
        return res;
    }

    @Override
    public List<Map<String, String>> getRepositoriesOfUser(String user_mail) throws Exception {
        logger.info("getting repos for user : " + user_mail);
        return this.getReposAsMap(user_mail, false);
    }

    private List<Map<String, String>> getReposAsMap(String user_mail, Boolean isAdmin) throws Exception {

        logger.info("getting repos as map for user: " + user_mail);
        List<Map<String, String>> res = new ArrayList<Map<String, String>>();
        try {
            for (Repository repo : this.getRepositoriesOfUser(user_mail, isAdmin)) {
                Map<String, String> rep = new HashMap<String, String>();
                rep.put("name", repo.getOfficialName());
                rep.put("id", repo.getId());
                rep.put("url", repo.getWebsiteUrl());
                rep.put("mode", repo.getDatasourceType());
                rep.put("registered", repo.isRegistered() ? "yes" : "no");
                res.add(rep);
            }
        } catch (Exception e) {
            logger.error("getting repos as map for user: " + user_mail, e);
        }
        return res;
    }

    @SuppressWarnings("unchecked")
    public TreeMap<String, List<Map<String, String>>> getRepositoriesByCountry(String collectedFrom) throws Exception {
        List<Repository> repoList = new ArrayList<Repository>();
        TreeMap<String, List<Map<String, String>>> res = new TreeMap<String, List<Map<String, String>>>();

        try {
            logger.info("getting repos by country from dms with key: " + collectedFrom);

            repoList = this.getRepositories(RepoTools.getFilterKey(collectedFrom));

            res = RepoTools.splitReposByCountry(repoList);

        } catch (Exception e) {
            logger.error("Error getting repositories from dms with key: " + collectedFrom, e);
            throw e;
        }
        return res;
    }

    @Override
    public Map<String, List<Repository>> getRepositoriesPerCountry(String collectedFrom) throws Exception {
        List<Repository> repoList;
        Map<String, List<Repository>> res = new TreeMap<String, List<Repository>>();

        try {
            logger.info("getting repos by country from dms with key: " + collectedFrom);

            repoList = this.getRepositories(RepoTools.getFilterKey(collectedFrom));

            res = RepoTools.splitReposPerCountry(repoList);

        } catch (Exception e) {
            logger.error("Error getting repositories from dms with key: " + collectedFrom, e);
            throw e;
        }
        return res;
    }

    @Override
    public List<Repository> getRepositoriesOfCountry(String collectedFrom, String country) throws Exception {
        try {
            logger.info("getting repos for country " + country + " from dms with key: " + collectedFrom);
            return this.getRepositoriesPerCountry(collectedFrom).get(country);
        } catch (Exception e) {
            logger.error("Error getting repos for country " + country + " from dms with key: " + collectedFrom, e);
            throw e;
        }
    }

    @Override
    public Map<String, String> getRepoCompatibility(String officialName, String datasourceId) throws Exception {
        Map<String, String> compMap = null;

        Repository repo = dmService.getService().getDatasource(datasourceId);
        try {
            logger.debug("getting repository " + officialName + " compatibility from dms");

            compMap = new HashMap<String, String>();
            if (repo.getInterfaces().size() > 0) {
                for (RepositoryInterface iFace : repo.getInterfaces()) {
                    compMap.put(iFace.getCompliance(), iFace.getAccessSet());
                    if (iFace.getCompliance().equalsIgnoreCase("openaire2.0")) {
                        compMap.put("openaire2.0_data", "openaire_data");
                    }
                }
            }
        } catch (Exception e) {
            logger.error("Error getting repo " + officialName + " compatibility from dms", e);
            throw e;
        }

        return compMap;
    }

    @Override
    public List<Repository> getReposByIds(List<String> datasourceIds) throws Exception {
        List<Repository> retRepos = new ArrayList<Repository>();
        try {
            logger.info("getting repos by ids from dms");
            for (String datasourceId : datasourceIds) {
                retRepos.add(this.getRepository(datasourceId));
            }
        } catch (Exception e) {
            logger.error("error getting repos by ids from dms", e);
        }
        return retRepos;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Repository> getRepositoriesOfUser(String user_mail, Boolean repoAdmin) throws Exception {
        List<Repository> retRepos = new ArrayList<Repository>();
        try {
            if (!repoAdmin) {
                logger.info("getting repositories registered by user: " + user_mail + " from dms");
                for (String filterKey : filterKeys) {
                    List<Repository> repoList = this.getRepositories(filterKey);
                    for (Repository rep : repoList) {
                        if (rep.getRegisteredBy().equalsIgnoreCase(user_mail) || rep.getContactEmail().equalsIgnoreCase(user_mail)) {
                            retRepos.add(rep);
                        }
                    }
                }
            } else {
                logger.debug("getting journal /agreg  registered by others  from dms");
                List<Repository> repoList = this.getRepositories("infrastruct_::openaire");
                for (Repository rep : repoList) {
                    if (!rep.getRegisteredBy().equalsIgnoreCase(user_mail) && !rep.getContactEmail().equalsIgnoreCase(user_mail)) {
                        retRepos.add(rep);
                    }
                }
            }

        } catch (Exception e) {
            logger.error("error getting repositories registered by user: " + user_mail + " from dms", e);
        }
        return retRepos;
    }

    @Override
    public boolean repoIsCompliant(String officialName) throws Exception {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean updateRepositoryInterfaceCompliance(String officialName,
                                                       String datasourceId, String interfaceId, String desiredCompliance, String set, String baseUrl, String oldId)
            throws Exception {
        boolean ret = true;
        try {
            if (desiredCompliance.equalsIgnoreCase("openaire2.0_data"))
                desiredCompliance = "openaire2.0";
            logger.info("updating repository " + officialName + " compliance to : " + desiredCompliance);
            if (oldId == null) {
                dmService.getService().updateLevelOfCompliance(datasourceId, interfaceId, desiredCompliance);
            } else {
                logger.debug("Checking if old interface should be updated");
                if (!desiredCompliance.equalsIgnoreCase("UNKNOWN") && (!desiredCompliance.equalsIgnoreCase("notCompatible"))) {
                    logger.debug("updating old interface with new set/url");
                    dmService.getService().updateBaseUrl(datasourceId, oldId, baseUrl);
                    if (set.equalsIgnoreCase("none"))
                        dmService.getService().deleteAccessParamOrExtraField(datasourceId, oldId, "set");
                    else
                        dmService.getService().updateAccessParam(datasourceId, oldId, "set", set, false);
                    logger.debug("deleting new interface");
                    dmService.getService().deleteInterface(datasourceId, interfaceId);

                }
                logger.debug("updating repository " + officialName + " compliance to : " + desiredCompliance);
            }
            java.util.Date utilDate = new java.util.Date();
            java.sql.Timestamp date = new java.sql.Timestamp(utilDate.getTime());

            String updateQuery = "UPDATE datasources SET activationid = " + null + "," +
                    " dateofvalidation = '" + date + "'" +
                    " WHERE id = '" + datasourceId + "'";

            if (dmService.getService().updateSQL(datasourceId, updateQuery, false))
                logger.debug("updated successfully");
            else
                logger.error("error while updating: " + updateQuery);

        } catch (Exception e) {
            logger.error("error connecting to dms to set a repo interface as openaire compliant " + officialName, e);
            ret = false;
            throw e;
        }
        return ret;
    }

    @Override
    public boolean insertPubFileInterface(String dsId, RepositoryInterface iFace)
            throws Exception {
        try {

            logger.info("storing pdf interface for repository: " + dsId);
            dmService.getService().addInterface(dsId, iFace);
            return true;
        } catch (Exception e) {
            logger.error("error storing pdf interface for repository: " + dsId, e);
            return false;
        }

    }

    @Override
    public boolean updatePubFileInterface(String dsId, RepositoryInterface iFace)
            throws Exception {
        try {

            logger.info("updating pdf interface for repository: " + dsId);
            dmService.getService().deleteInterface(dsId, iFace.getId());
            dmService.getService().addInterface(dsId, iFace);
            return true;
        } catch (Exception e) {
            logger.error("error updating pdf interface for repository: " + dsId, e);
            return false;
        }
    }

    @Override
    public List<String> getUrlsOfRepos(String user_mail, Boolean repoAdmin) throws Exception {
        List<String> urls = new ArrayList<String>();
        try {
            logger.info("getting url from repositories registered by user: " + user_mail + " from dms");
            for (Repository repo : this.getRepositoriesOfUser(user_mail, repoAdmin)) {
                repo = this.getRepository(repo.getOfficialName(), repo.getId());
                logger.debug("repo: " + repo.getOfficialName());
//				logger.debug("#interfaces: " + repo.getInterfaces().size());
                for (RepositoryInterface iFace : repo.getInterfaces()) {
//					logger.debug("url: " + iFace.getBaseUrl() );
                    if (iFace.getContentDescription().equalsIgnoreCase("metadata")) {
                        if (iFace.getBaseUrl() != null && !iFace.getBaseUrl().isEmpty() && !urls.contains(iFace.getBaseUrl()) && iFace.getAccessProtocol().equalsIgnoreCase("oai"))
                            urls.add(iFace.getBaseUrl());
                    }
                }
            }
        } catch (Exception e) {
            logger.error("error getting url from repositories registered by user: " + user_mail + " from dms", e);
            throw e;
        }
        return urls;
    }

    @Override
    public String updateRepositoryInformation(Repository repo) throws Exception {
        try {
            logger.info("updating repository information");
            String updateQuery = "UPDATE datasources SET englishname = '" + repo.getEnglishName() + "'," +
                    " logourl = '" + repo.getLogoUrl() + "'," +
                    " timezone = '" + repo.getTimezone() + "'," +
                    " registeredby = '" + repo.getRegisteredBy() + "'," +
                    " contactemail = '" + repo.getContactEmail() + "'," +
                    " datasourceclass = '" + repo.getDatasourceClass() + "'" +
                    " WHERE id = '" + repo.getId() + "'";

            if (dmService.getService().updateSQL(repo.getId(), updateQuery, false)) {
                logger.debug("updated successfully");
                return "The information about your repository is successfully updated.";
            } else {
                logger.error("error while updating: " + updateQuery);
                return "The information of your repository couldn't be updated. Please try again.";
            }
        } catch (Exception e) {
            logger.error("error updating repository information", e);
            throw e;
        }

    }

    @Override
    public String deleteRepositoryInterfaces(String dsId, List<RepositoryInterface> interfaces) throws Exception {
        String retMessage = "";
        try {
            logger.info("deleting repository interfaces");
            int countSelected = 0;
            int countRemoved = 0;
            for (RepositoryInterface iFace : interfaces) {
                if (iFace.isDeleteApi())
                    countSelected++;
            }
            if (countSelected == 0)
                return "None interface was selected.";
            if (countSelected == interfaces.size())
                return "You cannot delete all interfaces! There must be at least one left.";

            for (RepositoryInterface iFace : interfaces) {
                logger.debug("delete API: " + iFace.isDeleteApi() + "--" + "removable API: " + iFace.isRemovable());
                if (iFace.isDeleteApi()) {
                    if (iFace.isRemovable()) {
                        if (dmService.getService().deleteInterface(dsId, iFace.getId())) {
                            logger.debug("iface deleted: " + iFace.getId());
                            countRemoved++;
                        } else {
                            logger.error("error while deleting iFace: " + iFace.getId());
                            retMessage += "Interface for url/set: " + iFace.getBaseUrl() + " / " + iFace.getAccessSet() + " couldn't be delete. Please try again.<br>";
                        }
                    } else {
                        retMessage += "Interface for url/set: " + iFace.getBaseUrl() + " / " + iFace.getAccessSet() + " couldn't be deleted because it is the one registered in OpenDoar. <br>";
                    }
                }
            }
            retMessage += "You have successfully deleted " + countRemoved + " interface(s).";
        } catch (Exception e) {
            logger.error("error deleting repository interfaces", e);
            throw e;
        }
        return retMessage;
    }

    @Override
    public void deleteRepositoryInterfacesWithoutChecks(String dsId, List<RepositoryInterface> interfaces, String datatype) throws Exception {
        try {
            logger.info("deleting repository interfaces without checks");
            for (RepositoryInterface iFace : interfaces) {
                logger.info("deleting repository interface with url/set/id: " + iFace.getBaseUrl() + "/" + iFace.getAccessSet() + "/" + iFace.getId());
                if (dmService.getService().deleteInterface(dsId, iFace.getId())) {
                    logger.debug("iface deleted: " + iFace.getId());
                } else {
                    logger.error("error while deleting iFace: " + iFace.getId());
                    throw new Exception("error on dms while deleting iFace: " + iFace.getId());
                }
            }
        } catch (Exception e) {
            logger.error("error deleting repository interfaces", e);
            throw e;
        }
    }

    @Override
    public String updateRepositoryInterfaces(String dsId,
                                             List<RepositoryInterface> interfaces,
                                             List<RepositoryInterface> interfacesOld, String datatype, List<RepositoryInterface> interfacesToRegister) throws Exception {
        String importResult = "";
        try {
            logger.info("updating repository interfaces for datasource: " + dsId);
            for (RepositoryInterface iFace : interfaces) {
                if (iFace.isDeleteApi()) {
                    for (RepositoryInterface iFaceOld : interfacesOld) {
                        if (iFaceOld.getId().equals(iFace.getId())) {
                            logger.error("old inteface found:");
                            this.printInterface(iFaceOld);
                            logger.error("new inteface:");
                            this.printInterface(iFace);
                            if (!(iFace.getDesiredCompatibilityLevel().equals("openaire2.0_data") && iFace.getCompliance().equals("openaire2.0")) && !iFace.getCompliance().equals(iFace.getDesiredCompatibilityLevel())) {
                                logger.debug("Iface desired combatibility level changed.");
                                if ((iFace.getBaseUrl().equals(iFaceOld.getBaseUrl())) && (iFace.getAccessSet().equals(iFaceOld.getAccessSet()))) {
                                    logger.debug("Set and Url are the same.");
                                    if (iFace.isRemovable()) {
                                        logger.debug("deleting old iface..");
                                        if (dmService.getService().deleteInterface(dsId, iFaceOld.getId()))
                                            logger.debug("deleted successfully");
                                        else
                                            logger.error("error while deleting");
                                        logger.debug("adding new iface..");
                                        iFace.setContentDescription("metadata");
                                        iFace.setCompliance("UNKNOWN");
                                        iFace.setId("api_________::" + dsId + "::" + UUID.randomUUID().toString().substring(0, 8));
                                        iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
                                        if (iFace.getAccessSet().isEmpty()) {
                                            logger.debug("set is empty: " + iFace.getAccessSet());
                                            iFace.removeAccessSet();
                                        }
                                        logger.debug("new ifaceId :" + iFace.getId());
                                        if (dmService.getService().addInterface(dsId, iFace)) {
                                            logger.debug("added successfully");
                                            interfacesToRegister.add(iFace);
                                        } else
                                            logger.error("error while adding");
                                    } else {
                                        logger.debug("Cannot delete old iface.. Values of old interface will be updated");
                                        logger.debug("updating iface.. :" + iFace.getId());
                                        dmService.getService().updateBaseUrl(dsId, iFace.getId(), iFace.getBaseUrl());
                                        if (!iFace.getAccessSet().isEmpty())
                                            dmService.getService().updateAccessParam(dsId, iFace.getId(), "set", iFace.getAccessSet(), false);
                                        else
                                            dmService.getService().deleteAccessParamOrExtraField(dsId, iFace.getId(), "set");
                                        dmService.getService().updateContentDescription(dsId, iFace.getId(), "metadata");
                                        if (datatype.equals("re3data")) {
                                            dmService.getService().updateAccessParam(dsId, iFace.getId(), "format", "oai_datacite", false);
                                            iFace.setAccessFormat("oai_datacite");
                                        } else {
                                            dmService.getService().updateAccessParam(dsId, iFace.getId(), "format", "oai_dc", false);
                                            iFace.setAccessFormat("oai_dc");
                                        }
                                        logger.debug("added successfully");
                                        interfacesToRegister.add(iFace);
                                    }
                                } else if ((!iFace.getBaseUrl().equals(iFaceOld.getBaseUrl())) || (!iFace.getAccessSet().equals(iFaceOld.getAccessSet()))) {
                                    logger.debug("Set and/or Url changed. A new interface will be created");
                                    logger.debug("adding new iface..The old one will be kept untouched.");
                                    importResult += "Interface for url/set: " + iFace.getBaseUrl() + " / " + iFace.getAccessSet() + " seems to be completely new. As a result, a new interface will be created. If you wish, you can remove the old one later.<br>";
                                    iFace.setContentDescription("metadata");
                                    iFace.setCompliance("UNKNOWN");
                                    iFace.setRemovable(true);
                                    iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
                                    if (!iFace.isRemovable())
                                        iFace.getExtraFields().put("oldId", iFace.getId());
                                    iFace.setId("api_________::" + dsId + "::" + UUID.randomUUID().toString().substring(0, 8));
                                    if (iFace.getAccessSet().isEmpty()) {
                                        logger.debug("set is empty: " + iFace.getAccessSet());
                                        iFace.removeAccessSet();
                                    }
                                    logger.debug("new ifaceId :" + iFace.getId());
                                    if (dmService.getService().addInterface(dsId, iFace)) {
                                        logger.debug("added successfully");
                                        interfacesToRegister.add(iFace);
                                    } else
                                        logger.error("error while adding");
                                }
                            } else if ((!iFace.getBaseUrl().equals(iFaceOld.getBaseUrl())) || (!iFace.getAccessSet().equals(iFaceOld.getAccessSet()))) {
                                logger.debug("Iface url/set changed.");
                                importResult += "Interface for url/set: " + iFace.getBaseUrl() + " / " + iFace.getAccessSet() + " is already compliant. As a result, a new interface will be created. If the new interface becomes compliant, then the old interface will be replaced. If not, both interfaces will be available. <br>";

                                logger.debug("adding new iface..but keeping the old id to update later.");
                                logger.debug("import result: " + importResult);
                                iFace.setContentDescription("metadata");
                                iFace.setCompliance("UNKNOWN");
                                iFace.setRemovable(true);
                                iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
                                iFace.getExtraFields().put("oldId", iFace.getId());
                                iFace.setId("api_________::" + dsId + "::" + UUID.randomUUID().toString().substring(0, 8));
                                if (iFace.getAccessSet().isEmpty()) {
                                    logger.debug("set is empty: " + iFace.getAccessSet());
                                    iFace.removeAccessSet();
                                }
                                logger.debug("new ifaceId :" + iFace.getId());
                                if (dmService.getService().addInterface(dsId, iFace)) {
                                    logger.debug("added successfully");
                                    interfacesToRegister.add(iFace);
                                } else
                                    logger.error("error while adding");
                            }
                            break;
                        }
                    }
                }
            }
            logger.debug("import result final: " + importResult);
        } catch (Exception e) {
            logger.error("error updating repository interfaces for datasource: " + dsId, e);
            throw e;
        }
        return importResult;

    }

    @Override
    public RepositoryInterface updateRepositoryInterfaceWithoutChecks(String dsId, RepositoryInterface iFace, String datatype) throws Exception {
        try {
            logger.info("updating repository interface for datasource: " + dsId);
            this.printInterface(iFace);
            if (iFace.isRemovable()) {
                logger.debug("deleting old iface..");
                if (dmService.getService().deleteInterface(dsId, iFace.getId()))
                    logger.debug("deleted successfully");
                else
                    logger.error("error while deleting");
                logger.debug("adding new iface..");
                iFace.setContentDescription("metadata");
                iFace.setCompliance("UNKNOWN");
                iFace.setId("api_________::" + dsId + "::" + UUID.randomUUID().toString().substring(0, 8));
                iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
                if (iFace.getAccessSet().isEmpty()) {
                    logger.debug("set is empty: " + iFace.getAccessSet());
                    iFace.removeAccessSet();
                }
                logger.debug("new ifaceId :" + iFace.getId());
                if (dmService.getService().addInterface(dsId, iFace)) {
                    logger.debug("added successfully");
                } else {
                    logger.error("error while adding");
                    throw new Exception("Error on datasource manager service");
                }
            } else {
                logger.debug("Cannot delete old iface.. Values of old interface will be updated");
                logger.debug("updating iface.. :" + iFace.getId());
                dmService.getService().updateBaseUrl(dsId, iFace.getId(), iFace.getBaseUrl());
                if (!iFace.getAccessSet().isEmpty())
                    dmService.getService().updateAccessParam(dsId, iFace.getId(), "set", iFace.getAccessSet(), false);
                else
                    dmService.getService().deleteAccessParamOrExtraField(dsId, iFace.getId(), "set");
                dmService.getService().updateContentDescription(dsId, iFace.getId(), "metadata");
                if (datatype.equals("re3data"))
                    iFace.setAccessFormat("oai_datacite");
                else
                    iFace.setAccessFormat("oai_dc");
                dmService.getService().updateAccessParam(dsId, iFace.getId(), "format", iFace.getAccessFormat(), false);
                dmService.getService().updateLevelOfCompliance(dsId, iFace.getId(), "UNKNOWN");
            }
            logger.debug("updated successfully");
            return iFace;
        } catch (Exception e) {
            logger.error("error updating repository interface for datasource: " + dsId, e);
            throw e;
        }
    }

    @Override
    public String insertRepositoryInterfaces(String dsId,
                                             List<RepositoryInterface> interfaces, List<RepositoryInterface> interfacesOld, String datatype, List<RepositoryInterface> interfacesToRegister)
            throws Exception {
        String importResult = "";
        try {
            logger.info("inserting repository interfaces for datasource: " + dsId);
            logger.debug("interfacesNew size: " + interfaces.size());
            logger.debug("cleaning up interfacesNew list from empty rows");
            for (RepositoryInterface iFace : interfaces) {
                if (!iFace.getBaseUrl().isEmpty() && !iFace.getDesiredCompatibilityLevel().isEmpty()) {
                    logger.debug("adding new iface..");
                    logger.debug("checking if there exists an interface with same url/set..");
                    boolean exists = false;
                    for (RepositoryInterface iFaceOld : interfacesOld) {
                        if (iFaceOld.getBaseUrl().equals(iFace.getBaseUrl()) && iFaceOld.getAccessSet().equals(iFace.getAccessSet())) {
                            logger.debug("there exists an interface with same url/set..");
                            importResult += "Interface for url/set: " + iFace.getBaseUrl() + " / " + iFace.getAccessSet() + " could not be added. There already exists an interface with same url/set. You have to update he existing one or remove it before adding a new one.<br>";
                            exists = true;
                            break;
                        }
                    }
                    iFace.setContentDescription("metadata");
                    iFace.setCompliance("UNKNOWN");
                    if (datatype.equalsIgnoreCase("journal"))
                        iFace.setTypology("pubsrepository::journal");
                    else if (datatype.equalsIgnoreCase("aggregator"))
                        iFace.setTypology("aggregator::pubsrepository::unknown");
                    else
                        iFace.setTypology("pubsrepository::unknown");
                    if (datatype.equals("re3data"))
                        iFace.setAccessFormat("oai_datacite");
                    else
                        iFace.setAccessFormat("oai_dc");
                    iFace.setAccessProtocol("oai");
                    iFace.setRemovable(true);
                    iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
                    iFace.setId("api_________::" + dsId + "::" + UUID.randomUUID().toString().substring(0, 8));
                    if (iFace.getAccessSet().isEmpty()) {
                        logger.debug("set is empty: " + iFace.getAccessSet());
                        iFace.removeAccessSet();
                    }
                    logger.debug("new ifaceId :" + iFace.getId());
                    if (!exists) {
                        if (dmService.getService().addInterface(dsId, iFace)) {
                            logger.debug("added successfully");
                            interfacesToRegister.add(iFace);
                        } else
                            logger.error("error while adding");
                    }
                }
            }
            logger.debug("interfaces size after cleanup: " + interfacesToRegister.size());
        } catch (Exception e) {
            logger.error("error inserting repository interfaces for datasource: " + dsId, e);
            throw e;
        }
        return importResult;
    }

    @Override
    public RepositoryInterface insertRepositoryInterfaceWithoutChecks(String dsId,
                                                                      RepositoryInterface iFace, String datatype)
            throws Exception {
        try {
            Repository repo = this.getRepository(dsId);
            logger.info("inserting repository interface for datasource: " + dsId);
            logger.debug("adding new iface..");
            iFace.setContentDescription("metadata");
            iFace.setCompliance("UNKNOWN");
            if (repo.getDatasourceClass() == null) {
                if (datatype.equalsIgnoreCase("journal"))
                    iFace.setTypology("pubsrepository::journal");
                else if (datatype.equalsIgnoreCase("aggregator"))
                    iFace.setTypology("aggregator::pubsrepository::unknown");
                else
                    iFace.setTypology("pubsrepository::unknown");
            } else {
                iFace.setTypology(repo.getDatasourceClass());
            }
            if (datatype.equals("re3data"))
                iFace.setAccessFormat("oai_datacite");
            else
                iFace.setAccessFormat("oai_dc");
            iFace.setAccessProtocol("oai");
            iFace.setRemovable(true);
            iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
            iFace.setId("api_________::" + dsId + "::" + UUID.randomUUID().toString().substring(0, 8));
            if (iFace.getAccessSet().isEmpty()) {
                logger.debug("set is empty: " + iFace.getAccessSet());
                iFace.removeAccessSet();
            }
            logger.debug("new ifaceId :" + iFace.getId());
            if (dmService.getService().addInterface(dsId, iFace))
                logger.debug("added successfully");
            else
                logger.error("error while adding");

            return iFace;
        } catch (Exception e) {
            logger.error("error inserting repository interface for datasource: " + dsId, e);
            throw e;
        }
    }

    @Override
    public boolean unregisterRepository(Repository repo) throws Exception {
        logger.info("unregistering repository " + repo.getOfficialName());
        try {
            for (RepositoryInterface iFace : repo.getInterfaces()) {
                if (iFace.isRemovable()) {
                    logger.debug("deleting iface..");
                    if (dmService.getService().deleteInterface(repo.getId(), iFace.getId()))
                        logger.debug("deleted successfully");
                    else
                        logger.error("error while deleting");
                } else {
                    logger.debug("updating iface compliance to UNKNOWN");
                    dmService.getService().updateLevelOfCompliance(repo.getId(), iFace.getId(), "UNKNOWN");
                }
            }
        } catch (Exception e) {
            logger.error("Error unregistering repository " + repo.getOfficialName(), e);
            return false;
        }
        return true;

    }

    private void printInterface(RepositoryInterface iFace) {
        logger.debug("baseUrl: " + iFace.getBaseUrl());
        logger.debug("format: " + iFace.getAccessFormat());
        logger.debug("typology: " + iFace.getTypology());
        logger.debug("set: " + iFace.getAccessSet());
        logger.debug("des_comp_level: " + iFace.getDesiredCompatibilityLevel());
        logger.debug("cur_comp_level: " + iFace.getCompliance());
        logger.debug("protocol: " + iFace.getAccessProtocol());
        logger.debug("api_id: " + iFace.getId());
        logger.debug("removable: " + iFace.isRemovable());
        logger.debug("deleteApi: " + iFace.isDeleteApi());
    }

    public ServiceLocator<DatasourceManagerService> getDmService() {
        return dmService;
    }

    public void setDmService(ServiceLocator<DatasourceManagerService> dmService) {
        this.dmService = dmService;
    }

}