/*
 * Copyright (C) 2003-2010 eXo Platform SAS.
 *
 * 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.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see<http://www.gnu.org/licenses/>.
 */
package org.exoplatform.wiki.webui;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.ResourceBundle;

import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;

import org.exoplatform.commons.utils.StringCommonUtils;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.User;
import org.exoplatform.web.application.RequestContext;
import org.exoplatform.webui.application.WebuiRequestContext;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
import org.exoplatform.webui.event.Event;
import org.exoplatform.webui.event.EventListener;
import org.exoplatform.webui.form.UIFormStringInput;
import org.exoplatform.webui.form.UIFormTextAreaInput;
import org.exoplatform.webui.form.input.UICheckBoxInput;
import org.exoplatform.wiki.commons.Utils;
import org.exoplatform.wiki.mow.api.DraftPage;
import org.exoplatform.wiki.mow.api.Page;
import org.exoplatform.wiki.mow.api.PageVersion;
import org.exoplatform.wiki.service.WikiPageParams;
import org.exoplatform.wiki.service.WikiService;
import org.exoplatform.wiki.service.impl.SessionManager;
import org.exoplatform.wiki.webui.control.UIEditorTabs;
import org.exoplatform.wiki.webui.control.UISubmitToolBar;
import org.exoplatform.wiki.webui.core.UIWikiForm;
import org.exoplatform.wiki.webui.popup.UIWikiPagePreview;

@ComponentConfig(
  lifecycle = UIFormLifecycle.class,
  template = "app:/templates/wiki/webui/UIWikiPageEditForm.gtmpl",
  events = {
      @EventConfig(listeners = UIWikiPageEditForm.CloseActionListener.class),
      @EventConfig(listeners = UIWikiPageEditForm.DeleteDraftActionListener.class),
      @EventConfig(listeners = UIWikiPageEditForm.ResumeDraftActionListener.class),
      @EventConfig(listeners = UIWikiPageEditForm.ViewDraftChangeActionListener.class),
      @EventConfig(listeners = UIWikiPageEditForm.CancelDraftActionListener.class)
  }
)
public class UIWikiPageEditForm extends UIWikiForm {

  public static final String UNTITLED                  = "Untitled";

  public static final String FIELD_CONTENT             = "Markup";

  public static final String FIELD_COMMENT             = "Comment";

  public static final String FIELD_PUBLISH_ACTIVITY_UPPER    = "PublishActivityUpper";

  public static final String FIELD_PUBLISH_ACTIVITY_BOTTOM    = "PublishActivityBottom";

  public static final String TITLE_CONTROL             = "UIWikiPageTitleControlForm_PageEditForm";

  public static final String EDITOR_TABS               = "UIEditorTabs";

  public static final String SUBMIT_TOOLBAR_UPPER      = "UISubmitToolBarUpper";

  public static final String SUBMIT_TOOLBAR_BOTTOM     = "UISubmitToolBarBottom";

  public static final String HELP_PANEL                = "UIWikiSidePanelArea";

  public static final String RICHTEXT_AREA             = "UIWikiRichTextArea";

  public static final String FIELD_TEMPLATEDESCTIPTION = "UIWikiTemplateDescriptionContainer";

  private boolean            isTemplate        = false;

  private String             templateId        = StringUtils.EMPTY;

  private String             title;

  private List<String> notificationMessages = new ArrayList<String>();

  private String initDraftName = StringUtils.EMPTY;

  private boolean isFirstTimeRenderEdit = true;

  private boolean isRunAutoSave = true;

  public static final String CLOSE = "Close";

  private WikiService wikiService;

  public UIWikiPageEditForm() throws Exception {
    this.accept_Modes = Arrays.asList(new WikiMode[] { WikiMode.EDITPAGE, WikiMode.ADDPAGE, WikiMode.EDITTEMPLATE, WikiMode.ADDTEMPLATE });
    addChild(UIWikiPageTitleControlArea.class, null, TITLE_CONTROL).toInputMode();
    addChild(UISubmitToolBar.class, null, SUBMIT_TOOLBAR_UPPER);
    addUIFormInput(new UICheckBoxInput(FIELD_PUBLISH_ACTIVITY_UPPER, FIELD_PUBLISH_ACTIVITY_UPPER, false));
    addChild(UIWikiTemplateDescriptionContainer.class, null, FIELD_TEMPLATEDESCTIPTION);
    addChild(UIEditorTabs.class, null, EDITOR_TABS);
    addChild(UISubmitToolBar.class, null, SUBMIT_TOOLBAR_BOTTOM);
    addChild(UIWikiSidePanelArea.class, null, HELP_PANEL);
    addChild(UIWikiRichTextArea.class, null, RICHTEXT_AREA).setRendered(false);
    UIFormTextAreaInput markupInput = new UIFormTextAreaInput(FIELD_CONTENT, FIELD_CONTENT, "");
    addUIFormInput(markupInput);
    UIFormStringInput commentInput = new UIFormStringInput(FIELD_COMMENT, FIELD_COMMENT, "");
    addUIFormInput(commentInput);
    addUIFormInput(new UICheckBoxInput(FIELD_PUBLISH_ACTIVITY_BOTTOM, FIELD_PUBLISH_ACTIVITY_BOTTOM, false));

    wikiService = ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(WikiService.class);
  }

  protected void checkToDisplayNotification() throws Exception {
    if ("__anonim".equals(org.exoplatform.wiki.utils.Utils.getCurrentUser())) {
      isRunAutoSave = false;
      return;
    }

    // Check to display info message if the draft for this page exist
    WikiService wikiService = (WikiService) PortalContainer.getComponent(WikiService.class);
    WikiPageParams pageParams = Utils.getCurrentWikiPageParams();
    UIWikiPortlet wikiPortlet = getAncestorOfType(UIWikiPortlet.class);
    notificationMessages.clear();
    isRunAutoSave = true;
    if (wikiPortlet.getWikiMode() == WikiMode.EDITPAGE) {
      Page page = wikiService.getPageOfWikiByName(pageParams.getType(), pageParams.getOwner(), pageParams.getPageName());
      DraftPage draftPage = wikiService.getDraftOfPage(page);
      if (draftPage != null) {
        if (!draftPage.getName().equals(initDraftName)) {
          isRunAutoSave = false;
          if (wikiService.isDraftOutDated(draftPage)) {
            notificationMessages.add(createDraftOutdateNotification());
          } else {
            notificationMessages.add(createDraftExistNotification(draftPage.getUpdatedDate()));
          }
        }
      }

      List<String> edittingUsers = org.exoplatform.wiki.utils.Utils.getListOfUserEditingPage(pageParams.getPageName());
      if (edittingUsers.size() > 0) {
        notificationMessages.add(createCocurrentEdittingNotification(edittingUsers));
      }
    }
  }

  private String createDraftOutdateNotification() throws Exception {
    ResourceBundle bundle = RequestContext.getCurrentInstance().getApplicationResourceBundle();

    // Build message markup
    String messageMarkup = bundle.getString("DraftPage.msg.draft-version-outdated");
    String messageHTML = "<div class='alert alert-info'><i class='uiIconInformation uiIconBlue'></i>" + messageMarkup + "</div>";

    // Add actions to message html
    String viewChangeDraftLabel = bundle.getString("DraftPage.label.view-your-change");
    String viewChangeActionLink = event("ViewDraftChange");
    String continueEdittingLabel = bundle.getString("DraftPage.label.continue-editing");
    String continueEdittingActionLink = event("ResumeDraft");
    String deleteDraftLabel = bundle.getString("DraftPage.label.delete");
    String deleteActionLink = event("DeleteDraft");
    messageHTML = messageHTML.replace("{0}", "<a href=\"" + viewChangeActionLink + "\">" + viewChangeDraftLabel + "</a>");
    messageHTML = messageHTML.replace("{1}", "<a href=\"" + continueEdittingActionLink + "\">" + continueEdittingLabel + "</a>");
    messageHTML = messageHTML.replace("{2}", "<a href=\"" + deleteActionLink + "\">" + deleteDraftLabel + "</a>");
    return messageHTML;
  }

  private String createDraftExistNotification(Date draftUpdatedDate) throws Exception {
    ResourceBundle bundle = RequestContext.getCurrentInstance().getApplicationResourceBundle();
    Calendar calendar = new GregorianCalendar();
    calendar.setTime(draftUpdatedDate);
    // Build message markup
    String messageMarkup = bundle.getString("DraftPage.msg.draft-exist-notification");
    StringBuffer dateString = new StringBuffer().append("{").append(calendar.getTimeInMillis()).append("}");
    messageMarkup = messageMarkup.replace("{0}", dateString.toString());
    String messageHTML = "<div class='alert alert-info'><i class='uiIconInformation uiIconBlue'></i>" + messageMarkup + "</div>";

    // Add actions to message html
    String viewChangeDraftLabel = bundle.getString("DraftPage.label.view-your-change");
    String viewChangeActionLink = event("ViewDraftChange");
    String resumeDraftLabel = bundle.getString("DraftPage.label.resume-the-draft");
    String resumeActionLink = event("ResumeDraft");
    String deleteDraftLabel = bundle.getString("DraftPage.label.delete");
    String deleteActionLink = event("DeleteDraft");

    messageHTML = messageHTML.replace("{1}", "<a href=\"" + viewChangeActionLink + "\">" + viewChangeDraftLabel + "</a>");
    messageHTML = messageHTML.replace("{2}", "<a href=\"" + resumeActionLink + "\">" + resumeDraftLabel + "</a>");
    messageHTML = messageHTML.replace("{3}", "<a href=\"" + deleteActionLink + "\">" + deleteDraftLabel + "</a>");
    return messageHTML;
  }

  private String createCocurrentEdittingNotification(List<String> users) throws Exception {
    // Concat all user name
    StringBuilder usernameList = new StringBuilder();
    OrganizationService organizationService = (OrganizationService) PortalContainer.getComponent(OrganizationService.class);
    for (String user : users) {
      User userObject = organizationService.getUserHandler().findUserByName(user);
      usernameList.append(userObject.getFullName());
      usernameList.append(", ");
    }

    // Remove 2 last chars
    usernameList.setLength(usernameList.length() - 2);

    // Build message markup
    ResourceBundle bundle = RequestContext.getCurrentInstance().getApplicationResourceBundle();
    String messageMarkup = bundle.getString("DraftPage.msg.concurrent-editing");
    messageMarkup = messageMarkup.replace("{0}", "<b>" + usernameList.toString() + "</b>");
    messageMarkup = "<div class='alert'><i class='uiIconWarning'></i>" + messageMarkup + "</div>";;

    // Render to message html and return
    return messageMarkup;
  }

  public void setTitle(String title){ this.title = title ;}
  public String getTitle(){ return title ;}

  public String getInitDraftName() {
    return initDraftName;
  }

  public void setInitDraftName(String initDraftName) {
    this.initDraftName = initDraftName;
    this.isFirstTimeRenderEdit = true;
  }

  //only set the initDraftName at the first time when page is created or edited
  public boolean isFirstTimeRenderEdit() { return isFirstTimeRenderEdit; }

  public void setFirstTimeRenderEdit(boolean value) {
    this.isFirstTimeRenderEdit = value;
  }

  public boolean isInTemplateMode() {
    UIWikiPortlet wikiPortlet = getAncestorOfType(UIWikiPortlet.class);
    return (wikiPortlet.getWikiMode() == WikiMode.ADDTEMPLATE) || (wikiPortlet.getWikiMode() == WikiMode.EDITTEMPLATE);
  }

  public boolean isNewPage() {
    UIWikiPortlet wikiPortlet = getAncestorOfType(UIWikiPortlet.class);
    return wikiPortlet.getWikiMode() != WikiMode.EDITPAGE;
  }

  public long getAutoSaveSequenceTime() {
    WikiService wikiService = (WikiService) PortalContainer.getComponent(WikiService.class);
    return wikiService.getSaveDraftSequenceTime();
  }

  protected String getSaveDraftRestUrl() {
    StringBuilder childrenURLSb = new StringBuilder(Utils.getCurrentRestURL());
    childrenURLSb.append("/wiki/saveDraft/");
    return childrenURLSb.toString();
  }

  protected String getRemoveDraftRestUrl() {
    StringBuilder childrenURLSb = new StringBuilder(Utils.getCurrentRestURL());
    childrenURLSb.append("/wiki/removeDraft/");
    return childrenURLSb.toString();
  }

  protected String getWikiType() throws Exception {
    WikiPageParams pageParams = Utils.getCurrentWikiPageParams();
    return pageParams.getType();
  }

  protected String getWikiOwner() throws Exception {
    WikiPageParams pageParams = Utils.getCurrentWikiPageParams();
    return pageParams.getOwner();
  }

  protected String getCurrentPageId() throws Exception {
    WikiPageParams pageParams = Utils.getCurrentWikiPageParams();
    return URLEncoder.encode(pageParams.getPageName(),"utf-8");
  }

  protected String getCurrentPageRevision() throws Exception {
    UIWikiPortlet wikiPortlet = getAncestorOfType(UIWikiPortlet.class);
    if (wikiPortlet.getWikiMode() == WikiMode.EDITPAGE) {
      Page page = Utils.getCurrentWikiPage();
      List<PageVersion> versions = wikiService.getVersionsOfPage(page);
      if(versions != null && !versions.isEmpty()) {
        return versions.get(0).getName();
      } else {
        return null;
      }
    }
    return StringUtils.EMPTY;
  }

  public List getNotificationMessages() {
    return notificationMessages;
  }

  public boolean isTemplate() {
    return isTemplate;
  }

  public void setTemplate(boolean isTemplate) {
    this.isTemplate = isTemplate;
  }

  public String getTemplateId() {
    return templateId;
  }

  public void setTemplateId(String templateId) {
    this.templateId = templateId;
  }

  public boolean isSidePanelRendered(){
    return getChild(UIWikiSidePanelArea.class).isRendered();
  }

  public boolean isRunAutoSave() {
    return isRunAutoSave;
  }

  protected boolean isInRichTextEditor() {
    UIWikiRichTextArea wikiRichTextArea = getChild(UIWikiRichTextArea.class);
    return wikiRichTextArea.isRendered();
  }

  protected String getCancelDraftEvent() throws Exception {
    return org.exoplatform.wiki.commons.Utils.createFormActionLink(this, "CancelDraft", null);
  }

  public void synPublishActivityStatus(boolean isChecked) {
    UICheckBoxInput publishActivityUpperCheckBox =
        this.findComponentById(UIWikiPageEditForm.FIELD_PUBLISH_ACTIVITY_UPPER);
    UICheckBoxInput publishActivityBottomCheckBox =
        this.findComponentById(UIWikiPageEditForm.FIELD_PUBLISH_ACTIVITY_BOTTOM);
    publishActivityUpperCheckBox.setChecked(isChecked);
    publishActivityBottomCheckBox.setChecked(isChecked);
  }

  private void checkRenderOfPublishActivityCheckBoxes() {
    UICheckBoxInput publishActivityUpperCheckBox =
        this.findComponentById(UIWikiPageEditForm.FIELD_PUBLISH_ACTIVITY_UPPER);
    UICheckBoxInput publishActivityBottomCheckBox =
        this.findComponentById(UIWikiPageEditForm.FIELD_PUBLISH_ACTIVITY_BOTTOM);
    if (WikiMode.EDITPAGE == this.getCurrentMode()) {
      publishActivityUpperCheckBox.setRendered(true);
      publishActivityBottomCheckBox.setRendered(true);
    } else {
      publishActivityUpperCheckBox.setRendered(false);
      publishActivityBottomCheckBox.setRendered(false);
    }
  }

  @Override
  public void processRender(WebuiRequestContext context) throws Exception {
    // Store wikiContext for wikiRemoteServiceServlet to use later
    HttpSession session = Util.getPortalRequestContext().getRequest().getSession(false);
    SessionManager sessionManager = (SessionManager)PortalContainer.getComponent(SessionManager.class);
    sessionManager.addSessionContext(session.getId(),
                                     Utils.createWikiContext(this.getAncestorOfType(UIWikiPortlet.class)));

    this.checkRenderOfPublishActivityCheckBoxes();
    super.processRender(context);
  }

  public static class DeleteDraftActionListener extends EventListener<UIWikiPageEditForm> {
    @Override
    public void execute(Event<UIWikiPageEditForm> event) throws Exception {
      WikiService wikiService = (WikiService) PortalContainer.getComponent(WikiService.class);
      WikiPageParams pageParams = Utils.getCurrentWikiPageParams();
      wikiService.removeDraftOfPage(pageParams);
      event.getRequestContext().addUIComponentToUpdateByAjax(event.getSource());
    }
  }

  public static class ResumeDraftActionListener extends EventListener<UIWikiPageEditForm> {
    @Override
    public void execute(Event<UIWikiPageEditForm> event) throws Exception {
      UIWikiPageEditForm pageEditForm = event.getSource();
      UIWikiPortlet wikiPortlet = pageEditForm.getAncestorOfType(UIWikiPortlet.class);

      WikiPageParams pageParams = Utils.getCurrentWikiPageParams();
      WikiService wikiService = (WikiService) PortalContainer.getComponent(WikiService.class);
      if (wikiPortlet.getWikiMode() == WikiMode.EDITPAGE) {
        Page page = wikiService.getPageOfWikiByName(pageParams.getType(), pageParams.getOwner(), pageParams.getPageName());
        DraftPage draftPage = wikiService.getDraftOfPage(page);
        if (draftPage != null) {
          UIFormStringInput titleInput = pageEditForm.getChild(UIWikiPageTitleControlArea.class).getUIStringInput();
          UIFormTextAreaInput markupInput = pageEditForm.findComponentById(UIWikiPageEditForm.FIELD_CONTENT);

          String title = draftPage.getTitle();
          String content = draftPage.getContent();
          titleInput.setEditable(true);
          titleInput.setValue(StringCommonUtils.decodeSpecialCharToHTMLnumber(title));
          pageEditForm.setTitle(title);
          markupInput.setValue(content);
          UIWikiRichTextArea wikiRichTextArea = pageEditForm.getChild(UIWikiRichTextArea.class);
          if (wikiRichTextArea.isRendered()) {
            Utils.feedDataForWYSIWYGEditor(pageEditForm, null);
          }
          pageEditForm.setInitDraftName(draftPage.getName());
        }
      }
      event.getRequestContext().addUIComponentToUpdateByAjax(event.getSource());
    }
  }

  public static class ViewDraftChangeActionListener extends EventListener<UIWikiPageEditForm> {
    @Override
    public void execute(Event<UIWikiPageEditForm> event) throws Exception {
      UIWikiPageEditForm pageEditForm = event.getSource();
      UIWikiPortlet wikiPortlet = pageEditForm.getAncestorOfType(UIWikiPortlet.class);

      WikiPageParams pageParams = Utils.getCurrentWikiPageParams();
      WikiService wikiService = (WikiService) PortalContainer.getComponent(WikiService.class);
      if (wikiPortlet.getWikiMode() == WikiMode.EDITPAGE) {
        Page page = wikiService.getPageOfWikiByName(pageParams.getType(), pageParams.getOwner(), pageParams.getPageName());
        DraftPage draftPage = wikiService.getDraftOfPage(page);
        if (draftPage != null) {
          WebuiRequestContext context = WebuiRequestContext.getCurrentInstance() ;
          ResourceBundle res = context.getApplicationResourceBundle() ;
          UIWikiMaskWorkspace uiMaskWS = wikiPortlet.getChild(UIWikiMaskWorkspace.class);
          UIWikiPagePreview wikiPagePreview = uiMaskWS.createUIComponent(UIWikiPagePreview.class, null, null);
          wikiPagePreview.setPageTitle(draftPage.getTitle());
          wikiPagePreview.setContent(wikiService.getDraftChanges(draftPage).getDiffHTML());
          uiMaskWS.setUIComponent(wikiPagePreview);
          uiMaskWS.setShow(true);
          uiMaskWS.setPopupTitle(res.getString("DraftPage.title.draft-changes"));
          event.getRequestContext().addUIComponentToUpdateByAjax(uiMaskWS);
        }
      }
    }
  }

  public static class CancelDraftActionListener extends EventListener<UIWikiPageEditForm> {
    @Override
    public void execute(Event<UIWikiPageEditForm> event) throws Exception {
      UIWikiPageEditForm pageEditForm = event.getSource();
      UIWikiPortlet wikiPortlet = pageEditForm.getAncestorOfType(UIWikiPortlet.class);
      WikiService wikiService = (WikiService) PortalContainer.getComponent(WikiService.class);
      WikiPageParams pageParams = Utils.getCurrentWikiPageParams();

      if (wikiPortlet.getWikiMode() == WikiMode.EDITPAGE) {
        wikiService.removeDraftOfPage(pageParams);
      } else {
        DraftPage draftPage = wikiService.getLastestDraft();
        if (draftPage.isNewPage()) {
          wikiService.removeDraft(draftPage.getName());
        }
      }
      Utils.redirect(pageParams, WikiMode.VIEW);
    }
  }

  static public class CloseActionListener extends EventListener<UIWikiPageEditForm> {
   @Override
    public void execute(Event<UIWikiPageEditForm> event) throws Exception {
      UIWikiSidePanelArea sidePanelForm = event.getSource().getChild(UIWikiSidePanelArea.class);
      sidePanelForm.setRendered(false);
      event.getRequestContext().addUIComponentToUpdateByAjax(event.getSource());
    }
  }
}
