package com.airlock.iam.servicecontainer.app.infrastructure.webapp.view;

import com.airlock.iam.servicecontainer.app.application.configuration.TaskSchedule;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.presenter.TaskSchedulerServicePresenter;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.util.Css;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.util.GuiResources;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.util.ServiceContainerVaadinTranslator;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.util.TranslatedKeyValueTable;
import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.v7.ui.ProgressBar;

public class TaskRepresentationUI {
   private static final String PLUGIN_DESCRIPTION_ITEM_ID = "taskschedulerservice.plugin-description";
   private static final String EXECUTION_INTERVAL_ITEM_ID = "taskschedulerservice.execution-interval";
   private static final String FIRST_EXECUTION_ITEM_ID = "taskschedulerservice.execution-first-time";
   private static final String NEXT_EXECUTION_ITEM_ID = "taskschedulerservice.execution-next";
   private static final String LATEST_EXECUTION_ITEM_ID = "taskschedulerservice.execution-latest";
   private final TaskSchedulerServicePresenter taskSchedulerServicePresenter;
   private final TaskSchedule taskSchedule;
   private final TaskNameUI taskName;
   private final VerticalLayout taskView;
   private final GridLayout taskBody;
   private Button startStopButton;
   private TranslatedKeyValueTable<String, String> infoTable;
   private TranslatedKeyValueTable<String, String> lastExecutionsTable;
   private final Label latestExecutionDateInHeader = new Label();
   private final Label latestExecutionStateInHeader = new Label();
   private ProgressBar progressBar;
   private Label progressPercentageLabel;
   private Button expandTaskButton;
   private final TaskRepresentationUI.TaskExpandClickListener expandTaskClickListener = new TaskRepresentationUI.TaskExpandClickListener();

   public TaskRepresentationUI(TaskSchedulerServicePresenter taskSchedulerServicePresenter, TaskSchedule taskSchedule) {
      this.taskSchedulerServicePresenter = taskSchedulerServicePresenter;
      this.taskSchedule = taskSchedule;
      this.taskName = TaskNameUI.taskNameUI(taskSchedule.getTaskName());
      this.taskView = new VerticalLayout();
      this.taskView.setSpacing(false);
      this.taskView.setMargin(false);
      this.taskView.addComponent(this.buildHeader());
      this.taskView.setId(this.taskName.taskHtmlId());
      this.taskBody = this.buildBody();
   }

   private GridLayout buildBody() {
      this.buildInformationTable();
      this.buildLastExecutionTable();
      this.buildProgressLayout();
      Label infoText = new Label(ServiceContainerVaadinTranslator.translate("taskschedulerservice.information"));
      infoText.addStyleName(Css.SC_SMALL_MARGIN_BOTTOM.toString());
      Label lastExecutionsText = new Label(ServiceContainerVaadinTranslator.translate("taskschedulerservice.last-executions"));
      lastExecutionsText.addStyleName(Css.SC_SMALL_MARGIN_BOTTOM.toString());
      GridLayout body = new GridLayout(2, 3);
      body.addComponent(this.progressBar);
      body.addComponent(this.progressPercentageLabel);
      body.addComponent(infoText);
      body.addComponent(lastExecutionsText);
      body.addComponent(this.infoTable);
      body.addComponent(this.lastExecutionsTable);
      body.setComponentAlignment(this.progressBar, Alignment.MIDDLE_LEFT);
      body.addStyleName(Css.SC_TASK_BODY.toString());
      return body;
   }

   private void buildProgressLayout() {
      this.progressBar = new ProgressBar();
      this.progressBar.setVisible(false);
      this.progressBar.setWidth("400px");
      this.progressPercentageLabel = new Label();
   }

   private void buildLastExecutionTable() {
      this.lastExecutionsTable = TranslatedKeyValueTable.buildTable();
      this.lastExecutionsTable.setWidth("400px");
      this.lastExecutionsTable.setColumnCollapsingAllowed(false);
   }

   private void buildInformationTable() {
      this.infoTable = TranslatedKeyValueTable.buildTable();
      this.infoTable.setWidth("400px");
      this.infoTable.setStyleName("sc-task-infotable");
      this.infoTable.addKeyValuePair("taskschedulerservice.plugin-description", this.taskSchedulerServicePresenter.getPluginDescription(this.taskSchedule));
      this.infoTable.addKeyValuePair("taskschedulerservice.execution-interval", this.taskSchedulerServicePresenter.getExecutionInterval(this.taskSchedule));
      this.infoTable.addKeyValuePair("taskschedulerservice.execution-first-time", this.taskSchedulerServicePresenter.getFirstExecutionTime(this.taskSchedule));
      this.infoTable.addKeyValuePair("taskschedulerservice.execution-next", this.taskSchedulerServicePresenter.getNextExecutionTime(this.taskSchedule));
      this.infoTable.addKeyValuePair("taskschedulerservice.execution-latest", this.taskSchedulerServicePresenter.getLatestExecutionTime(this.taskSchedule));
   }

   private HorizontalLayout buildHeader() {
      HorizontalLayout taskViewHeader = new HorizontalLayout();
      taskViewHeader.setSpacing(false);
      taskViewHeader.addStyleName(Css.SC_TASK.toString());
      taskViewHeader.setWidth("900px");
      taskViewHeader.setHeight("50px");
      this.expandTaskButton = this.buildExpandTaskButton();
      taskViewHeader.addComponent(this.expandTaskButton);
      Label title = new Label(this.taskSchedule.getTaskName());
      title.addStyleName("sc-task-title");
      CssLayout clickableContainer = new CssLayout(new Component[]{title});
      clickableContainer.setWidth("100%");
      clickableContainer.addStyleName("task-clickable");
      clickableContainer.addLayoutClickListener(this.expandTaskClickListener);
      taskViewHeader.addComponent(clickableContainer);
      HorizontalLayout latestExecutionHeader = new HorizontalLayout();
      latestExecutionHeader.setMargin(new MarginInfo(false, true, false, true));
      this.latestExecutionDateInHeader.setHeight("40px");
      this.latestExecutionDateInHeader.setContentMode(ContentMode.HTML);
      latestExecutionHeader.addComponent(this.latestExecutionDateInHeader);
      latestExecutionHeader.addComponent(this.latestExecutionStateInHeader);
      taskViewHeader.addComponent(latestExecutionHeader);
      taskViewHeader.setExpandRatio(clickableContainer, 1.0F);
      this.startStopButton = this.buildStartStopTaskButton();
      taskViewHeader.addComponent(this.startStopButton);
      return taskViewHeader;
   }

   private Button buildStartStopTaskButton() {
      Button button = new Button();
      button.addClickListener(event -> this.taskSchedulerServicePresenter.startStopTask(this.taskSchedule));
      button.setWidth("40px");
      button.addStyleName("borderless");
      button.setId(this.taskName.startStopTaskHtmlId());
      return button;
   }

   private Button buildExpandTaskButton() {
      Button button = new Button(GuiResources.ICON_TASK_EXPAND);
      button.setWidth("40px");
      button.addStyleName("borderless");
      button.addClickListener(this.expandTaskClickListener);
      return button;
   }

   void updateInfoTable() {
      this.infoTable.update("taskschedulerservice.plugin-description", this.taskSchedulerServicePresenter.getPluginDescription(this.taskSchedule));
      this.infoTable.update("taskschedulerservice.execution-interval", this.taskSchedulerServicePresenter.getExecutionInterval(this.taskSchedule));
      this.infoTable.update("taskschedulerservice.execution-first-time", this.taskSchedulerServicePresenter.getFirstExecutionTime(this.taskSchedule));
      this.infoTable.update("taskschedulerservice.execution-next", this.taskSchedulerServicePresenter.getNextExecutionTime(this.taskSchedule));
      this.infoTable.update("taskschedulerservice.execution-latest", this.taskSchedulerServicePresenter.getLatestExecutionTime(this.taskSchedule));
   }

   void updateProgress(int progressPercentage) {
      float progress = (float)(progressPercentage / 100.0);
      this.progressBar.setValue(progress);
      this.progressBar.setVisible(true);
      this.progressPercentageLabel.setValue(progressPercentage + "%");
   }

   void disableProgress() {
      this.progressBar.setVisible(false);
      this.progressBar.setValue(1.0F);
      this.progressPercentageLabel.setValue("");
   }

   void setStatusRunning() {
      this.startStopButton.setIcon(GuiResources.ICON_SERVICE_STOP);
      this.startStopButton.setDescription(ServiceContainerVaadinTranslator.translate("taskschedulerservice.stop-task"));
   }

   void setStatusIdle() {
      this.startStopButton.setIcon(GuiResources.ICON_SERVICE_START);
      this.startStopButton.setDescription(ServiceContainerVaadinTranslator.translate("taskschedulerservice.start-task"));
   }

   void setServiceRunnable(boolean runnable) {
      this.startStopButton.setEnabled(runnable);
   }

   boolean isTaskBodyAttached() {
      return this.taskBody.isAttached();
   }

   boolean isInfoTableAttached() {
      return this.infoTable.isAttached();
   }

   boolean isLastExecutionTableAttached() {
      return this.lastExecutionsTable.isAttached();
   }

   boolean isStartStopButAttached() {
      return this.startStopButton.isAttached();
   }

   int getNumberOfVisibleExecutionEntires() {
      return this.lastExecutionsTable.getItemIds().size();
   }

   void addLatestExecutionItem(String key, String value) {
      this.lastExecutionsTable.addKeyValuePair(key, value);
   }

   void setLatestExecutionItemForHeader(String key, String value) {
      this.latestExecutionDateInHeader.setValue(key);
      boolean isTaskSuccessful = "taskschedulerservice.ok".equals(value);
      this.latestExecutionStateInHeader.setIcon(isTaskSuccessful ? GuiResources.ICON_TASK_SUCCESS : GuiResources.ICON_TASK_FAILED);
      this.latestExecutionStateInHeader.setStyleName(isTaskSuccessful ? "sc-task-header-success" : "sc-task-header-failed");
      String successTooltip = ServiceContainerVaadinTranslator.translate("taskschedulerservice.execution-latest")
         + " "
         + ServiceContainerVaadinTranslator.translate("taskschedulerservice.ok");
      String failedTooltip = ServiceContainerVaadinTranslator.translate("taskschedulerservice.execution-latest")
         + " "
         + ServiceContainerVaadinTranslator.translate("taskschedulerservice.not-ok");
      this.latestExecutionStateInHeader.setDescription(isTaskSuccessful ? successTooltip : failedTooltip);
   }

   void clearLatestExecutionTable() {
      this.lastExecutionsTable.removeAllItems();
   }

   void setLastExecutionVisible(boolean isVisible) {
      this.lastExecutionsTable.setVisible(isVisible);
      Component lastExecutionsLabel = this.taskBody.getComponent(1, 1);
      if (lastExecutionsLabel != null) {
         lastExecutionsLabel.setVisible(isVisible);
      }
   }

   VerticalLayout getLayout() {
      return this.taskView;
   }

   private final class TaskExpandClickListener implements ClickListener, LayoutClickListener {
      private final TaskRepresentationUI ui = TaskRepresentationUI.this;
      private boolean expanded;

      TaskExpandClickListener() {
      }

      public void buttonClick(ClickEvent event) {
         this.click();
      }

      public void layoutClick(LayoutClickEvent event) {
         this.click();
      }

      private void click() {
         if (this.expanded) {
            this.compress();
         } else {
            this.expand();
         }
      }

      private void expand() {
         TaskRepresentationUI.this.taskView.addComponent(this.ui.taskBody);
         this.ui.expandTaskButton.setIcon(GuiResources.ICON_TASK_COMPRESS);
         this.expanded = true;
      }

      private void compress() {
         this.ui.taskView.removeComponent(this.ui.taskBody);
         this.ui.expandTaskButton.setIcon(GuiResources.ICON_TASK_EXPAND);
         this.expanded = false;
      }
   }
}
