/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard ([email protected])
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition 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.projectforge.web.task;

import java.util.List;
import java.util.ListIterator;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.hibernate.Hibernate;
import org.projectforge.task.TaskDO;
import org.projectforge.task.TaskDao;
import org.projectforge.task.TaskFavorite;
import org.projectforge.task.TaskNode;
import org.projectforge.task.TaskTree;
import org.projectforge.user.UserPrefArea;
import org.projectforge.web.CSSColor;
import org.projectforge.web.fibu.ISelectCallerPage;
import org.projectforge.web.wicket.AbstractEditPage;
import org.projectforge.web.wicket.AbstractSecuredPage;
import org.projectforge.web.wicket.AbstractSelectPanel;
import org.projectforge.web.wicket.WicketUtils;
import org.projectforge.web.wicket.components.FavoritesChoicePanel;
import org.projectforge.web.wicket.flowlayout.ComponentWrapperPanel;
import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
import org.projectforge.web.wicket.flowlayout.IconPanel;
import org.projectforge.web.wicket.flowlayout.IconType;

/**
 * Panel for showing and selecting one task.
 * @author Kai Reinhard ([email protected])
 * 
 */
public class TaskSelectPanel extends AbstractSelectPanel<TaskDO> implements ComponentWrapperPanel
{
  private static final long serialVersionUID = -7231190025292695850L;

  @SpringBean(name = "taskDao")
  private TaskDao taskDao;

  @SpringBean(name = "taskTree")
  private TaskTree taskTree;

  private boolean showPath = true;

  private final WebMarkupContainer divContainer;

  private RepeatingView ancestorRepeater;

  private Integer currentTaskId;

  private boolean ajaxTaskSelectMode;

  private WebMarkupContainer userselectContainer;

  private FieldsetPanel fieldsetPanel;

  private boolean autocompleteOnlyTaskBookableForTimesheets;

  public TaskSelectPanel(final FieldsetPanel fieldsetPanel, final IModel<TaskDO> model, final ISelectCallerPage caller,
      final String selectProperty)
  {
    super(fieldsetPanel.newChildId(), model, caller, selectProperty);
    this.fieldsetPanel = fieldsetPanel;
    fieldsetPanel.getFieldset().setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
    TaskDO task = model.getObject();
    if (Hibernate.isInitialized(task) == false) {
      task = taskTree.getTaskById(task.getId());
      model.setObject(task);
    }
    divContainer = new WebMarkupContainer("div") {
      private static final long serialVersionUID = -8150112323444983335L;

      /**
       * @see org.apache.wicket.Component#isVisible()
       */
      @Override
      public boolean isVisible()
      {
        // display only, if we are not in ajax task select mode
        return ajaxTaskSelectMode == false;
      }
    };
    divContainer.setOutputMarkupId(true);
    divContainer.setOutputMarkupPlaceholderTag(true);
    add(divContainer);
    ajaxTaskSelectMode = false;
  }

  /**
   * @see org.projectforge.web.wicket.AbstractSelectPanel#onBeforeRender()
   */
  @SuppressWarnings("serial")
  @Override
  protected void onBeforeRender()
  {
    super.onBeforeRender();
    final TaskDO task = getModelObject();
    final Integer taskId = task != null ? task.getId() : null;
    if (currentTaskId == taskId) {
      return;
    }
    currentTaskId = taskId;
    if (showPath == true && task != null) {
      ancestorRepeater.removeAll();
      final TaskNode taskNode = taskTree.getTaskNodeById(task.getId());
      final List<Integer> ancestorIds = taskNode.getAncestorIds();
      final ListIterator<Integer> it = ancestorIds.listIterator(ancestorIds.size());
      while (it.hasPrevious() == true) {
        final Integer ancestorId = it.previous();
        final TaskDO ancestorTask = taskTree.getTaskById(ancestorId);
        if (ancestorTask.getParentTask() == null) {
          // Don't show root node:
          continue;
        }
        final WebMarkupContainer cont = new WebMarkupContainer(ancestorRepeater.newChildId());
        ancestorRepeater.add(cont);
        final SubmitLink selectTaskLink = new SubmitLink("ancestorTaskLink") {
          @Override
          public void onSubmit()
          {
            caller.select(selectProperty, ancestorTask.getId());
          }
        };
        selectTaskLink.setDefaultFormProcessing(false);
        cont.add(selectTaskLink);
        WicketUtils.addTooltip(selectTaskLink, getString("task.selectPanel.selectAncestorTask.tooltip"));
        selectTaskLink.add(new Label("name", ancestorTask.getTitle()));
      }
      ancestorRepeater.setVisible(true);
    } else {
      ancestorRepeater.setVisible(false);
    }
  }

  @Override
  @SuppressWarnings("serial")
  public TaskSelectPanel init()
  {
    super.init();
    ancestorRepeater = new RepeatingView("ancestorTasks");
    divContainer.add(ancestorRepeater);
    final SubmitLink taskLink = new SubmitLink("taskLink") {
      @Override
      public void onSubmit()
      {
        final TaskDO task = getModelObject();
        if (task == null) {
          return;
        }
        final PageParameters pageParams = new PageParameters();
        pageParams.add(AbstractEditPage.PARAMETER_KEY_ID, String.valueOf(task.getId()));
        final TaskEditPage editPage = new TaskEditPage(pageParams);
        editPage.setReturnToPage((AbstractSecuredPage) getPage());
        setResponsePage(editPage);
      }
    };
    taskLink.setDefaultFormProcessing(false);
    divContainer.add(taskLink);
    // auto complete panels
    initAutoCompletePanels();

    WicketUtils.addTooltip(taskLink, getString("task.selectPanel.displayTask.tooltip"));
    taskLink.add(new Label("name", new Model<String>() {
      /**
       * @see org.apache.wicket.model.Model#getObject()
       */
      @Override
      public String getObject()
      {
        final TaskDO task = getModelObject();
        return task != null ? task.getTitle() : "";
      }
    }));

    final SubmitLink selectButton = new SubmitLink("select") {
      @Override
      public void onSubmit()
      {
        final TaskTreePage taskTreePage = new TaskTreePage(caller, selectProperty);
        if (getModelObject() != null) {
          taskTreePage.setHighlightedRowId(getModelObject().getId()); // Preselect node for highlighting.
        }
        setResponsePage(taskTreePage);
      };
    };
    selectButton.setDefaultFormProcessing(false);
    divContainer.add(selectButton);
    selectButton.add(new IconPanel("selectHelp", IconType.TASK, getString("tooltip.selectTask")));
    final SubmitLink unselectButton = new SubmitLink("unselect") {
      @Override
      public void onSubmit()
      {
        caller.unselect(selectProperty);
      }

      @Override
      public boolean isVisible()
      {
        return isRequired() == false && getModelObject() != null;
      }
    };
    unselectButton.setDefaultFormProcessing(false);
    divContainer.add(unselectButton);
    unselectButton.add(new IconPanel("unselectHelp", IconType.REMOVE_SIGN, getString("tooltip.unselectTask")).setColor(CSSColor.RED));
    // DropDownChoice favorites
    final FavoritesChoicePanel<TaskDO, TaskFavorite> favoritesPanel = new FavoritesChoicePanel<TaskDO, TaskFavorite>("favorites",
        UserPrefArea.TASK_FAVORITE, tabIndex, "full text") {
      @Override
      protected void select(final TaskFavorite favorite)
      {
        if (favorite.getTask() != null) {
          TaskSelectPanel.this.selectTask(favorite.getTask());
        }
      }

      @Override
      protected TaskDO getCurrentObject()
      {
        return TaskSelectPanel.this.getModelObject();
      }

      @Override
      protected TaskFavorite newFavoriteInstance(final TaskDO currentObject)
      {
        final TaskFavorite favorite = new TaskFavorite();
        favorite.setTask(currentObject);
        return favorite;
      }
    };
    divContainer.add(favoritesPanel);
    favoritesPanel.init();
    if (showFavorites == false) {
      favoritesPanel.setVisible(false);
    }
    return this;
  }

  /**
   * 
   */
  private void initAutoCompletePanels()
  {
    userselectContainer = new WebMarkupContainer("userselectContainer") {
      private static final long serialVersionUID = -4871020567729661148L;

      /**
       * @see org.apache.wicket.Component#isVisible()
       */
      @Override
      public boolean isVisible()
      {
        // only show if we are in ajax select task mode
        return ajaxTaskSelectMode == true;
      }
    };
    add(userselectContainer);
    userselectContainer.setOutputMarkupId(true);
    userselectContainer.setOutputMarkupPlaceholderTag(true);
    final TaskSelectAutoCompleteFormComponent searchTaskInput = new TaskSelectAutoCompleteFormComponent("searchTaskInput") {
      private static final long serialVersionUID = -7741009167252308262L;

      /**
       * @see org.projectforge.web.task.TaskSelectAutoCompleteFormComponent#onModelChanged(org.apache.wicket.ajax.AjaxRequestTarget)
       */
      @Override
      protected void onModelSelected(final AjaxRequestTarget target, final TaskDO taskDo)
      {
        ajaxTaskSelectMode = false;
        target.appendJavaScript("hideAllTooltips();");
        TaskSelectPanel.this.setModelObject(taskDo);
        TaskSelectPanel.this.onModelSelected(target, taskDo);
      }

    };
    searchTaskInput.setAutocompleteOnlyTaskBookableForTimesheets(autocompleteOnlyTaskBookableForTimesheets);
    userselectContainer.add(searchTaskInput);
    // opener link
    final WebMarkupContainer searchTaskInputOpen = new WebMarkupContainer("searchTaskInputOpen");
    WicketUtils.addTooltip(searchTaskInputOpen, getString("quickselect"));
    searchTaskInputOpen.add(new AjaxEventBehavior("click") {
      private static final long serialVersionUID = -938527474172868488L;

      @Override
      protected void onEvent(final AjaxRequestTarget target)
      {
        ajaxTaskSelectMode = true;
        target.appendJavaScript("hideAllTooltips();");
        target.add(divContainer);
        target.add(userselectContainer);
        target.focusComponent(searchTaskInput);
      }
    });
    // close link
    final WebMarkupContainer searchTaskInputClose = new WebMarkupContainer("searchTaskInputClose");
    divContainer.add(searchTaskInputClose);
    searchTaskInputClose.add(new AjaxEventBehavior("click") {
      private static final long serialVersionUID = -4334830387094758960L;

      @Override
      protected void onEvent(final AjaxRequestTarget target)
      {
        ajaxTaskSelectMode = false;
        target.appendJavaScript("hideAllTooltips();");
        target.add(divContainer);
        target.add(userselectContainer);
      }
    });
    userselectContainer.add(searchTaskInputClose);
    divContainer.add(searchTaskInputOpen);
  }

  /**
   * Hook method which is called, when the task is set by auto complete field
   * 
   * @param target
   * @param taskDo
   */
  protected void onModelSelected(final AjaxRequestTarget target, final TaskDO taskDo)
  {
    target.add(fieldsetPanel.getFieldset());
    target.add(divContainer);
    target.add(userselectContainer);
  }

  /**
   * Will be called if the user has chosen an entry of the task favorites drop down choice.
   * @param task
   */
  protected void selectTask(final TaskDO task)
  {
    setModelObject(task);
    caller.select(selectProperty, task.getId());
  }

  @Override
  public Component getClassModifierComponent()
  {
    return divContainer;
  }

  @Override
  protected void convertInput()
  {
    setConvertedInput(getModelObject());
  }

  /**
   * If true (default) then the path from the root task to the currently selected will be shown, otherwise only the name of the task is
   * displayed.
   * @param showPath
   */
  public void setShowPath(final boolean showPath)
  {
    this.showPath = showPath;
  }

  /**
   * @see org.projectforge.web.wicket.flowlayout.ComponentWrapperPanel#getComponentOutputId()
   */
  @Override
  public String getComponentOutputId()
  {
    divContainer.setOutputMarkupId(true);
    return divContainer.getMarkupId();
  }

  /**
   * @see org.projectforge.web.wicket.flowlayout.ComponentWrapperPanel#getFormComponent()
   */
  @Override
  public FormComponent< ? > getFormComponent()
  {
    return null;
  }

  /**
   * @param autocompleteOnlyTaskBookableForTimesheets the autocompleteOnlyTaskBookableForTimesheets to set
   * @return this for chaining.
   */
  public TaskSelectPanel setAutocompleteOnlyTaskBookableForTimesheets(final boolean autocompleteOnlyTaskBookableForTimesheets)
  {
    this.autocompleteOnlyTaskBookableForTimesheets = autocompleteOnlyTaskBookableForTimesheets;
    return this;
  }

  /**
   * If true then only task will be displayed in autocompletion list which are allowed to have timesheets.
   * @return the autocompleteOnlyTaskBookableForTimesheets
   */
  public boolean isAutocompleteOnlyTaskBookableForTimesheets()
  {
    return autocompleteOnlyTaskBookableForTimesheets;
  }
}