/*
 * Copyright (C) 2003-2011 eXo Platform SAS.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program 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.exoplatform.social.core.activity;

import java.util.Collections;
import java.util.List;

import org.exoplatform.social.common.RealtimeListAccess;
import org.exoplatform.social.core.activity.model.ExoSocialActivity;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.storage.api.ActivityStorage;

/**
 * The real time list access for activities.
 *
 * @author <a href="http://hoatle.net">hoatle (hoatlevan at gmail dot com)</a>
 * @since Apr 8, 2011
 */
public class ActivitiesRealtimeListAccess implements RealtimeListAccess<ExoSocialActivity> {

  public enum ActivityType {
    ACTIVITY_FEED,
    USER_ACTIVITIES,
    VIEW_USER_ACTIVITIES,
    CONNECTIONS_ACTIVITIES,
    USER_SPACE_ACTIVITIES,
    SPACE_ACTIVITIES,
    POSTER_ACTIVITIES,
    POSTER_AND_TYPES_ACTIVITIES,
    ALL
  }

  /**
   * The activity activityStorage.
   */
  private ActivityStorage activityStorage;

  /**
   * The chosen activity type.
   */
  private ActivityType    activityType;

  /**
   * The chosen identity.
   */
  private Identity        ownerIdentity;

  /**
   * The viewer identity.
   */
  private Identity        viewerIdentity;

  private String[]        activityTypes;

  /**
   * The activity stream type.
   */
  private ActivityFilter  activityFilter;

  /**
   * Constructor.
   *
   * @param existingActivityStorage
   * @param chosenActivityType
   */
  public ActivitiesRealtimeListAccess(final ActivityStorage existingActivityStorage,
                                      final ActivityType chosenActivityType) {
    this.activityStorage = existingActivityStorage;
    this.activityType = chosenActivityType;
  }

  /**
   * Constructor.
   *
   * @param existingActivityStorage
   * @param chosenActivityType
   * @param chosenOwnerIdentity
   */
  public ActivitiesRealtimeListAccess(final ActivityStorage existingActivityStorage,
                                      final ActivityType chosenActivityType,
                                      final Identity chosenOwnerIdentity) {
    this.activityStorage = existingActivityStorage;
    this.activityType = chosenActivityType;
    this.ownerIdentity = chosenOwnerIdentity;
  }

  /**
   * Constructor.
   *
   * @param existingActivityStorage
   * @param chosenActivityType
   * @param chosenOwnerIdentity
   * @param activityTypes
   */
  public ActivitiesRealtimeListAccess(final ActivityStorage existingActivityStorage,
                                      final ActivityType chosenActivityType,
                                      final Identity chosenOwnerIdentity,
                                      final String... activityTypes) {
    this.activityStorage = existingActivityStorage;
    this.activityType = chosenActivityType;
    this.ownerIdentity = chosenOwnerIdentity;
    this.activityTypes = activityTypes;
  }

  /**
   * Constructor.
   *
   * @param existingActivityStorage
   * @param chosenActivityType
   * @param chosenOwnerIdentity
   * @param viewerIndentity viewer gets and show other owner stream
   */
  public ActivitiesRealtimeListAccess(final ActivityStorage existingActivityStorage,
                                      final ActivityType chosenActivityType,
                                      final Identity chosenOwnerIdentity,
                                      final Identity viewerIndentity) {
    this.activityStorage = existingActivityStorage;
    this.activityType = chosenActivityType;
    this.ownerIdentity = chosenOwnerIdentity;
    this.viewerIdentity = viewerIndentity;
  }

  /**
   * Constructor.
   *
   * @param activityStorage
   * @param viewerIdentity
   * @param activityFilter
   */
  public ActivitiesRealtimeListAccess(ActivityStorage activityStorage,
                                      Identity viewerIdentity,
                                      ActivityFilter activityFilter) {
    this.activityStorage = activityStorage;
    this.viewerIdentity = viewerIdentity;
    this.activityFilter = activityFilter;
  }

  @Override
  public List<String> loadIdsAsList(int index, int limit) {
    if (activityFilter != null) {
      return activityStorage.getActivityIdsByFilter(viewerIdentity, activityFilter, index, limit);
    } else if (activityType != null) {
      switch (activityType) {
      case ACTIVITY_FEED: {
        return activityStorage.getActivityIdsFeed(ownerIdentity, index, limit);
      }
      case USER_ACTIVITIES: {
        return activityStorage.getUserIdsActivities(ownerIdentity, index, limit);
      }
      case VIEW_USER_ACTIVITIES: {
        return activityStorage.getActivities(ownerIdentity, viewerIdentity, index, limit)
                              .stream()
                              .map(ExoSocialActivity::getId)
                              .toList();
      }
      case CONNECTIONS_ACTIVITIES: {
        return activityStorage.getActivityIdsOfConnections(ownerIdentity, index, limit);
      }
      case USER_SPACE_ACTIVITIES: {
        return activityStorage.getUserSpacesActivityIds(ownerIdentity, index, limit);
      }
      case SPACE_ACTIVITIES: {
        return activityStorage.getSpaceActivityIds(ownerIdentity, index, limit);
      }
      default:
        return Collections.emptyList();
      }
    } else {
      return Collections.emptyList();
    }
  }

  /**
   * {@inheritDoc}
   */
  public List<ExoSocialActivity> loadAsList(int index, int limit) {
    if (activityFilter != null) {
      return activityStorage.getActivitiesByFilter(viewerIdentity, activityFilter, index, limit);
    } else if (activityType != null) {
      switch (activityType) {
      case ACTIVITY_FEED: {
        return activityStorage.getActivityFeed(ownerIdentity, index, limit);
      }
      case USER_ACTIVITIES: {
        return activityStorage.getUserActivities(ownerIdentity, index, limit);
      }
      case VIEW_USER_ACTIVITIES: {
        return activityStorage.getActivities(ownerIdentity, viewerIdentity, index, limit);
      }
      case CONNECTIONS_ACTIVITIES: {
        return activityStorage.getActivitiesOfConnections(ownerIdentity, index, limit);
      }
      case USER_SPACE_ACTIVITIES: {
        return activityStorage.getUserSpacesActivities(ownerIdentity, index, limit);
      }
      case SPACE_ACTIVITIES: {
        return activityStorage.getSpaceActivities(ownerIdentity, index, limit);
      }
      case POSTER_ACTIVITIES: {
        return activityStorage.getActivitiesByPoster(ownerIdentity, index, limit);
      }
      case POSTER_AND_TYPES_ACTIVITIES: {
        return activityStorage.getActivitiesByPoster(ownerIdentity, index, limit, activityTypes);
      }
      case ALL: {
        return activityStorage.getAllActivities(index, limit);
      }
      default:
        return Collections.emptyList();
      }
    } else {
      return Collections.emptyList();
    }
  }

  /**
   * {@inheritDoc}
   */
  public ExoSocialActivity[] load(int index, int limit) {
    return RealtimeListAccess.convertListToArray(loadAsList(index, limit), ExoSocialActivity.class);
  }

  /**
   * {@inheritDoc}
   */
  public int getSize() {
    if (activityFilter != null) {
      return activityStorage.getActivitiesCountByFilter(viewerIdentity, activityFilter);
    } else if (activityType != null) {
      switch (activityType) {
      case ACTIVITY_FEED: {
        return activityStorage.getNumberOfActivitesOnActivityFeed(ownerIdentity);
      }
      case USER_ACTIVITIES: {
        return activityStorage.getNumberOfUserActivities(ownerIdentity);
      }
      case CONNECTIONS_ACTIVITIES: {
        return activityStorage.getNumberOfActivitiesOfConnections(ownerIdentity);
      }
      case USER_SPACE_ACTIVITIES: {
        return activityStorage.getNumberOfUserSpacesActivities(ownerIdentity);
      }
      case SPACE_ACTIVITIES: {
        return activityStorage.getNumberOfSpaceActivities(ownerIdentity);
      }
      case POSTER_ACTIVITIES: {
        return activityStorage.getNumberOfActivitiesByPoster(ownerIdentity);
      }
      case POSTER_AND_TYPES_ACTIVITIES: {
        return 0;
      }
      case VIEW_USER_ACTIVITIES: {
        return activityStorage.getNumberOfActivitiesByPoster(ownerIdentity, viewerIdentity);
      }
      }
    }
    return 0;
  }

  /**
   * {@inheritDoc}
   */
  public List<ExoSocialActivity> loadNewer(ExoSocialActivity baseActivity, int length) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNewerOnActivityFeed(ownerIdentity, baseActivity, length);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNewerOnUserActivities(ownerIdentity, baseActivity, length);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNewerOnActivitiesOfConnections(ownerIdentity, baseActivity, length);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNewerOnUserSpacesActivities(ownerIdentity, baseActivity, length);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNewerOnSpaceActivities(ownerIdentity, baseActivity, length);
    }
    }
    return Collections.emptyList();
  }

  /**
   * {@inheritDoc}
   */
  public int getNumberOfNewer(ExoSocialActivity baseActivity) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNumberOfNewerOnActivityFeed(ownerIdentity, baseActivity);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnUserActivities(ownerIdentity, baseActivity);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnActivitiesOfConnections(ownerIdentity, baseActivity);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnUserSpacesActivities(ownerIdentity, baseActivity);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnSpaceActivities(ownerIdentity, baseActivity);
    }
    }
    return 0;
  }

  /**
   * {@inheritDoc}
   */
  public List<ExoSocialActivity> loadOlder(ExoSocialActivity baseActivity, int length) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getOlderOnActivityFeed(ownerIdentity, baseActivity, length);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getOlderOnUserActivities(ownerIdentity, baseActivity, length);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getOlderOnActivitiesOfConnections(ownerIdentity, baseActivity, length);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getOlderOnUserSpacesActivities(ownerIdentity, baseActivity, length);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getOlderOnSpaceActivities(ownerIdentity, baseActivity, length);
    }
    }
    return Collections.emptyList();
  }

  /**
   * {@inheritDoc}
   */
  public int getNumberOfOlder(ExoSocialActivity baseActivity) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNumberOfOlderOnActivityFeed(ownerIdentity, baseActivity);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnUserActivities(ownerIdentity, baseActivity);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnActivitiesOfConnections(ownerIdentity, baseActivity);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnUserSpacesActivities(ownerIdentity, baseActivity);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnSpaceActivities(ownerIdentity, baseActivity);
    }
    }
    return 0;
  }

  /**
   * {@inheritDoc}
   */
  public int getNumberOfNewer(Long sinceTime) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNumberOfNewerOnActivityFeed(ownerIdentity, sinceTime);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnUserActivities(ownerIdentity, sinceTime);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnActivitiesOfConnections(ownerIdentity, sinceTime);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnUserSpacesActivities(ownerIdentity, sinceTime);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfNewerOnSpaceActivities(ownerIdentity, sinceTime);
    }
    }
    return 0;
  }

  public List<ExoSocialActivity> getUpadtedActivities(Long sinceTime, int limit) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNewerFeedActivities(ownerIdentity, sinceTime, limit);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNewerUserActivities(ownerIdentity, sinceTime, limit);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNewerActivitiesOfConnections(ownerIdentity, sinceTime, limit);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNewerUserSpacesActivities(ownerIdentity, sinceTime, limit);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNewerSpaceActivities(ownerIdentity, sinceTime, limit);
    }
    }
    return Collections.emptyList();
  }

  /**
   * {@inheritDoc}
   */
  public List<ExoSocialActivity> loadNewer(Long sinceTime, int limit) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNewerFeedActivities(ownerIdentity, sinceTime, limit);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNewerUserActivities(ownerIdentity, sinceTime, limit);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNewerActivitiesOfConnections(ownerIdentity, sinceTime, limit);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNewerUserSpacesActivities(ownerIdentity, sinceTime, limit);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNewerSpaceActivities(ownerIdentity, sinceTime, limit);
    }
    }
    return Collections.emptyList();
  }

  /**
   * {@inheritDoc}
   */
  public List<ExoSocialActivity> loadOlder(Long sinceTime, int limit) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getOlderFeedActivities(ownerIdentity, sinceTime, limit);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getOlderUserActivities(ownerIdentity, sinceTime, limit);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getOlderActivitiesOfConnections(ownerIdentity, sinceTime, limit);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getOlderUserSpacesActivities(ownerIdentity, sinceTime, limit);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getOlderSpaceActivities(ownerIdentity, sinceTime, limit);
    }
    }
    return Collections.emptyList();
  }

  /**
   * {@inheritDoc}
   */
  public int getNumberOfOlder(Long sinceTime) {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNumberOfOlderOnActivityFeed(ownerIdentity, sinceTime);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnUserActivities(ownerIdentity, sinceTime);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnActivitiesOfConnections(ownerIdentity, sinceTime);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnUserSpacesActivities(ownerIdentity, sinceTime);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfOlderOnSpaceActivities(ownerIdentity, sinceTime);
    }
    }
    return 0;
  }

  /**
   * {@inheritDoc}
   */
  public int getNumberOfUpgrade() {
    switch (activityType) {
    case ACTIVITY_FEED: {
      return activityStorage.getNumberOfActivitesOnActivityFeedForUpgrade(ownerIdentity);
    }
    case USER_ACTIVITIES: {
      return activityStorage.getNumberOfUserActivitiesForUpgrade(ownerIdentity);
    }
    case CONNECTIONS_ACTIVITIES: {
      return activityStorage.getNumberOfActivitiesOfConnectionsForUpgrade(ownerIdentity);
    }
    case USER_SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfUserSpacesActivitiesForUpgrade(ownerIdentity);
    }
    case SPACE_ACTIVITIES: {
      return activityStorage.getNumberOfSpaceActivitiesForUpgrade(ownerIdentity);
    }
    case POSTER_ACTIVITIES: {
      return activityStorage.getNumberOfActivitiesByPoster(ownerIdentity);
    }
    case POSTER_AND_TYPES_ACTIVITIES: {
      return 0;
    }
    case VIEW_USER_ACTIVITIES: {
      return activityStorage.getNumberOfActivitiesByPoster(ownerIdentity, viewerIdentity);
    }
    }
    return 0;
  }

}
