/*
 * Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Eike Stepper - initial API and implementation
 */
package org.eclipse.userstorage.internal;

import org.eclipse.userstorage.IBlob;
import org.eclipse.userstorage.IStorage;
import org.eclipse.userstorage.IStorageService;
import org.eclipse.userstorage.StorageFactory;
import org.eclipse.userstorage.internal.util.IOUtil;
import org.eclipse.userstorage.internal.util.IOUtil.TeeInputStream;
import org.eclipse.userstorage.internal.util.StringUtil;
import org.eclipse.userstorage.spi.ICredentialsProvider;
import org.eclipse.userstorage.spi.ISettings;
import org.eclipse.userstorage.spi.StorageCache;
import org.eclipse.userstorage.util.BadApplicationTokenException;
import org.eclipse.userstorage.util.ConflictException;
import org.eclipse.userstorage.util.NoServiceException;
import org.eclipse.userstorage.util.NotFoundException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author Eike Stepper
 */
public final class Storage implements IStorage
{
  private static final String DEFAULT_APPLICATION_TOKEN = "<default>";

  private static final int CHUNK_SIZE = 100;

  private final List<Listener> listeners = new CopyOnWriteArrayList<Listener>();

  private final String applicationToken;

  private final StorageFactory factory;

  private final InternalStorageCache cache;

  private final Map<String, Blob> blobs = new WeakHashMap<String, Blob>();

  private StorageService service;

  private ICredentialsProvider credentialsProvider;

  public Storage(StorageFactory factory, String applicationToken, InternalStorageCache cache) throws BadApplicationTokenException
  {
    this.applicationToken = BadApplicationTokenException.validate(applicationToken);
    this.factory = factory;
    this.cache = cache;

    StorageServiceRegistry.INSTANCE.addStorage(this);
  }

  @Override
  public String getApplicationToken()
  {
    return applicationToken;
  }

  @Override
  public StorageFactory getFactory()
  {
    return factory;
  }

  @Override
  public StorageCache getCache()
  {
    return (StorageCache)cache;
  }

  @Override
  public StorageService getService()
  {
    StorageService oldService;
    StorageService newService;

    synchronized (this)
    {
      oldService = service;
      newService = oldService;

      if (newService != null)
      {
        URI serviceURI = newService.getServiceURI();
        service = newService = StorageServiceRegistry.INSTANCE.getService(serviceURI);
      }

      if (newService == null)
      {
        service = newService = lookupService();
        if (cache != null)
        {
          cache.setService(newService);
        }
      }
    }

    notifyListeners(oldService, newService);
    return newService;
  }

  @Override
  public void setService(IStorageService service)
  {
    StorageService oldService;

    synchronized (this)
    {
      oldService = this.service;

      if (service != oldService)
      {
        disposeBlobs();

        this.service = (StorageService)service;

        String serviceURI = service == null ? null : service.getServiceURI().toString();
        setServiceURI(serviceURI);

        if (cache != null)
        {
          cache.setService(service);
        }
      }
    }

    notifyListeners(oldService, service);
  }

  @Override
  public ICredentialsProvider getCredentialsProvider()
  {
    return credentialsProvider;
  }

  @Override
  public void setCredentialsProvider(ICredentialsProvider credentialsProvider)
  {
    this.credentialsProvider = credentialsProvider;
  }

  @Override
  public Iterable<IBlob> getBlobs() throws IOException
  {
    return new Iterable<IBlob>()
    {
      @Override
      public Iterator<IBlob> iterator()
      {
        return new Iterator<IBlob>()
        {
          private int page;

          private boolean lastChunk;

          private boolean endReached;

          private Iterator<IBlob> chunk;

          private RuntimeException exception;

          @Override
          public boolean hasNext()
          {
            for (;;)
            {
              if (endReached)
              {
                return false;
              }

              if (exception != null)
              {
                throw exception;
              }

              if (chunk != null)
              {
                if (chunk.hasNext())
                {
                  return true;
                }

                if (lastChunk)
                {
                  endReached = true;
                  return false;
                }
              }

              try
              {
                List<IBlob> blobs = getBlobs(CHUNK_SIZE, ++page);
                if (blobs.size() < CHUNK_SIZE)
                {
                  lastChunk = true;
                }

                chunk = blobs.iterator();
              }
              catch (NotFoundException ex)
              {
                chunk = null;
                endReached = true;
              }
              catch (IOException ex)
              {
                chunk = null;
                exception = new RuntimeException(ex);
              }
            }
          }

          @Override
          public IBlob next()
          {
            hasNext();
            return chunk.next();
          }

          @Override
          public void remove()
          {
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }

  @Override
  public List<IBlob> getBlobs(int pageSize, int page) throws IOException, NotFoundException
  {
    List<IBlob> blobs = new ArrayList<IBlob>();

    StorageService service = getServiceSafe();
    Map<String, Map<String, Object>> properties = service.retrieveProperties(credentialsProvider, applicationToken, pageSize, page);

    for (Map.Entry<String, Map<String, Object>> entry : properties.entrySet())
    {
      String key = entry.getKey();
      Map<String, Object> value = entry.getValue();

      Blob blob = (Blob)getBlob(key);
      blob.setProperties(value);

      blobs.add(blob);
    }

    return blobs;
  }

  @Override
  public IBlob getBlob(String key)
  {
    synchronized (this)
    {
      Blob blob = blobs.get(key);
      if (blob == null)
      {
        Map<String, String> properties = new HashMap<String, String>();

        if (cache != null)
        {
          try
          {
            cache.internalLoadProperties(applicationToken, key, properties);
          }
          catch (IOException ex)
          {
            properties.clear();
            Activator.log(ex);
          }
        }

        blob = new Blob(this, key, properties);
        blobs.put(key, blob);
      }

      return blob;
    }
  }

  @Override
  public void addListener(Listener listener)
  {
    listeners.add(listener);
  }

  @Override
  public void removeListener(Listener listener)
  {
    listeners.remove(listener);
  }

  public void setETag(String key, Map<String, String> properties, String eTag)
  {
    if (StringUtil.isEmpty(eTag))
    {
      properties.remove(Blob.ETAG);
    }
    else
    {
      properties.put(Blob.ETAG, eTag);
    }

    if (cache != null)
    {
      try
      {
        if (!StringUtil.isEmpty(eTag))
        {
          Map<String, String> cacheProperties = new HashMap<String, String>();
          cache.loadProperties(applicationToken, key, cacheProperties);
          String cacheETag = cacheProperties.get(Blob.ETAG);
          if (eTag.equals(cacheETag))
          {
            // Don't delete blob from cache because it has the new ETag.
            return;
          }
        }

        cache.internalDelete(applicationToken, key);
      }
      catch (IOException ex)
      {
        Activator.log(ex);
      }
    }
  }

  public InputStream retrieveBlob(String key, Map<String, String> properties) throws IOException, NoServiceException
  {
    InputStream cacheStream = null;
    if (cache != null)
    {
      try
      {
        cacheStream = cache.internalGetInputStream(applicationToken, key);
      }
      catch (IOException ex)
      {
        Activator.log(ex);
      }
    }

    try
    {
      StorageService service = getServiceSafe();
      InputStream contents = service.retrieveBlob(credentialsProvider, applicationToken, key, properties, cacheStream != null);

      if (cacheStream != null)
      {
        if (contents == Blob.NOT_MODIFIED)
        {
          InputStream cacheStreamResult = cacheStream;
          cacheStream = null; // Avoid closing the result stream in the finally block
          return cacheStreamResult;
        }

        OutputStream output = cache.internalGetOutputStream(applicationToken, key, properties);
        return new TeeInputStream(contents, output);
      }

      return contents;
    }
    catch (NotFoundException ex)
    {
      if (cache != null)
      {
        cache.internalDelete(applicationToken, key);
      }

      throw ex;
    }
    finally
    {
      IOUtil.closeSilent(cacheStream);
    }
  }

  public boolean updateBlob(String key, Map<String, String> properties, InputStream in) throws IOException, NoServiceException, ConflictException
  {
    StorageService service = getServiceSafe();

    if (cache != null)
    {
      OutputStream output = cache.internalGetOutputStream(applicationToken, key, properties);
      in = new TeeInputStream(in, output);
    }

    boolean created;

    try
    {
      created = service.updateBlob(credentialsProvider, applicationToken, key, properties, in);
    }
    catch (ConflictException ex)
    {
      properties.clear();

      if (cache != null)
      {
        cache.internalDelete(applicationToken, key);
      }

      throw ex;
    }

    if (cache != null)
    {
      cache.internalSaveProperties(applicationToken, key, properties);
    }

    return created;
  }

  public boolean deleteBlob(String key, Map<String, String> properties) throws IOException, NoServiceException, ConflictException
  {
    StorageService service = getServiceSafe();
    boolean deleted = service.deleteBlob(credentialsProvider, applicationToken, key, properties);

    if (cache != null)
    {
      cache.internalDelete(applicationToken, key);
    }

    return deleted;
  }

  @Override
  public boolean deleteAllBlobs() throws IOException, NoServiceException
  {
    boolean deleted = false;

    for (;;)
    {
      List<IBlob> blobs = getBlobs(100, 1);
      if (blobs.isEmpty())
      {
        break;
      }

      for (IBlob blob : blobs)
      {
        blob.delete();
        deleted = true;
      }
    }

    return deleted;
  }

  @Override
  public String toString()
  {
    return service + " (" + applicationToken + ")";
  }

  void serviceRemoved(IStorageService service)
  {
    if (this.service == service)
    {
      setService(null);
    }
  }

  private StorageService getServiceSafe() throws NoServiceException
  {
    StorageService service = getService();
    if (service != null)
    {
      return service;
    }

    throw new NoServiceException();
  }

  private StorageService lookupService()
  {
    if (!StringUtil.isEmpty(applicationToken))
    {
      StorageService service = lookupService(applicationToken);
      if (service != null)
      {
        return service;
      }
    }

    StorageService service = lookupService(DEFAULT_APPLICATION_TOKEN);
    if (service != null)
    {
      return service;
    }

    return StorageServiceRegistry.INSTANCE.getFirstService();
  }

  private StorageService lookupService(String applicationToken)
  {
    try
    {
      String serviceURI = getServiceURI(applicationToken);
      if (serviceURI != null)
      {
        return StorageServiceRegistry.INSTANCE.getService(StringUtil.newURI(serviceURI));
      }
    }
    catch (Exception ex)
    {
      //$FALL-THROUGH$
    }

    return null;
  }

  private String getServiceURI(String applicationToken)
  {
    try
    {
      ISettings settings = factory.getSettings();
      return settings.getValue(applicationToken);
    }
    catch (Exception ex)
    {
      Activator.log(ex);
    }

    return null;
  }

  private void setServiceURI(String serviceURI)
  {
    try
    {
      ISettings settings = factory.getSettings();
      settings.setValue(applicationToken, serviceURI);
    }
    catch (Exception ex)
    {
      Activator.log(ex);
    }
  }

  private void notifyListeners(IStorageService oldService, IStorageService newService)
  {
    if (oldService != newService)
    {
      for (Listener listener : listeners)
      {
        try
        {
          listener.serviceChanged(this, oldService, newService);
        }
        catch (Exception ex)
        {
          Activator.log(ex);
        }
      }
    }
  }

  private void disposeBlobs()
  {
    for (Blob blob : blobs.values())
    {
      blob.dispose();
    }

    blobs.clear();

    if (cache != null)
    {
      try
      {
        for (Iterator<String> it = cache.getKeys(applicationToken); it.hasNext();)
        {
          String key = it.next();

          try
          {
            cache.delete(applicationToken, key);
          }
          catch (Exception ex)
          {
            Activator.log(ex);
          }
        }
      }
      catch (Exception ex)
      {
        Activator.log(ex);
      }
    }
  }
}
