# PublicationImport.java

    /*
     * Copyright (C) 2000 - 2024 Silverpeas
     *
     * This program is free software: you can redistribute it and/or modify it under the terms of the
     * GNU Affero General Public License as published by the Free Software Foundation, either version 3
     * of the License, or (at your option) any later version.
     *
     * As a special exception to the terms and conditions of version 3.0 of the GPL, you may
     * redistribute this Program in connection with Free/Libre Open Source Software ("FLOSS")
     * applications as described in Silverpeas's FLOSS exception. You should have received a copy of the
     * text describing the FLOSS exception, and it is also available here:
     * "https://www.silverpeas.org/legal/floss_exception.html"
     *
     * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
     * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     * Affero General Public License for more details.
     *
     * You should have received a copy of the GNU Affero General Public License along with this program.
     * If not, see <https://www.gnu.org/licenses/>.
     */
    package org.silverpeas.components.kmelia;

    import org.apache.commons.fileupload.FileItem;
    import org.silverpeas.components.kmelia.model.KmeliaRuntimeException;
    import org.silverpeas.components.kmelia.service.KmeliaService;
    import org.silverpeas.core.ResourceReference;
    import org.silverpeas.core.contribution.content.form.DataRecord;
    import org.silverpeas.core.contribution.content.form.Form;
    import org.silverpeas.core.contribution.content.form.PagesContext;
    import org.silverpeas.core.contribution.content.form.RecordSet;
    import org.silverpeas.core.contribution.content.form.XMLField;
    import org.silverpeas.core.contribution.content.form.fileitem.InternalFileItem;
    import org.silverpeas.core.contribution.publication.model.PublicationDetail;
    import org.silverpeas.core.contribution.publication.model.PublicationPK;
    import org.silverpeas.core.contribution.publication.service.PublicationService;
    import org.silverpeas.core.contribution.template.publication.PublicationTemplate;
    import org.silverpeas.core.contribution.template.publication.PublicationTemplateManager;
    import org.silverpeas.core.index.indexing.model.FieldDescription;
    import org.silverpeas.core.index.indexing.model.IndexManager;
    import org.silverpeas.core.index.search.SearchEngineProvider;
    import org.silverpeas.core.index.search.model.MatchingIndexEntry;
    import org.silverpeas.core.index.search.model.ParseException;
    import org.silverpeas.core.index.search.model.QueryDescription;
    import org.silverpeas.core.node.model.NodeDetail;
    import org.silverpeas.core.node.model.NodePK;
    import org.silverpeas.core.util.DateUtil;
    import org.silverpeas.core.util.StringUtil;
    import org.silverpeas.core.util.logging.SilverLogger;

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Date;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;

    public class PublicationImport {

      private KmeliaService kmeliaService;
      private String componentId;
      private String topicId;
      private String spaceId;
      private String userId;
      private boolean ignoreMissingFormFields = false;
      private SilverLogger logger = SilverLogger.getLogger(this);

      public PublicationImport(KmeliaService kmeliaService, String componentId,
          String topicId, String spaceId, String userId) {
        this.kmeliaService = kmeliaService;
        this.componentId = componentId;
        this.topicId = topicId;
        this.spaceId = spaceId;
        this.userId = userId;
      }

      public PublicationImport(KmeliaService kmeliaService, String componentId) {
        this.kmeliaService = kmeliaService;
        this.componentId = componentId;
      }

      public void importPublications(List<Map<String, String>> publiParamsList,
          List<Map<String, String>> formParamsList, String language, String xmlFormName,
          String discrimatingParameterName, String userProfile) {
        for (int i = 0; i < publiParamsList.size(); i++) {
          importPublication(publiParamsList.get(i), formParamsList.get(i), language, xmlFormName,
              discrimatingParameterName, userProfile);
        }
      }

      /**
       * Creates or updates a publication.
       *
       * @param publiParams The parameters of the publication.
       * @param formParams The parameters of the publication's form.
       * @param language The language of the publication.
       * @param xmlFormName The name of the publication's form.
       * @param discrimatingParameterName The name of the field included in the form which allows to
       * retrieve the eventually existing publication to update.
       * @param userProfile The user's profile used to draft out the publication.
       * @return True if the publication is created, false if it is updated.
       */
      public boolean importPublication(Map<String, String> publiParams, Map<String, String> formParams,
          String language, String xmlFormName, String discrimatingParameterName, String userProfile) {
        String publicationToUpdateId = null;
        if (discrimatingParameterName != null && discrimatingParameterName.length() > 0) {
          String discrimatingParameterValue = formParams.get(discrimatingParameterName);
          publicationToUpdateId = getPublicationId(xmlFormName, discrimatingParameterName,
              discrimatingParameterValue);
        }
        return importPublication(publicationToUpdateId, publiParams, formParams, language, xmlFormName,
            userProfile);
      }

      /**
       * Creates or updates a publication.
       *
       * @param publicationToUpdateId The id of the publication to update.
       * @param publiParams The parameters of the publication.
       * @param formParams The parameters of the publication's form.
       * @param language The language of the publication.
       * @param xmlFormName The name of the publication's form.
       * @param userProfile The user's profile used to draft out the publication.
       * @return True if the publication is created, false if it is updated.
       */
      public boolean importPublication(String publicationToUpdateId, Map<String, String> publiParams,
          Map<String, String> formParams, String language, String xmlFormName, String userProfile) {
        PublicationDetail pubDetail = null;
        boolean resultStatus;
        PublicationPK pubPK;
        if (publicationToUpdateId != null) {
          // Update
          try {
            resultStatus = false;
            pubPK = new PublicationPK(publicationToUpdateId, spaceId, componentId);
            pubDetail = kmeliaService.getPublicationDetail(pubPK);
            updatePublicationDetail(pubDetail, publiParams, language);
            updatePublication(pubDetail, true);
          } catch (Exception e) {
            throw new KmeliaRuntimeException(e);
          }
        } else {
          // Creation
          try {
            resultStatus = true;
            pubDetail = getPublicationDetail(publiParams, language);
            createPublication(pubDetail);

            pubDetail.setInfoId(xmlFormName);
            updatePublication(pubDetail, true);

            pubPK = pubDetail.getPK();
          } catch (Exception e) {
            throw new KmeliaRuntimeException(e);
          }
        }

        // UpdateXMLForm
        try {
          String pubId = pubPK.getId();

          PublicationTemplateManager publicationTemplateManager =
              PublicationTemplateManager.getInstance();
          publicationTemplateManager.addDynamicPublicationTemplate(componentId
              + ":" + xmlFormName, xmlFormName + ".xml");

          PublicationTemplate pub = publicationTemplateManager
              .getPublicationTemplate(componentId + ":" + xmlFormName);

          RecordSet set = pub.getRecordSet();
          Form form = pub.getUpdateForm();

          DataRecord data = set.getRecord(pubId, language);
          if (data == null) {
            data = set.getEmptyRecord();
            data.setId(pubId);
            data.setLanguage(language);
          }

          PagesContext context = new PagesContext("myForm", "3", language, false,
              componentId, userId);
          context.setNodeId(topicId);
          context.setObjectId(pubId);
          context.setContentLanguage(language);
          if (ignoreMissingFormFields) {
            context.setUpdatePolicy(PagesContext.ON_UPDATE_IGNORE_EMPTY_VALUES);
          }
          List< FileItem> items = new ArrayList<>();
          for (String fieldName : data.getFieldNames()) {
            String fieldValue = formParams.get(fieldName);
            fieldValue = (fieldValue == null ? "" : fieldValue);
            items.add(new InternalFileItem(fieldName, fieldValue));
          }
          form.update(items, data, context);
          set.save(data);
          updatePublication(pubDetail, true);
          NodePK nodePK = new NodePK(topicId, spaceId, componentId);
          kmeliaService.draftOutPublication(pubPK, nodePK, userProfile, true);
        } catch (Exception e) {
          throw new KmeliaRuntimeException(e);
        }

        return resultStatus;
      }

      public List<XMLField> getPublicationXmlFields(String publicationId) {
        return getPublicationXmlFields(publicationId, null);
      }

      public List<XMLField> getPublicationXmlFields(String publicationId, String language) {
        PublicationPK pubPK = new PublicationPK(publicationId, spaceId, componentId);
        PublicationDetail pubDetail = kmeliaService.getPublicationDetail(pubPK);
        return pubDetail.getXmlFields(language);
      }

      /**
       * @param parameters The parameters defining the publication.
       * @param language The language used to create the publication.
       * @return A publication detail containing the parameters given as parameters.
       * @throws Exception
       */
      private PublicationDetail getPublicationDetail(Map<String, String> parameters, String language)
          throws java.text.ParseException {
        String id = parameters.get("PubId");
        String status = parameters.get("Status");
        String name = parameters.get("Name");
        String description = parameters.get("Description");
        String keywords = parameters.get("Keywords");
        String beginDate = parameters.get("BeginDate");
        String endDate = parameters.get("EndDate");
        String version = parameters.get("Version");
        String importance = parameters.get("Importance");
        String beginHour = parameters.get("BeginHour");
        String endHour = parameters.get("EndHour");
        String author = parameters.get("Author");
        String validatorId = parameters.get("ValideurId");
        String tempId = parameters.get("TempId");
        String infoId = parameters.get("InfoId");
        String creationDate = parameters.get("CreationDate");
        String updateDate = parameters.get("UpdateDate");

        Date jBeginDate = null;
        Date jEndDate = null;
        Date jCreationDate;
        Date jUpdateDate;

        if (StringUtil.isDefined(beginDate)) {
          jBeginDate = DateUtil.stringToDate(beginDate, language);
        }
        if (StringUtil.isDefined(endDate)) {
          jEndDate = DateUtil.stringToDate(endDate, language);
        }
        if (StringUtil.isDefined(creationDate)) {
          jCreationDate = DateUtil.stringToDate(creationDate, language);
        } else {
          jCreationDate = new Date();
        }
        if (StringUtil.isDefined(updateDate)) {
          jUpdateDate = DateUtil.stringToDate(updateDate, language);
        } else {
          jUpdateDate = jCreationDate;
        }

        if (!StringUtil.isInteger(importance)) {
          importance = "5";
        }

        String pubId = StringUtil.isDefined(id) ? id : ResourceReference.UNKNOWN_ID;
        PublicationDetail pubDetail = PublicationDetail.builder(language)
            .setPk(new PublicationPK(pubId, spaceId, componentId))
            .setNameAndDescription(name, description)
            .created(jCreationDate, userId)
            .updated(jUpdateDate, userId)
            .setImportance(Integer.parseInt(importance))
            .setVersion(version)
            .setKeywords(keywords)
            .setContentPagePath("")
            .setBeginDateTime(jBeginDate, beginHour)
            .setEndDateTime(jEndDate, endHour)
            .build();

        pubDetail.setAuthor(author);
        pubDetail.setStatus(status);

        if (StringUtil.isDefined(validatorId)) {
          pubDetail.setTargetValidatorId(validatorId);
        }

        pubDetail.setCloneId(tempId);

        if (StringUtil.isDefined(infoId)) {
          pubDetail.setInfoId(infoId);
        }

        return pubDetail;
      }

      /**
       * Creates the publication described by the detail given as a parameter.
       *
       * @param pubDetail The publication detail.
       * @return The id of the newly created publication.
       */
      private String createPublication(PublicationDetail pubDetail) {
        NodePK nodePK = new NodePK(topicId, spaceId, componentId);
        return kmeliaService.createPublicationIntoTopic(pubDetail, nodePK);
      }

      /**
       * Updates the publication detail given as a parameter.
       *
       * @param pubDetail The publication detail.
       */
      private void updatePublication(PublicationDetail pubDetail, boolean forceUpdateDate) {
        pubDetail.getPK().setSpace(spaceId);
        pubDetail.getPK().setComponentName(componentId);
        pubDetail.setUpdaterId(userId);
        pubDetail.setIndexOperation(IndexManager.NONE);
        kmeliaService.updatePublication(pubDetail, forceUpdateDate);
      }

      /**
       * @param xmlFormName The name of the XML form describing the publication.
       * @param fieldName The name of the field searched into the form.
       * @param fieldValue The value of the field searched into the form.
       * @return The id of the publication corresponding to the XML form name and containing a field
       * named fieldName and valued to fieldValue. Returns null if no publication is found.
       */
      public String getPublicationId(String xmlFormName, String fieldName, String fieldValue) {
        QueryDescription query = new QueryDescription("*");
        query.setSearchingUser(userId);
        query.addComponent(componentId);

        query.addFieldQuery(new FieldDescription(xmlFormName + "$$" + fieldName, fieldValue, null));

        try {
          List<MatchingIndexEntry> result = SearchEngineProvider.getSearchEngine().search(query).
              getEntries();
          for (MatchingIndexEntry mie : result) {
            if ("Publication".equals(mie.getObjectType())) {
              return mie.getPK().getObjectId();
            }
          }
        } catch (ParseException e) {
          logger.error(e.getMessage(), e);
        }
        return null;
      }

      /**
       * @param name The name of the topic.
       * @param description The description of the topic.
       * @return The id of the newly created topic.
       */
      public String createTopic(String name, String description) {
        NodeDetail topic = new NodeDetail("-1", name, description, 0, "X");
        topic.getNodePK().setSpace(spaceId);
        topic.getNodePK().setComponentName(componentId);
        topic.setCreatorId(userId);

        NodePK fatherPK = new NodePK(topicId, spaceId, componentId);
        String alertType = "None";
        NodePK nodePK = kmeliaService.addSubTopic(fatherPK, topic, alertType);

        return nodePK.getId();
      }

      public Collection<String> getPublicationsSpecificValues(String componentId, String xmlFormName,
          String fieldName) {
        PublicationService publicationService = getPublicationService();
        Collection<PublicationDetail> publications = publicationService.getAllPublications(componentId);
        List<String> result = new ArrayList<>();
        Iterator<PublicationDetail> iter = publications.iterator();
        while (iter.hasNext()) {
          PublicationDetail publication = iter.next();
          if (publication.getInfoId().equals(xmlFormName)) {
            Collection<NodePK> fatherPKs = publicationService.getAllFatherPKInSamePublicationComponentInstance(publication.getPK());
            if (!fatherPKs.isEmpty()) {
              NodePK fatherPK = fatherPKs.iterator().next();
              if (!fatherPK.isTrash()) {
                String fieldValue = publication.getFieldValue(fieldName);
                if (StringUtil.isDefined(fieldValue)) {
                  result.add(fieldValue);
                }
              }
            }
          }
        }
        return result;
      }

      public void draftInPublication(String xmlFormName, String fieldName, String fieldValue) {
        String publicationId = getPublicationId(xmlFormName, fieldName, fieldValue);
        if (publicationId != null) {
          PublicationPK publicationPK = new PublicationPK(publicationId, componentId);
          kmeliaService.draftInPublication(publicationPK);
        }
      }

      public void updatePublicationEndDate(String xmlFormName, String fieldName, String fieldValue,
          Date endDate) {
        String publicationToUpdateId = getPublicationId(xmlFormName, fieldName, fieldValue);
        PublicationPK publicationPK = new PublicationPK(publicationToUpdateId, spaceId, componentId);
        PublicationDetail pubDetail = kmeliaService.getPublicationDetail(publicationPK);
        Date publicationEndDate = pubDetail.getEndDate();
        if (publicationEndDate == null || publicationEndDate.after(endDate)) {
          pubDetail.setEndDate(endDate);
          updatePublication(pubDetail, false);
        }
      }

      /**
       * @param parameters The parameters defining the publication.
       * @param language The language used to create the publication.
       * @return A publication detail containing the parameters given as parameters.
       * @throws Exception
       */
      private void updatePublicationDetail(PublicationDetail pubDetail, Map<String, String> parameters,
          String language) throws java.text.ParseException {
        String status = parameters.get("Status");
        String name = parameters.get("Name");
        String description = parameters.get("Description");
        String keywords = parameters.get("Keywords");
        String beginDate = parameters.get("BeginDate");
        String endDate = parameters.get("EndDate");
        String version = parameters.get("Version");
        String importance = parameters.get("Importance");
        String beginHour = parameters.get("BeginHour");
        String endHour = parameters.get("EndHour");
        String author = parameters.get("Author");
        String validatorId = parameters.get("ValideurId");
        String tempId = parameters.get("TempId");
        String infoId = parameters.get("InfoId");
        String updateDate = parameters.get("UpdateDate");

        if (StringUtil.isDefined(updateDate)) {
          pubDetail.setUpdateDate(DateUtil.stringToDate(updateDate, language));
        }

        if (StringUtil.isDefined(beginDate)) {
          pubDetail.setBeginDate(DateUtil.stringToDate(beginDate, language));
        }
        if (StringUtil.isDefined(endDate)) {
          pubDetail.setEndDate(DateUtil.stringToDate(endDate, language));
        }

        if (name != null) {
          pubDetail.setName(name);
        }

        if (description != null) {
          pubDetail.setDescription(description);
        }

        if (StringUtil.isInteger(importance)) {
          pubDetail.setImportance(Integer.parseInt(importance));
        }

        if (version != null) {
          pubDetail.setVersion(version);
        }

        if (keywords != null) {
          pubDetail.setKeywords(keywords);
        }

        if (author != null) {
          pubDetail.setAuthor(author);
        }

        pubDetail.setBeginHour(beginHour);
        pubDetail.setEndHour(endHour);

        if (status != null) {
          pubDetail.setStatus(status);
        }

        if (StringUtil.isDefined(validatorId)) {
          pubDetail.setTargetValidatorId(validatorId);
        }

        pubDetail.setCloneId(tempId);

        if (StringUtil.isDefined(infoId)) {
          pubDetail.setInfoId(infoId);
        }
      }

      public void setIgnoreMissingFormFields(boolean ignore) {
        ignoreMissingFormFields = ignore;
      }

      private PublicationService getPublicationService() {
        return PublicationService.get();
      }
    }