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

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.elog.api.LogTypes;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.model.ServiceContainerModel;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.presenter.OverviewPresenter;
import com.airlock.iam.servicecontainer.app.infrastructure.webapp.presenter.ServicePresenter;
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.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.server.Page;
import com.vaadin.server.Sizeable.Unit;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Image;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.v7.ui.Tree;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

public class ContentView extends VerticalLayout implements View {
   private static final String OVERVIEW = "overview";
   private static final ELogger LOG = ELoggerFactory.getLogger(ContentView.class);
   private Panel contentPanel;
   private final Navigator navigator;
   private final ServiceContainerModel serviceContainerModel;
   private OverviewView overviewView;
   private Panel menu;
   private Tree menuTree;

   public ContentView(Navigator navigator, ServiceContainerModel serviceContainerModel) {
      this.navigator = navigator;
      this.serviceContainerModel = serviceContainerModel;
   }

   public void init() {
      this.initComponents();
      this.initLayout();
   }

   private void initComponents() {
      OverviewPresenter overviewPresenter = new OverviewPresenter(this.serviceContainerModel);
      this.overviewView = new OverviewView(overviewPresenter);
      this.serviceContainerModel.createServicePresenters();
      this.serviceContainerModel.initServicePresenters();
   }

   private void initLayout() {
      this.contentPanel = new Panel();
      this.setSpacing(false);
      this.setMargin(false);
      this.setSizeFull();
      this.addComponent(this.getHeader());
      this.setMenu();
      HorizontalSplitPanel layout = new HorizontalSplitPanel();
      layout.setSizeFull();
      layout.setFirstComponent(this.menu);
      layout.setSplitPosition(300.0F, Unit.PIXELS);
      this.contentPanel.setHeight("100%");
      layout.setSecondComponent(this.contentPanel);
      this.addComponent(layout);
      this.setExpandRatio(layout, 1.0F);
   }

   private void setMenu() {
      this.menu = new Panel();
      this.menu.setHeight("100%");
      this.menuTree = new Tree();
      this.menuTree.setImmediate(true);
      this.menuTree.addStyleName(Css.SC_TREE.toString());
      this.menuTree.addValueChangeListener(event -> {
         ContentView.NavigationItem navigationItem = (ContentView.NavigationItem)this.menuTree.getValue();
         if (navigationItem != null) {
            this.navigator.navigateTo("/" + navigationItem.getIdentifier());
         }
      });
      this.initializeMenuTree();
      this.menu.setContent(this.menuTree);
   }

   private void initializeMenuTree() {
      List<ContentView.NavigationItem> navigationItems = new ArrayList<>();
      ContentView.NavigationItem overview = new ContentView.NavigationItem("overview", ServiceContainerVaadinTranslator.translate("overview.title"));
      this.menuTree.addItem(overview);
      this.menuTree.setChildrenAllowed(overview, false);
      navigationItems.add(overview);
      this.addServicesToNavigationTree(this.menuTree, navigationItems);
      this.selectNavigationItemBasedOnUrlFragment(this.menuTree, navigationItems, overview);
   }

   private void addServicesToNavigationTree(Tree tree, List<ContentView.NavigationItem> navigationItems) {
      for (Entry<String, ServicePresenter<?, ?>> entry : this.serviceContainerModel.getServicesToBePresented().entrySet()) {
         ContentView.NavigationItem navigationItem = new ContentView.NavigationItem(entry.getKey(), entry.getValue().getName());
         tree.addItem(navigationItem);
         tree.setChildrenAllowed(navigationItem, false);
         navigationItems.add(navigationItem);
      }
   }

   private void selectNavigationItemBasedOnUrlFragment(Tree tree, List<ContentView.NavigationItem> navigationItems, ContentView.NavigationItem overview) {
      String fragment = Page.getCurrent().getUriFragment();
      String path = "";
      if (fragment != null) {
         String[] splittedFragment = fragment.split("/");
         if (splittedFragment.length > 1) {
            path = splittedFragment[1];
         }
      }

      if ("".equals(path)) {
         tree.setValue(overview);
         tree.select(overview);
      } else {
         for (ContentView.NavigationItem navigationItem : navigationItems) {
            if (navigationItem.getIdentifier().equals(path)) {
               tree.select(navigationItem);
            }
         }
      }
   }

   private HorizontalLayout getHeader() {
      HorizontalLayout headerLayout = new HorizontalLayout();
      headerLayout.setSpacing(false);
      headerLayout.setWidth("100%");
      headerLayout.setMargin(new MarginInfo(false, true, false, false));
      headerLayout.addStyleName(Css.SC_HEADERUI.toString());
      Label title = new Label("Service Container");
      title.addStyleName(Css.SC_TITLE.toString());
      headerLayout.addComponent(title);
      Button logout = new Button(ServiceContainerVaadinTranslator.translate("logout"), event -> {
         this.getSession().close();
         this.getUI().getPage().setLocation("about:blank");
      });
      logout.setStyleName("link");
      Image logo = new Image(null, GuiResources.AIRLOCK_IAM_LOGO);
      logo.addStyleName("iam-logo");
      headerLayout.addComponent(logout);
      headerLayout.addComponent(logo);
      headerLayout.setExpandRatio(title, 1.0F);
      headerLayout.setComponentAlignment(logo, Alignment.MIDDLE_RIGHT);
      headerLayout.setComponentAlignment(logout, Alignment.BOTTOM_CENTER);
      return headerLayout;
   }

   public void enter(ViewChangeEvent event) {
      VerticalLayout panelContent = new VerticalLayout();
      panelContent.setSpacing(false);
      panelContent.setMargin(false);
      panelContent.setHeightUndefined();
      this.contentPanel.setContent(panelContent);
      if (event.getParameters() != null && !event.getParameters().isEmpty() && !event.getParameters().equals("overview")) {
         GenericServiceView view = this.serviceContainerModel.getViewForServicePresenter(event.getParameters());
         if (view != null) {
            panelContent.addComponent(view);
            panelContent.setComponentAlignment(view, Alignment.TOP_LEFT);
         } else {
            LOG.error(LogTypes.SERVER_INFO_SYS, "Couldn't display page with identifier " + event.getParameters());
            panelContent.addComponent(this.overviewView);
         }
      } else {
         panelContent.addComponent(this.overviewView);
      }
   }

   private void updateNavigation(ServiceContainerUI serviceContainerUI) {
      serviceContainerUI.access(() -> {
         this.serviceContainerModel.createServicePresenters();
         this.serviceContainerModel.initServicePresenters();
         this.menuTree.getUI().getSession().lock();
         this.menuTree.removeAllItems();
         List<ContentView.NavigationItem> navigationItems = new ArrayList<>();
         ContentView.NavigationItem overview = new ContentView.NavigationItem("overview", ServiceContainerVaadinTranslator.translate("overview.title"));
         this.menuTree.addItem(overview);
         this.menuTree.setChildrenAllowed(overview, false);
         navigationItems.add(overview);
         this.addServicesToNavigationTree(this.menuTree, navigationItems);
         this.menuTree.select(overview);
         this.navigator.navigateTo("/overview");
         this.menuTree.getUI().getSession().unlock();
      });
   }

   void update(ServiceContainerUI serviceContainerUI) {
      this.overviewView.update(serviceContainerUI);

      for (ServicePresenter<?, ?> servicePresenter : this.serviceContainerModel.getServicesToBePresented().values()) {
         servicePresenter.getView().update(serviceContainerUI);
      }

      if (this.serviceContainerModel.getServicesToBePresented().size() != this.serviceContainerModel.getServer().getServices().length) {
         this.updateNavigation(serviceContainerUI);
      }
   }

   static final class NavigationItem {
      private final String identifier;
      private final String name;

      public NavigationItem(String newIdentifier, String newName) {
         this.identifier = newIdentifier;
         this.name = newName;
      }

      public String getIdentifier() {
         return this.identifier;
      }

      @Override
      public String toString() {
         return this.name;
      }
   }
}
