/*
 * Copyright (c) 2016, 2017 Ed Merks (Berlin, Germany) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v20.html
 *
 * Contributors:
 *    Ed Merks - initial API and implementation
 */
package org.eclipse.oomph.setup.internal.core.util;

import org.eclipse.oomph.base.Annotation;
import org.eclipse.oomph.base.BaseFactory;
import org.eclipse.oomph.base.BasePackage;
import org.eclipse.oomph.base.util.ArchiveResourceImpl;
import org.eclipse.oomph.base.util.BaseResourceFactoryImpl;
import org.eclipse.oomph.base.util.BaseUtil;
import org.eclipse.oomph.internal.setup.SetupProperties;
import org.eclipse.oomph.setup.Index;
import org.eclipse.oomph.setup.internal.core.SetupContext;
import org.eclipse.oomph.util.ObjectUtil;
import org.eclipse.oomph.util.PropertiesUtil;
import org.eclipse.oomph.util.StringUtil;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;

import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author Ed Merks
 */
public class IndexManager
{
  private static URI DEFAULT_INDEX_LOCATION = URI
      .createURI("archive:http://www.eclipse.org/setups/setups.zip!/http/git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/org.eclipse.setup");

  private final ResourceSet resourceSet = new ResourceSetImpl();

  private final URI indicesLocation;

  private final Resource indicesResource;

  private final IndexManager globalIndexManager;

  public IndexManager()
  {
    this(SetupContext.CONFIGURATION_STATE_LOCATION_URI.appendSegment("indices.xmi"),
        new IndexManager(SetupContext.GLOBAL_SETUPS_LOCATION_URI.appendSegment("indices.xmi"), null));
  }

  private IndexManager(URI indicesLocation, IndexManager globalIndexManager)
  {
    resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new BaseResourceFactoryImpl());
    this.indicesLocation = indicesLocation;
    indicesResource = resourceSet.createResource(indicesLocation);
    this.globalIndexManager = globalIndexManager;
  }

  public IndexManager getGlobalIndexManager()
  {
    return globalIndexManager;
  }

  public boolean addIndex(Index index)
  {
    Resource resource = index.eResource();
    URI uri = resource.getURI();
    URIConverter uriConverter = resource.getResourceSet().getURIConverter();
    URI indexLocation = uriConverter.normalize(uri);

    return addIndex(indexLocation, index.getName(), false);
  }

  public boolean addIndex(URI indexLocation, String name, boolean local)
  {
    if (!local && globalIndexManager != null)
    {
      globalIndexManager.addIndex(indexLocation, name, true);
    }

    Annotation annotation = getAnnotation();
    EMap<String, String> details = annotation.getDetails();
    String oldName = details.put(indexLocation.toString(), name);

    int entryIndex = details.indexOfKey(indexLocation.toString());
    if (entryIndex != 0)
    {
      details.move(0, entryIndex);
    }

    save(annotation);

    return !ObjectUtil.equals(oldName, name);
  }

  public void remove(URI indexLocation, boolean local)
  {
    if (!local && globalIndexManager != null)
    {
      globalIndexManager.remove(indexLocation, true);
    }

    Annotation annotation = getAnnotation();
    Annotation labelsAnnotation = annotation.getAnnotation("labels");

    annotation.getDetails().removeKey(indexLocation.toString());
    if (labelsAnnotation != null)
    {
      labelsAnnotation.getDetails().removeKey(indexLocation.toString());
    }

    save(annotation);
  }

  public void setLabel(URI indexLocation, String label, boolean local)
  {
    if (!local && globalIndexManager != null)
    {
      globalIndexManager.setLabel(indexLocation, label, true);
    }

    Annotation annotation = getAnnotation();
    Annotation labelsAnnotation = annotation.getAnnotation("labels");
    if (labelsAnnotation == null)
    {
      labelsAnnotation = BaseFactory.eINSTANCE.createAnnotation();
      labelsAnnotation.setSource("labels");
      annotation.getAnnotations().add(labelsAnnotation);
    }

    labelsAnnotation.getDetails().put(indexLocation.toString(), label);

    save(annotation);
  }

  public void configure(ResourceSet resourceSet)
  {
    // If there are any filter properties in place, we have to assume that we're in a crippled installer
    // or in an application that has specified exactly the index they want to use in this application,
    // so don't switch the most recently used index in this case.
    if (StringUtil.isEmpty(PropertiesUtil.getProperty(SetupProperties.PROP_SETUP_PRODUCT_CATALOG_FILTER))
        && StringUtil.isEmpty(PropertiesUtil.getProperty(SetupProperties.PROP_SETUP_PRODUCT_FILTER))
        && StringUtil.isEmpty(PropertiesUtil.getProperty(SetupProperties.PROP_SETUP_PRODUCT_VERSION_FILTER)))
    {
      // If the resource set is configured to use the default location...
      URI currentIndexLocation = resourceSet.getURIConverter().normalize(SetupContext.INDEX_SETUP_URI);
      if (currentIndexLocation.equals(DEFAULT_INDEX_LOCATION) || currentIndexLocation.equals(SetupContext.INDEX_SETUP_LOCATION_URI))
      {
        // If there are indices in the local indices.xmi...
        Annotation annotation = getAnnotation();
        EMap<String, String> details = annotation.getDetails();
        if (!details.isEmpty())
        {
          // If the first index location is different from the default location (which is already configured in the given resource set)
          // and the current index location is also already in present,
          // only then configure the resource set to use the first location,
          // which is the most recently used index for this application,
          // or, if it's the first time this application is executed,
          // the most recently used index for any application on this machine.
          URI indexLocation = URI.createURI(details.get(0).getKey());
          if (!indexLocation.equals(DEFAULT_INDEX_LOCATION) && currentIndexLocation.equals(SetupContext.INDEX_SETUP_LOCATION_URI)
              || details.containsKey(currentIndexLocation.toString()) && !currentIndexLocation.equals(indexLocation))
          {
            configureForProxy(resourceSet, indexLocation);
          }
        }
      }
    }
  }

  public void configureForProxy(ResourceSet resourceSet, URI indexLocation)
  {
    // If the index location is an entry in an archive...
    if (indexLocation.isArchive())
    {
      // Configure for the resource set for the underlying archive as the whole.
      String authority = indexLocation.authority();
      URI archiveLocation = URI.createURI(authority.substring(0, authority.length() - 1));
      configure(resourceSet, archiveLocation);
    }
    else
    {
      // Configure the resource set to use the default archive location,
      // which the client may have already redirected in this resource set.
      configure(resourceSet, SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI);

      // Add a URI mapping to ensure that index folder maps to the folder of the specified index location.
      Map<URI, URI> uriMap = resourceSet.getURIConverter().getURIMap();
      uriMap.put(SetupContext.INDEX_ROOT_URI, indexLocation.trimSegments(1).appendSegment(""));
    }
  }

  public void configure(ResourceSet resourceSet, URI setupArchiveURI)
  {
    // Load the entry information in the archive.
    Resource archiveResource = new ArchiveResourceImpl(setupArchiveURI, resourceSet.getURIConverter());
    try
    {
      archiveResource.load(null);
    }
    catch (IOException ex)
    {
      // Ignore.
    }

    // This will be represented as an annotation.
    Annotation annotation = (Annotation)EcoreUtil.getObjectByType(archiveResource.getContents(), BasePackage.Literals.ANNOTATION);
    if (annotation != null && !annotation.getDetails().isEmpty())
    {
      // Clear any previous redirections and reestablish a clean set of redirections.
      URIConverter uriConverter = resourceSet.getURIConverter();
      Map<URI, URI> uriMap = uriConverter.getURIMap();
      uriMap.clear();
      SetupCoreUtil.configureRedirections(uriMap);

      // Redirect the default archive location to this archive's location.
      uriMap.put(SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI, setupArchiveURI);

      for (Map.Entry<String, String> entry : annotation.getDetails())
      {
        // Add mappings for each entry.
        URI sourceURI = URI.createURI(entry.getKey());
        if (sourceURI.equals(uriConverter.normalize(sourceURI)))
        {
          URI targtURI = URI.createURI(entry.getValue());
          uriMap.put(sourceURI, targtURI);

          // If this is the index resource itself...
          if (SetupContext.INDEX_SETUP_NAME.equals(sourceURI.lastSegment()))
          {
            // Map the index location to this location,
            // map the folder of the index location to this location's folder,
            // and map the whole index folder to this locations's folder.
            // This brute force approach is most likely to fully override any mappings that might already be in place in the resource set.
            uriMap.put(SetupContext.INDEX_SETUP_LOCATION_URI, targtURI);
            uriMap.put(SetupContext.INDEX_ROOT_LOCATION_URI, targtURI.trimSegments(1).appendSegment(""));
            uriMap.put(SetupContext.INDEX_ROOT_URI, targtURI.trimSegments(1).appendSegment(""));
          }
        }
      }
    }
  }

  public Map<URI, String> getIndexNames(boolean local)
  {
    Map<URI, String> result = new LinkedHashMap<URI, String>();
    Annotation annotation = getAnnotation();
    for (Map.Entry<String, String> detail : annotation.getDetails())
    {
      String name = detail.getValue();
      if (StringUtil.isEmpty(name))
      {
        name = "<unnamed-index>";
      }

      result.put(URI.createURI(detail.getKey()), name);
    }

    if (!local && globalIndexManager != null)
    {
      for (Map.Entry<URI, String> entry : globalIndexManager.getIndexNames(true).entrySet())
      {
        if (!result.containsKey(entry.getKey()))
        {
          result.put(entry.getKey(), entry.getValue());
        }
      }
    }

    return result;
  }

  public Map<URI, String> getIndexLabels(boolean local)
  {
    Annotation annotation = getAnnotation();
    Annotation labelsAnnotation = annotation.getAnnotation("labels");

    Map<URI, String> result = new LinkedHashMap<URI, String>();
    Set<String> labels = new HashSet<String>();
    Set<String> duplicates = new HashSet<String>();
    for (Map.Entry<String, String> detail : annotation.getDetails())
    {
      String label = null;
      String indexLocation = detail.getKey();
      if (labelsAnnotation != null)
      {
        label = labelsAnnotation.getDetails().get(indexLocation);
      }

      if (label == null)
      {
        String name = detail.getValue();
        if (!labels.add(name))
        {
          duplicates.add(name);
        }
      }

      result.put(URI.createURI(indexLocation), label);
    }

    for (Map.Entry<String, String> detail : annotation.getDetails())
    {
      URI indexLocation = URI.createURI(detail.getKey());
      if (result.get(indexLocation) == null)
      {
        String itemText = detail.getValue();
        if (StringUtil.isEmpty(itemText))
        {
          itemText = "<unnamed-index>";
        }

        if (duplicates.contains(itemText))
        {
          itemText += " - " + indexLocation;
        }

        result.put(indexLocation, itemText);
      }
    }

    if (!local && globalIndexManager != null)
    {
      for (Map.Entry<URI, String> entry : globalIndexManager.getIndexLabels(true).entrySet())
      {
        if (!result.containsKey(entry.getKey()))
        {
          result.put(entry.getKey(), entry.getValue());
        }
      }
    }

    return result;
  }

  public Map<URI, Boolean> getIndexAvailability(boolean local)
  {
    Map<URI, Boolean> result = new LinkedHashMap<URI, Boolean>();
    Set<URI> indexLocations = getIndexNames(local).keySet();
    URIConverter uriConverter = resourceSet.getURIConverter();
    for (URI indexLocation : indexLocations)
    {
      result.put(indexLocation, uriConverter.exists(indexLocation, null));
    }

    return result;
  }

  private Annotation getAnnotation()
  {
    BaseUtil.execute(5000, new Runnable()
    {
      public void run()
      {
        loadIndices();
      }
    }, resourceSet.getURIConverter(), indicesLocation);

    Annotation annotation = (Annotation)EcoreUtil.getObjectByType(indicesResource.getContents(), BasePackage.Literals.ANNOTATION);
    if (annotation == null)
    {
      annotation = createDefaultIndex();
    }

    return annotation;
  }

  private void loadIndices()
  {
    if (resourceSet.getURIConverter().exists(indicesLocation, null))
    {
      try
      {
        indicesResource.unload();
        indicesResource.load(resourceSet.getLoadOptions());
      }
      catch (IOException ex)
      {
        // Ignore.
      }

      Annotation annotation = (Annotation)EcoreUtil.getObjectByType(indicesResource.getContents(), BasePackage.Literals.ANNOTATION);
      if (annotation == null)
      {
        createDefaultIndex();
      }
    }
    else
    {
      createDefaultIndex();
    }
  }

  private Annotation createDefaultIndex()
  {
    Annotation annotation = null;
    if (globalIndexManager != null)
    {
      annotation = globalIndexManager.getAnnotation();
      if (annotation != null)
      {
        annotation = EcoreUtil.copy(annotation);
      }
    }

    if (annotation == null)
    {
      ResourceSet configuredResourceSet = SetupCoreUtil.createResourceSet();
      URI indexLocation = configuredResourceSet.getURIConverter().normalize(SetupContext.INDEX_SETUP_URI);
      annotation = BaseFactory.eINSTANCE.createAnnotation();
      annotation.setSource("IndexLocations");
      EMap<String, String> details = annotation.getDetails();
      details.put(indexLocation.toString(), "Eclipse");
    }

    EList<EObject> contents = indicesResource.getContents();
    contents.clear();
    contents.add(annotation);
    return annotation;
  }

  private void save(final Annotation annotation)
  {
    BaseUtil.execute(5000, new Runnable()
    {
      public void run()
      {
        BaseUtil.saveEObject(annotation);
      }
    }, resourceSet.getURIConverter(), indicesLocation);
  }

  public static URI getUnderlyingLocation(URI indexLocation)
  {
    if (indexLocation.isArchive())
    {
      String authority = indexLocation.authority();
      return URI.createURI(authority.substring(0, authority.length() - 1));
    }

    if (SetupContext.INDEX_SETUP_NAME.equals(indexLocation.lastSegment()))
    {
      return indexLocation.trimSegments(1).appendSegment("");
    }

    return indexLocation;
  }
}
