/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.ui.share;

import android.app.Activity;
import android.app.ProgressDialog;
import android.view.View;
import android.view.View.OnClickListener;
import com.socialize.ShareUtils;
import com.socialize.Socialize;
import com.socialize.SocializeService;
import com.socialize.api.action.ShareType;
import com.socialize.api.action.share.ShareOptions;
import com.socialize.entity.Entity;
import com.socialize.entity.Share;
import com.socialize.error.SocializeException;
import com.socialize.i18n.I18NConstants;
import com.socialize.listener.share.ShareAddListener;
import com.socialize.networks.SocialNetwork;
import com.socialize.ui.actionbar.ActionBarView;
import com.socialize.ui.actionbar.OnActionBarEventListener;
import com.socialize.ui.dialog.AlertDialogFactory;
import com.socialize.ui.dialog.ProgressDialogFactory;

/**
 * @author Jason Polites
 *
 */
public class ShareClickListener implements OnClickListener {

	private ShareType shareType;
	private Activity context;
	private Entity entity;
	private ShareInfoProvider provider;
	private ProgressDialogFactory progressDialogFactory;
	private AlertDialogFactory alertDialogFactory;
	private OnActionBarEventListener onActionBarEventListener;
	private ActionBarView actionBarView;

	public ShareClickListener(Activity context) {
		super();
		this.context = context;
	}

	public ShareClickListener(
			Activity context,
			Entity entity,
			ShareType shareType,
			ShareInfoProvider provider,
			OnActionBarEventListener onActionBarEventListener,
			ActionBarView actionBarView) {
		this(context);
		this.shareType = shareType;
		this.entity = entity;
		this.provider = provider;
		this.onActionBarEventListener = onActionBarEventListener;
		this.actionBarView = actionBarView;
	}

	/* (non-Javadoc)
	 * @see android.view.View.OnClickListener#onClick(android.view.View)
	 */
	@Override
	public void onClick(View view) {
		final ProgressDialog dialog = progressDialogFactory.show(view.getContext(), I18NConstants.DLG_SHARE, I18NConstants.DLG_SHARE_MESSAGE + " " + shareType.getDisplayName() + "...");

		ShareOptions shareOptions = ShareUtils.getUserShareOptions(context);
		shareOptions.setText(provider.getShareText());

		ShareUtils.registerShare(context, entity, shareOptions, new ShareAddListener() {
			@Override
			public void onError(SocializeException error) {
				dialog.dismiss();
				alertDialogFactory.showToast(context, "Share failed.  Please try again");
			}

			@Override
			public void onCreate(Share share) {
				dialog.dismiss();
				if(onActionBarEventListener != null) {
					onActionBarEventListener.onPostShare(actionBarView, share);
				}
			}
		}, SocialNetwork.valueOf(shareType));
	}

	public void setProgressDialogFactory(ProgressDialogFactory progressDialogFactory) {
		this.progressDialogFactory = progressDialogFactory;
	}

	public void setAlertDialogFactory(AlertDialogFactory alertDialogFactory) {
		this.alertDialogFactory = alertDialogFactory;
	}

	public void setShareType(ShareType shareType) {
		this.shareType = shareType;
	}

	public void setEntity(Entity entity) {
		this.entity = entity;
	}

	public void setProvider(ShareInfoProvider provider) {
		this.provider = provider;
	}

	public void setOnActionBarEventListener(OnActionBarEventListener onActionBarEventListener) {
		this.onActionBarEventListener = onActionBarEventListener;
	}

	public void setActionBarView(ActionBarView actionBarView) {
		this.actionBarView = actionBarView;
	}

	protected SocializeService getSocialize() {
		return Socialize.getSocialize();
	}

}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.demo.implementations.action;

import com.socialize.ActionUtils;
import com.socialize.UserUtils;
import com.socialize.demo.SDKDemoActivity;
import com.socialize.entity.ListResult;
import com.socialize.entity.SocializeAction;
import com.socialize.error.SocializeException;
import com.socialize.listener.activity.ActionListListener;

/**
 * @author Jason Polites
 *
 */
public class GetActionsByUserActivity extends SDKDemoActivity {

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#executeDemo()
	 */
	@Override
	public void executeDemo(String text) {

		try {
			ActionUtils.getActionsByUser(this, UserUtils.getCurrentUser(this).getId(), 0, PAGE_SIZE, new ActionListListener() {

				@Override
				public void onList(ListResult<SocializeAction> result) {
					handleSocializeResult(result);
				}

				@Override
				public void onError(SocializeException error) {
					handleError(GetActionsByUserActivity.this, error);
				}
			});
		}
		catch (SocializeException e) {
			e.printStackTrace();
		}
	}

	@Override
	public boolean isTextEntryRequired() {
		return false;
	}

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#getButtonText()
	 */
	@Override
	public String getButtonText() {
		return "List " + PAGE_SIZE + " Actions for Current User";
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.i18n;

import android.content.Context;
import android.content.res.Resources;
import com.socialize.util.StringUtils;

import java.util.Map;
import java.util.TreeMap;

/**
 * @author Jason Polites
 *
 */
public class CustomLocalizationService implements LocalizationService {

	private static final Map<String, String> strings = new TreeMap<String, String>();

	private String packageName;
	private LocalizationService defaultLocalizationService;
	private Resources resources;

	public void init(Context context) {
		packageName = context.getPackageName();
		resources = context.getResources();
	}

	/* (non-Javadoc)
	 * @see com.socialize.i18n.LocalizationService#getString(java.lang.String)
	 */
	@Override
	public String getString(String key) {
		if(key == null) return "";
		String str = strings.get(key);
		if(StringUtils.isEmpty(str)) {
			int resId = resources.getIdentifier(key, "string", packageName);

			if(resId > 0) {
				try {
					str = resources.getString(resId);
				}
				catch (Exception e) {
					// Shouldn't happen
					e.printStackTrace();
				}
			}

			if(str == null) {
				// Get default
				str = defaultLocalizationService.getString(key);
			}

			if(str != null) {
				strings.put(key, str);
			}
			else {
				str = key;
			}
		}

		return str;
	}

	public void setDefaultLocalizationService(LocalizationService defaultLocalizationService) {
		this.defaultLocalizationService = defaultLocalizationService;
	}

}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.demo.implementations.comment;

import com.socialize.CommentUtils;
import com.socialize.UserUtils;
import com.socialize.demo.SDKDemoActivity;
import com.socialize.entity.Comment;
import com.socialize.entity.ListResult;
import com.socialize.error.SocializeException;
import com.socialize.listener.comment.CommentListListener;

/**
 * @author Jason Polites
 *
 */
public class GetCommentsByUserActivity extends SDKDemoActivity {

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#executeDemo()
	 */
	@Override
	public void executeDemo(String text) {

		try {
			CommentUtils.getCommentsByUser(this, UserUtils.getCurrentUser(this), 0, PAGE_SIZE, new CommentListListener() {

				@Override
				public void onList(ListResult<Comment> comments) {
					handleSocializeResult(comments);
				}

				@Override
				public void onError(SocializeException error) {
					handleError(GetCommentsByUserActivity.this, error);
				}
			});
		}
		catch (SocializeException e) {
			e.printStackTrace();
		}
	}

	@Override
	public boolean isTextEntryRequired() {
		return false;
	}

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#getButtonText()
	 */
	@Override
	public String getButtonText() {
		return "List " + PAGE_SIZE + " Comments for Current User";
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.notifications;

import android.app.Notification;
import android.content.Context;
import android.os.Bundle;
import com.socialize.api.SocializeSession;
import com.socialize.api.action.user.UserSystem;
import com.socialize.config.SocializeConfig;
import com.socialize.entity.JSONFactory;
import com.socialize.entity.User;
import com.socialize.error.SocializeException;
import com.socialize.log.SocializeLogger;
import com.socialize.ui.profile.UserSettings;
import com.socialize.util.AppUtils;
import com.socialize.util.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Map;

/**
 * @author Jason Polites
 */
public class SocializeC2DMCallback implements C2DMCallback {

	private int notificationIcon = android.R.drawable.sym_action_chat;

	private SocializeLogger logger;
	private SocializeConfig config;
	private AppUtils appUtils;
	private UserSystem userSystem;

	private Map<String, JSONFactory<NotificationMessage>> messageFactories;
	private Map<String, NotificationMessageBuilder> messageBuilders;
	private NotificationRegistrationState notificationRegistrationState;
	private NotificationRegistrationSystem notificationRegistrationSystem;
	private NotificationManagerFacade notificationManagerFacade;

	@Override
	public void onRegister(Context context, String registrationId)  {

		if(logger != null && logger.isInfoEnabled()) {
			logger.info("Registration with GCM successful: " + registrationId);

			if(logger.isDebugEnabled()) {
				logger.debug("GCM ID [" +
						registrationId +
						"]");
			}
		}
		notificationRegistrationState.setC2DMRegistrationId(registrationId);
		notificationRegistrationState.save(context);

		// Trigger socialize registration
		notificationRegistrationSystem.registerSocialize(context, registrationId);
	}

	@Override
	public void onError(Context context, String errorId) {
		if(logger != null && logger.isWarnEnabled()) {
			logger.warn("Registration with GCM failed: " + errorId);
		}
	}

	@Override
	public void onUnregister(Context context) {
		// Do nothing
	}

	/* (non-Javadoc)
	 * @see com.socialize.notifications.NotificationSystem#sendNotification(android.os.Bundle)
	 */
	@Override
	public void onMessage(final Context context, final Bundle data) {
		// DON'T Use Socialize instance here, we are using a different container!
		try {
			// This should be synchronous.  We don't want to launch an async task off the main UI thread.
			SocializeSession session = userSystem.authenticateSynchronous(context, config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_KEY), config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_SECRET));
			handleNotification(context, data, session);
		}
		catch (SocializeException e) {
			handleError("Failed to authenticate user for notification receipt", e);
		}
	}

	protected void handleNotification(final Context context, final Bundle data, final SocializeSession session) {

		final UserSettings settings = session.getUserSettings();
		final User user = session.getUser();

		if(settings != null && settings.isNotificationsEnabled()) {

			String json = data.getString(MESSAGE_KEY);

			if(!StringUtils.isEmpty(json)) {

				if(logger != null && logger.isDebugEnabled()) {
					logger.debug("Received notification [" +
							json +
							"]");
				}

				try {
					JSONObject message = newJSONObject(json);
					String notification_type = "notification_type";

					if(message.has(notification_type) && !message.isNull(notification_type)) {

						String type = message.getString(notification_type).trim().toUpperCase();

						NotificationType notificationType = null;

						try {
							notificationType = NotificationType.valueOf(type);
						}
						catch (Exception e) {
							handleError("Invalid notification_type [" +
									type +
									"] defined in notification message [" +
									json +
									"]", e);
						}

						if(notificationType != null) {

							JSONFactory<NotificationMessage> factory = messageFactories.get(notificationType.name());

							if(factory != null) {
								NotificationMessage notificationMessage = factory.fromJSON(message);
								NotificationMessageBuilder builder = messageBuilders.get(notificationType.name());

								if(builder != null) {
									int icon = getNotificationIcon(context);
									Notification notification = builder.build(context, data, notificationMessage, icon);
									doNotify(context, getNotificationTag(notificationMessage),  getNotificationId(notificationMessage), notification);
								}
								else {
									handleError("No message builder defined for notification type [" +
											notificationType +
											"]");
								}
							}
							else {
								handleError("No message factory defined for notification type [" +
										notificationType +
										"]");

							}
						}
					}
					else {
						handleError("No notification_type defined in notification message [" +
								json +
								"]");
					}
				}
				catch (JSONException e) {
					handleError("Notification system received an invalid JSON message [" +
							json +
							"]", e);
				}
				catch (Exception e) {
					handleError("Error building notification message", e);
				}
			}
			else {
				handleError("No data found in message bundle under key [" +
						MESSAGE_KEY +
						"]");
			}
		}
		else {
			if(settings == null) {
				handleError("No user settings found in session!");
			}
			else {
				if(logger != null && logger.isDebugEnabled()) {
					logger.debug("Notification for user [" +
							user.getId() +
							"] ignored.  Notifications are disabled for this user");
				}
			}
		}
	}

	protected void doNotify(Context context, String tag, int id, Notification notification) {
		notificationManagerFacade.notify(context, tag, id, notification);
	}

	protected String getNotificationTag(NotificationMessage message) {
		if(message.getEntityId() != null) {
			return String.valueOf(message.getEntityId().longValue());
		}
		else if(message.getUrl() != null) {
			return message.getUrl();
		}
		else {
			return String.valueOf(message.getActionId());
		}
	}

	protected int getNotificationId(NotificationMessage message) {
		if(message.getEntityId() != null) {
			return message.getEntityId().intValue();
		}
		return 0;
	}

	protected JSONObject newJSONObject(String json) throws JSONException {
		return new JSONObject(json);
	}

	protected int getNotificationIcon(Context context) {
		int icon = notificationIcon;

		if(config.getBooleanProperty(SocializeConfig.SOCIALIZE_NOTIFICATION_APP_ICON, true)) {
			icon = appUtils.getAppIconId(context);

			if(icon <= 0) {
				if(logger != null && logger.isDebugEnabled()) {
					logger.debug("Could not locate ID for application icon.  Using default icon for notification");
					icon = notificationIcon;
				}
			}
		}

		return icon;
	}

	protected void handleError(String msg) {
		if(logger != null) {
			logger.error(msg);
		}
		else {
			System.err.println(msg);
		}
	}

	protected void handleError(String msg, Exception e) {
		if(logger != null) {
			logger.error(msg, e);
		}
		else {
			SocializeLogger.e(msg, e);
		}
	}

	public void setLogger(SocializeLogger logger) {
		this.logger = logger;
	}

	public void setConfig(SocializeConfig config) {
		this.config = config;
	}

	public void setAppUtils(AppUtils appUtils) {
		this.appUtils = appUtils;
	}

	public int getNotificationIcon() {
		return notificationIcon;
	}

	public void setNotificationIcon(int notificationIcon) {
		this.notificationIcon = notificationIcon;
	}

	public void setMessageFactories(Map<String, JSONFactory<NotificationMessage>> messageFactories) {
		this.messageFactories = messageFactories;
	}

	public void setMessageBuilders(Map<String, NotificationMessageBuilder> messageBuilders) {
		this.messageBuilders = messageBuilders;
	}

	public void setNotificationRegistrationState(NotificationRegistrationState notificationRegistrationState) {
		this.notificationRegistrationState = notificationRegistrationState;
	}

	public void setNotificationRegistrationSystem(NotificationRegistrationSystem notificationRegistrationSystem) {
		this.notificationRegistrationSystem = notificationRegistrationSystem;
	}

	public void setUserSystem(UserSystem userSystem) {
		this.userSystem = userSystem;
	}

	public void setNotificationManagerFacade(NotificationManagerFacade notificationManagerFacade) {
		this.notificationManagerFacade = notificationManagerFacade;
	}

}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.demo.implementations.facebook;

import com.socialize.demo.SDKDemoActivity;
import com.socialize.error.SocializeException;
import com.socialize.networks.facebook.FacebookUtils;
import com.socialize.networks.facebook.OnPermissionResult;
import com.socialize.util.StringUtils;

import java.util.Arrays;

/**
 * @author Jason Polites
 *
 */
public class GetPermissionsActivity extends SDKDemoActivity {

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#executeDemo()
	 */
	@Override
	public void executeDemo(String text) {

		String token = FacebookUtils.getAccessToken(this);

		if(!StringUtils.isEmpty(token)) {
			FacebookUtils.getCurrentPermissions(this, token, new OnPermissionResult() {
				@Override
				public void onError(SocializeException error) {
					handleError(GetPermissionsActivity.this, error);
				}

				@Override
				public void onSuccess(String[] permissions) {
					handleResults(Arrays.asList(permissions));
				}
			});
		}
		else {
			handleError(this, new SocializeException("Not signed into Facebook"));
		}
	}

	@Override
	public boolean isTextEntryRequired() {
		return false;
	}

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#getButtonText()
	 */
	@Override
	public String getButtonText() {
		return "Get Current Permissions";
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.api.action.like;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CompoundButton;
import com.socialize.LikeUtils;
import com.socialize.ShareUtils;
import com.socialize.UserUtils;
import com.socialize.api.SocializeSession;
import com.socialize.api.action.ShareType;
import com.socialize.api.action.SocializeActionUtilsBase;
import com.socialize.entity.Entity;
import com.socialize.entity.Like;
import com.socialize.entity.User;
import com.socialize.error.SocializeApiError;
import com.socialize.error.SocializeException;
import com.socialize.listener.like.*;
import com.socialize.log.SocializeLogger;
import com.socialize.networks.SocialNetwork;
import com.socialize.ui.actionbutton.LikeButtonListener;
import com.socialize.ui.auth.AuthDialogListener;
import com.socialize.ui.auth.AuthPanelView;
import com.socialize.ui.auth.IAuthDialogFactory;
import com.socialize.ui.profile.UserSettings;
import com.socialize.ui.share.DialogFlowController;
import com.socialize.ui.share.IShareDialogFactory;
import com.socialize.ui.share.ShareDialogListener;
import com.socialize.ui.share.SharePanelView;

/**
 * @author Jason Polites
 */
public class SocializeLikeUtils extends SocializeActionUtilsBase implements LikeUtilsProxy {

	private IAuthDialogFactory authDialogFactory;
	private IShareDialogFactory shareDialogFactory;
	private LikeSystem likeSystem;

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.action.like.LikeUtilsProxy#like(android.app.Activity, com.socialize.entity.Entity, com.socialize.listener.like.LikeAddListener)
	 */
	@Override
	public void like(Activity context, final Entity entity, final LikeAddListener listener) {
		like(context, entity, getUserLikeOptions(context), listener);
	}

	@Override
	public void like(final Activity context, final Entity entity, final LikeOptions likeOptions, final LikeAddListener listener, final SocialNetwork...networks) {

		try {

			final boolean doShare = isDisplayShareDialog(context, likeOptions);
			final SocializeSession session = getSocialize().getSession();

			if(isDisplayAuthDialog(context, session, likeOptions, networks)) {
				authDialogFactory.show(context, new AuthDialogListener() {
					@Override
					public void onShow(Dialog dialog, AuthPanelView dialogView) {}

					@Override
					public void onCancel(Dialog dialog) {
						if(listener != null) {
							listener.onCancel();
						}
					}

					@Override
					public void onSkipAuth(Activity context, Dialog dialog) {
						dialog.dismiss();
						doLikeWithoutShareDialog(context, session, entity, likeOptions, listener);
					}

					@Override
					public void onError(Activity context, Dialog dialog, Exception error) {
						dialog.dismiss();
						if(listener != null) {
							listener.onError(SocializeException.wrap(error));
						}
					}
					@Override
					public void onAuthenticate(Activity context, Dialog dialog, SocialNetwork network) {
						dialog.dismiss();

						try {
							if(doShare) {
								doLikeWithShareDialog(context, session, entity, likeOptions, listener);
							}
							else {
								if(networks == null || networks.length == 0) {
									doLikeWithoutShareDialog(context, session, entity, likeOptions, listener, UserUtils.getAutoPostSocialNetworks(context));
								}
								else {
									doLikeWithoutShareDialog(context, session, entity, likeOptions, listener, networks);
								}
							}
						}
						catch (SocializeException e) {
							if(listener != null) {
								listener.onError(e);
							}

							Log.e(SocializeLogger.LOG_TAG, "Error adding like", e);
						}
					}
				}, !config.isAllowSkipAuthOnAllActions());
			}
			else {
				if(doShare) {
					doLikeWithShareDialog(context, session, entity, likeOptions, listener);
				}
				else {
					if(networks == null || networks.length == 0) {
						doLikeWithoutShareDialog(context, session, entity, likeOptions, listener, UserUtils.getAutoPostSocialNetworks(context));
					}
					else {
						doLikeWithoutShareDialog(context, session, entity, likeOptions, listener, networks);
					}
				}
			}
		}
		catch (Throwable e) {
			if(listener != null) {
				listener.onError(SocializeException.wrap(e));
			}

			Log.e(SocializeLogger.LOG_TAG, "Error adding like", e);
		}

	}

	@Override
	public LikeOptions getUserLikeOptions(Context context) {
		LikeOptions options = new LikeOptions();
		populateActionOptions(context, options);
		return options;
	}

	protected void doLikeWithoutShareDialog(final Activity context, final SocializeSession session, final Entity entity, final LikeAddListener listener) throws SocializeException {
		doLikeWithoutShareDialog(context, session, entity, getUserLikeOptions(context), listener, UserUtils.getAutoPostSocialNetworks(context));
	}

	protected void doLikeWithoutShareDialog(final Activity context, final SocializeSession session, final Entity entity, final LikeOptions likeOptions, final LikeAddListener listener, final SocialNetwork...networks) {
		likeSystem.addLike(session, entity, likeOptions, new LikeAddListener() {
			@Override
			public void onError(SocializeException error) {
				if(listener != null) {
					listener.onError(error);
				}
			}

			@Override
			public void onCreate(Like like) {
				if(listener != null) {
					listener.onCreate(like);
				}
				if(networks != null) {
					doActionShare(context, like, null, listener, networks);
				}
			}
		}, networks);
	}

	protected void doLikeWithShareDialog(final Activity context, final SocializeSession session, final Entity entity, final LikeOptions likeOptions, final LikeAddListener listener) throws SocializeException {

		if(isDisplayShareDialog(context, likeOptions)) {

			shareDialogFactory.show(context, entity, null, new ShareDialogListener() {

				@Override
				public void onShow(Dialog dialog, SharePanelView dialogView) {}

				@Override
				public void onFlowInterrupted(DialogFlowController controller) {}

				@Override
				public void onSimpleShare(ShareType type) {}

				@Override
				public boolean onContinue(final Dialog dialog, boolean remember, final SocialNetwork... networks) {

					UserSettings settings = session.getUserSettings();

					if(remember && settings.setAutoPostPreferences(networks)) {
						UserUtils.saveUserSettings(context, settings, null);
					}

					LikeAddListener overrideListener = new LikeAddListener() {

						@Override
						public void onError(SocializeException error) {
							if(dialog != null) {
								dialog.dismiss();
							}

							if(listener != null) {
								listener.onError(error);
							}
						}

						@Override
						public void onCreate(final Like like) {

							if(listener != null) {
								listener.onCreate(like);
							}

							doActionShare(context, like, null, listener, networks);

							if(dialog != null) {
								dialog.dismiss();
							}
						}
					};

					likeSystem.addLike(session, entity, likeOptions, overrideListener, networks);

					return false;
				}
				@Override
				public void onCancel(Dialog dialog) {
					if(listener != null) {
						listener.onCancel();
					}
				}
			}, ShareUtils.SOCIAL|ShareUtils.SHOW_REMEMBER|ShareUtils.ALWAYS_CONTINUE);
		}
		else {
			doLikeWithoutShareDialog(context, session, entity, listener);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.action.like.LikeUtilsProxy#unlike(android.app.Activity, com.socialize.entity.Entity, com.socialize.listener.like.LikeDeleteListener)
	 */
	@Override
	public void unlike(Activity context, String entityKey, final LikeDeleteListener listener) {
		final SocializeSession session = getSocialize().getSession();
		// Get the like based on the key
		likeSystem.getLike(session, entityKey , new LikeGetListener() {
			@Override
			public void onGet(Like entity) {
				if(entity != null) {
					likeSystem.deleteLike(session, entity.getId(), listener);
				}
				else {
					if(listener != null) {
						listener.onDelete();
					}
				}
			}

			@Override
			public void onError(SocializeException error) {

				if(error instanceof SocializeApiError) {
					if(((SocializeApiError)error).getResultCode() == 404) {
						if(listener != null) {
							listener.onDelete();
						}
						return;
					}
				}

				if(listener != null) {
					listener.onError(error);
				}
			}
		});
	}

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.action.like.LikeUtilsProxy#getLike(android.app.Activity, com.socialize.entity.Entity, com.socialize.listener.like.LikeGetListener)
	 */
	@Override
	public void getLike(Activity context, String entityKey, LikeGetListener listener) {
		final SocializeSession session = getSocialize().getSession();
		likeSystem.getLike(session, entityKey, listener);
	}

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.action.like.LikeUtilsProxy#getLike(android.app.Activity, long, com.socialize.listener.like.LikeGetListener)
	 */
	@Override
	public void getLike(Activity context, long id, LikeGetListener listener) {
		final SocializeSession session = getSocialize().getSession();
		likeSystem.getLike(session, id, listener);
	}

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.action.like.LikeUtilsProxy#getLikesByUser(android.app.Activity, com.socialize.entity.User, int, int, com.socialize.listener.like.LikeListListener)
	 */
	@Override
	public void getLikesByUser(Activity context, User user, int start, int end, LikeListListener listener) {
		final SocializeSession session = getSocialize().getSession();
		likeSystem.getLikesByUser(session, user.getId(), start, end, listener);
	}

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.action.like.LikeUtilsProxy#getLikesByEntity(android.app.Activity, com.socialize.entity.Entity, int, int, com.socialize.listener.like.LikeListListener)
	 */
	@Override
	public void getLikesByEntity(Activity context, String entityKey, int start, int end, LikeListListener listener) {
		likeSystem.getLikesByEntity(getSocialize().getSession(), entityKey, start, end, listener);
	}

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.action.like.LikeUtilsProxy#getLikesByApplication(android.app.Activity, int, int, com.socialize.listener.like.LikeListListener)
	 */
	@Override
	public void getLikesByApplication(Activity context, int start, int end, LikeListListener listener) {
		likeSystem.getLikesByApplication(getSocialize().getSession(), start, end, listener);
	}

	public void setAuthDialogFactory(IAuthDialogFactory authDialogFactory) {
		this.authDialogFactory = authDialogFactory;
	}

	public void setShareDialogFactory(IShareDialogFactory shareDialogFactory) {
		this.shareDialogFactory = shareDialogFactory;
	}

	public void setLikeSystem(LikeSystem likeSystem) {
		this.likeSystem = likeSystem;
	}

	@Override
	public void makeLikeButton(final Activity context, final CompoundButton button, final Entity entity, final LikeButtonListener listener) {

		if(listener != null) {
			// Clear any current listener
			button.setOnCheckedChangeListener(null);
		}

		// Use onclick because we don't want to trigger the checked listener when we change state
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				if(listener != null) {
					listener.onClick(button);
				}

				if(button.isChecked()) {
					LikeUtils.like(context, entity, new LikeAddListener() {
						@Override
						public void onError(SocializeException error) {
							button.setChecked(false);
							if(listener != null) {
								listener.onError(button, error);
							}
						}

						@Override
						public void onCreate(Like result) {
							if(listener != null) {
								listener.onCheckedChanged(button, true);
							}
						}

						@Override
						public void onCancel() {
							button.setChecked(false);
							if(listener != null) {
								listener.onCheckedChanged(button, false);
							}
						}
					});
				}
				else {
					LikeUtils.unlike(context, entity.getKey(), new LikeDeleteListener() {
						@Override
						public void onError(SocializeException error) {
							button.setChecked(true);
							if(listener != null) {
								listener.onError(button, error);
							}
						}

						@Override
						public void onDelete() {
							button.setChecked(false);
							if(listener != null) {
								listener.onCheckedChanged(button, false);
							}
						}
					});
				}
			}
		});

		// Get the initial state
		LikeUtils.isLiked(context, entity.getKey(), new IsLikedListener() {
			@Override
			public void onNotLiked() {
				button.setChecked(false);
				if(listener != null) {
					listener.onCheckedChanged(button, false);
				}
			}

			@Override
			public void onLiked(Like like) {
				button.setChecked(true);
				if(listener != null) {
					listener.onCheckedChanged(button, true);
				}
			}
		});
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.networks.facebook;

import android.content.Context;
import android.widget.ImageView;
import com.socialize.ui.view.ClickableSectionCell;

/**
 * @author Jason Polites
 */
public abstract class FacebookCell extends ClickableSectionCell {

	public FacebookCell(Context context) {
		super(context);
	}

	/* (non-Javadoc)
	 * @see com.socialize.ui.view.ClickableSectionCell#makeImage()
	 */
	@Override
	protected ImageView makeImage() {
        if(drawables != null) {
            setImageOn(drawables.getDrawable("icon_facebook.png"));
            setImageOff(drawables.getDrawable("icon_facebook_disabled.png"));
        }
		return  new ImageView(getContext());
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.demo.implementations.comment;

import com.socialize.CommentUtils;
import com.socialize.api.action.comment.CommentOptions;
import com.socialize.demo.SDKDemoActivity;
import com.socialize.entity.Comment;
import com.socialize.error.SocializeException;
import com.socialize.listener.comment.CommentAddListener;

/**
 * @author Jason Polites
 *
 */
public class AddCommentWithoutShareActivity extends SDKDemoActivity {

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#executeDemo()
	 */
	@Override
	public void executeDemo(String text) {
		CommentOptions options = CommentUtils.getUserCommentOptions(this);
		options.setShowAuthDialog(false);
		options.setShowShareDialog(false);

		CommentUtils.addComment(this, entity, text, options, new CommentAddListener() {
			@Override
			public void onError(SocializeException error) {
				handleError(AddCommentWithoutShareActivity.this, error);
			}

			@Override
			public void onCreate(Comment comment) {
				handleSocializeResult(comment);
			}

			@Override
			public void onCancel() {
				handleCancel();
			}
		});
	}

	@Override
	public boolean isTextEntryRequired() {
		return true;
	}

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#getButtonText()
	 */
	@Override
	public String getButtonText() {
		return "Add Comment";
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.socialize.log.SocializeLogger;
import com.socialize.notifications.C2DMCallback;
import com.socialize.notifications.SocializeC2DMReceiverHandler;

/**
 * Utility class to assist in overriding the default behavior of smart alerts.
 * @author Jason Polites
 */
public class SmartAlertUtils {

	// Does not use the SocializeActionProxy because we need to manually init notification beans
	static SocializeC2DMReceiverHandler handler = null;
	static final Object syncLock = new Object();

	/**
	 * Handles a GCM message.  Returns true ONLY if this message was intended for Socialize.
	 * @param context
	 * @param intent
	 * @return
	 */
	public static boolean onMessage(Context context, Intent intent) {
		assertInitialized(context);

		Bundle messageData = intent.getExtras();

		if(messageData != null) {
			String source = messageData.getString(C2DMCallback.SOURCE_KEY);
			if(source != null && source.trim().equalsIgnoreCase(C2DMCallback.SOURCE_SOCIALIZE)) {
				handler.onMessage(context, intent);
				return true;
			}
		}

		return false;
	}

	public static void onRegister(Context context, String registrationId) {
		assertInitialized(context);
		handler.onRegistered(context, registrationId);
	}

	public static void onError(Context context, String errorId) {
		assertInitialized(context);
		handler.onError(context, errorId);
	}

	public static void onUnregister(Context context, String registrationId) {
		assertInitialized(context);
		handler.onUnregistered(context);
	}

	static void assertInitialized(Context context) {
		if(handler == null) {
			synchronized (syncLock) {
				if(handler == null) {
					handler = new SocializeC2DMReceiverHandler();
					handler.onCreate(context);
				}
			}
		}
	}

	static void logNotInitializedError() {
		Log.e(SocializeLogger.LOG_TAG, "GCMUtils was not initialized.  Make sure you are calling onCreate in your receiver");
	}

	/**
	 * Handles a broadcast intent received by a Broadcast Receiver on Android.
	 * Call this method if you already have a broadcast receiver defined but want to also utilize Socialize SmartAlerts.
	 * @param context The current context.
	 * @param intent The broadcast intent provided by Android.
	 * @return Returns true if Socialize handled the intent.  This indicates the intent was designed to be handled by Socialize and you do not need to handle it yourself.
	 */
	public static boolean handleBroadcastIntent(Context context, Intent intent) {
		return Socialize.getSocialize().handleBroadcastIntent(context, intent);
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.launcher;

import android.app.Activity;
import android.os.Bundle;
import com.socialize.Socialize;
import com.socialize.SocializeService;
import com.socialize.api.SocializeSession;
import com.socialize.api.action.entity.EntitySystem;
import com.socialize.entity.Entity;
import com.socialize.log.SocializeLogger;
import com.socialize.notifications.NotificationAuthenticator;
import com.socialize.ui.SocializeEntityLoader;
import com.socialize.util.EntityLoaderUtils;

/**
 * @author Jason Polites
 *
 */
public class EntityLauncher extends BaseLauncher {

	private EntityLoaderUtils entityLoaderUtils;
	private SocializeLogger logger;
	private EntitySystem entitySystem;
	private NotificationAuthenticator notificationAuthenticator;

	/* (non-Javadoc)
	 * @see com.socialize.launcher.Launcher#launch(android.app.Activity, android.os.Bundle)
	 */
	@Override
	public boolean launch(final Activity context, Bundle data) {

		if(entityLoaderUtils != null) {
			final SocializeEntityLoader entityLoader = entityLoaderUtils.initEntityLoader();

			if(entityLoader != null) {

				Object idObj = data.get(Socialize.ENTITY_ID);

				if(idObj != null) {
					long id = Long.parseLong(idObj.toString());
					try {
						SocializeSession session = notificationAuthenticator.authenticate(context);
						Entity entity = entitySystem.getEntitySynchronous(session, id);
						return loadEntity(context, entityLoader, entity);
					}
					catch (Exception e) {
						handleError("Failed to load entity", e);
					}
				}
				else {
					handleWarn("No entity id found.  Entity based notification cannot be handled");
				}
			}
			else {
				handleWarn("No entity loader found.  Entity based notification cannot be handled");
			}
		}

		return false;
	}

	protected boolean loadEntity(Activity context, SocializeEntityLoader entityLoader, Entity entity) {
		if(entity != null) {
			if(entityLoader.canLoad(context, entity)) {

				if(logger != null && logger.isInfoEnabled()) {
					logger.info("Calling entity loader for entity with key [" +
							entity.getKey() +
							"]");
				}

				entityLoader.loadEntity(context, entity);

				return true;
			}
			else {
				if(logger != null && logger.isDebugEnabled()) {
					logger.debug("Entity loaded indicates that entity with key [" +
							entity.getKey() +
							"] cannot be loaded");
				}
			}
		}
		else {
			handleWarn("No entity object found under key [" +
					Socialize.ENTITY_OBJECT +
					"] in EntityLaucher");

		}

		return false;
	}

	protected void handleWarn(String msg) {
		if(logger != null) {
			logger.warn(msg);
		}
		else {
			System.err.println(msg);
		}
	}

	protected void handleError(String msg, Exception e) {
		if(logger != null) {
			logger.error(msg, e);
		}
		else {
			SocializeLogger.e(e.getMessage(), e);
		}
	}

	protected SocializeService getSocialize() {
		return Socialize.getSocialize();
	}

	public void setEntityLoaderUtils(EntityLoaderUtils entityLoaderUtils) {
		this.entityLoaderUtils = entityLoaderUtils;
	}

	public void setLogger(SocializeLogger logger) {
		this.logger = logger;
	}

	public void setEntitySystem(EntitySystem entitySystem) {
		this.entitySystem = entitySystem;
	}

	public void setNotificationAuthenticator(NotificationAuthenticator notificationAuthenticator) {
		this.notificationAuthenticator = notificationAuthenticator;
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.launcher.task;

import android.content.Context;
import android.os.Bundle;
import com.socialize.api.SocializeSession;
import com.socialize.api.event.EventListener;
import com.socialize.api.event.EventSystem;
import com.socialize.api.event.SocializeEvent;
import com.socialize.error.SocializeException;
import com.socialize.launcher.LaunchTask;
import com.socialize.listener.SocializeAuthListener;
import com.socialize.log.SocializeLogger;
import com.socialize.notifications.C2DMCallback;
import com.socialize.notifications.NotificationAuthenticator;
import org.json.JSONObject;

/**
 * @author Jason Polites
 *
 */
public class NotificationOpenEventTask implements LaunchTask {

	private EventSystem eventSystem;
	private SocializeLogger logger;
	private NotificationAuthenticator notificationAuthenticator;

	/* (non-Javadoc)
	 * @see com.socialize.launcher.LaunchTask#execute(android.content.Context, android.os.Bundle)
	 */
	@Override
	public void execute(Context context, Bundle extras) throws SocializeException {

		try {

			if(logger != null && logger.isDebugEnabled()) {
				logger.debug("Recording notification open event...");
			}

			final SocializeEvent event = new SocializeEvent();
			event.setBucket("NOTIFICATION_OPEN");
			String json = extras.getString(C2DMCallback.MESSAGE_KEY);
			JSONObject obj = new JSONObject(json);
			event.setData(obj);

			notificationAuthenticator.authenticateAsync(context, new SocializeAuthListener() {

				@Override
				public void onError(SocializeException error) {
					logError(error);
				}

				@Override
				public void onCancel() {}

				@Override
				public void onAuthSuccess(SocializeSession session) {
					eventSystem.addEvent(session, event, new EventListener() {

						@Override
						public void onError(SocializeException error) {
							logError(error);
						}

						@Override
						public void onPost() {
							if(logger != null && logger.isDebugEnabled()) {
								logger.debug("Notification open event recorded.");
							}
						}
					});
				}

				@Override
				public void onAuthFail(SocializeException error) {
					logError(error);
				}
			});

		}
		catch (Exception e) {
			throw SocializeException.wrap(e);
		}
	}

	protected void logError(Exception e) {
		if(logger != null) {
			logger.error("Error recording notification open event", e);
		}
		else {
			SocializeLogger.e(e.getMessage(), e);
		}
	}

	public void setEventSystem(EventSystem eventSystem) {
		this.eventSystem = eventSystem;
	}

	public void setLogger(SocializeLogger logger) {
		this.logger = logger;
	}

	public void setNotificationAuthenticator(NotificationAuthenticator notificationAuthenticator) {
		this.notificationAuthenticator = notificationAuthenticator;
	}
}


// Portions copyright 2002, Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.socialize.util;

// This code was converted from code at http://iharder.sourceforge.net/base64/
// Lots of extraneous features were removed.
/* The original code said:
 *

 * I am placing this code in the Public Domain. Do with it as you will.
 * This software comes with no guarantees or warranties but with
 * plenty of well-wishing instead!
 * Please visit
 * http://iharder.net/xmlizable
 * periodically to check for updates or to contribute improvements.
 *

 *
 * @author Robert Harder
 * @author rharder@usa.net
 * @version 1.3
 */

/**
 * Base64 converter class. This code is not a full-blown MIME encoder;
 * it simply converts binary data to base64 data and back.
 */
public class Base64Utils {
  /** Specify encoding (value is {@code true}). */
  public final static boolean ENCODE = true;

  /** Specify decoding (value is {@code false}). */
  public final static boolean DECODE = false;

  /** The equals sign (=) as a byte. */
  private final static byte EQUALS_SIGN = (byte) '=';

  /** The new line character (\n) as a byte. */
  private final static byte NEW_LINE = (byte) '\n';

  /**
   * The 64 valid Base64 values.
   */
  private final static byte[] ALPHABET =
      {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F',
          (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K',
          (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
          (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
          (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
          (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e',
          (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j',
          (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
          (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't',
          (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y',
          (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
          (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8',
          (byte) '9', (byte) '+', (byte) '/'};

  /**
   * The 64 valid web safe Base64 values.
   */
  private final static byte[] WEBSAFE_ALPHABET =
      {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F',
          (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K',
          (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
          (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
          (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
          (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e',
          (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j',
          (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
          (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't',
          (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y',
          (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
          (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8',
          (byte) '9', (byte) '-', (byte) '_'};

  /**
   * Translates a Base64 value to either its 6-bit reconstruction value
   * or a negative number indicating some other meaning.
   **/
  private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal  0 -  8
      -5, -5, // Whitespace: Tab and Linefeed
      -9, -9, // Decimal 11 - 12
      -5, // Whitespace: Carriage Return
      -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
      -9, -9, -9, -9, -9, // Decimal 27 - 31
      -5, // Whitespace: Space
      -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
      62, // Plus sign at decimal 43
      -9, -9, -9, // Decimal 44 - 46
      63, // Slash at decimal 47
      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
      -9, -9, -9, // Decimal 58 - 60
      -1, // Equals sign at decimal 61
      -9, -9, -9, // Decimal 62 - 64
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
      14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
      -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
      26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
      39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
      -9, -9, -9, -9, -9 // Decimal 123 - 127
      /*  ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 128 - 139
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
      };

  /** The web safe decodabet */
  private final static byte[] WEBSAFE_DECODABET =
      {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal  0 -  8
          -5, -5, // Whitespace: Tab and Linefeed
          -9, -9, // Decimal 11 - 12
          -5, // Whitespace: Carriage Return
          -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
          -9, -9, -9, -9, -9, // Decimal 27 - 31
          -5, // Whitespace: Space
          -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44
          62, // Dash '-' sign at decimal 45
          -9, -9, // Decimal 46-47
          52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
          -9, -9, -9, // Decimal 58 - 60
          -1, // Equals sign at decimal 61
          -9, -9, -9, // Decimal 62 - 64
          0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
          14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
          -9, -9, -9, -9, // Decimal 91-94
          63, // Underscore '_' at decimal 95
          -9, // Decimal 96
          26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
          39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
          -9, -9, -9, -9, -9 // Decimal 123 - 127
      /*  ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 128 - 139
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
      };

  // Indicates white space in encoding
  private final static byte WHITE_SPACE_ENC = -5;
  // Indicates equals sign in encoding
  private final static byte EQUALS_SIGN_ENC = -1;

  /* ********  E N C O D I N G   M E T H O D S  ******** */

  /**
   * Encodes up to three bytes of the array <var>source</var>
   * and writes the resulting four Base64 bytes to <var>destination</var>.
   * The source and destination arrays can be manipulated
   * anywhere along their length by specifying
   * <var>srcOffset</var> and <var>destOffset</var>.
   * This method does not check to make sure your arrays
   * are large enough to accommodate <var>srcOffset</var> + 3 for
   * the <var>source</var> array or <var>destOffset</var> + 4 for
   * the <var>destination</var> array.
   * The actual number of significant bytes in your array is
   * given by <var>numSigBytes</var>.
   *
   * @param source the array to convert
   * @param srcOffset the index where conversion begins
   * @param numSigBytes the number of significant bytes in your array
   * @param destination the array to hold the conversion
   * @param destOffset the index where output will be put
   * @param alphabet is the encoding alphabet
   * @return the <var>destination</var> array
   * @since 1.3
   */
  private byte[] encode3to4(byte[] source, int srcOffset,
      int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) {
    //           1         2         3
    // 01234567890123456789012345678901 Bit position
    // --------000000001111111122222222 Array position from threeBytes
    // --------|    ||    ||    ||    | Six bit groups to index alphabet
    //          >>18  >>12  >> 6  >> 0  Right shift necessary
    //                0x3f  0x3f  0x3f  Additional AND

    // Create buffer with zero-padding if there are only one or two
    // significant bytes passed in the array.
    // We have to shift left 24 in order to flush out the 1's that appear
    // when Java treats a value as negative that is cast from a byte to an int.
    int inBuff =
        (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
            | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
            | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);

    switch (numSigBytes) {
      case 3:
        destination[destOffset] = alphabet[(inBuff >>> 18)];
        destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f];
        destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f];
        destination[destOffset + 3] = alphabet[(inBuff) & 0x3f];
        return destination;
      case 2:
        destination[destOffset] = alphabet[(inBuff >>> 18)];
        destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f];
        destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f];
        destination[destOffset + 3] = EQUALS_SIGN;
        return destination;
      case 1:
        destination[destOffset] = alphabet[(inBuff >>> 18)];
        destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f];
        destination[destOffset + 2] = EQUALS_SIGN;
        destination[destOffset + 3] = EQUALS_SIGN;
        return destination;
      default:
        return destination;
    } // end switch
  } // end encode3to4

  /**
   * Encodes a byte array into Base64 notation.
   * Equivalent to calling
   * {@code encodeBytes(source, 0, source.length)}
   *
   * @param source The data to convert
   * @since 1.4
   */
  public String encode(byte[] source) {
    return encode(source, 0, source.length, ALPHABET, true);
  }

  /**
   * Encodes a byte array into web safe Base64 notation.
   *
   * @param source The data to convert
   * @param doPadding is {@code true} to pad result with '=' chars
   *        if it does not fall on 3 byte boundaries
   */
  public String encodeWebSafe(byte[] source, boolean doPadding) {
    return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding);
  }

  /**
   * Encodes a byte array into Base64 notation.
   *
   * @param source The data to convert
   * @param off Offset in array where conversion should begin
   * @param len Length of data to convert
   * @param alphabet is the encoding alphabet
   * @param doPadding is {@code true} to pad result with '=' chars
   *        if it does not fall on 3 byte boundaries
   * @since 1.4
   */
  public String encode(byte[] source, int off, int len, byte[] alphabet,
      boolean doPadding) {
    byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE);
    int outLen = outBuff.length;

    // If doPadding is false, set length to truncate '='
    // padding characters
    while (doPadding == false && outLen > 0) {
      if (outBuff[outLen - 1] != '=') {
        break;
      }
      outLen -= 1;
    }

    return new String(outBuff, 0, outLen);
  }

  /**
   * Encodes a byte array into Base64 notation.
   *
   * @param source The data to convert
   * @param off Offset in array where conversion should begin
   * @param len Length of data to convert
   * @param alphabet is the encoding alphabet
   * @param maxLineLength maximum length of one line.
   * @return the BASE64-encoded byte array
   */
  public byte[] encode(byte[] source, int off, int len, byte[] alphabet,
      int maxLineLength) {
    int lenDiv3 = (len + 2) / 3; // ceil(len / 3)
    int len43 = lenDiv3 * 4;
    byte[] outBuff = new byte[len43 // Main 4:3
        + (len43 / maxLineLength)]; // New lines

    int d = 0;
    int e = 0;
    int len2 = len - 2;
    int lineLength = 0;
    for (; d < len2; d += 3, e += 4) {

      // The following block of code is the same as
      // encode3to4( source, d + off, 3, outBuff, e, alphabet );
      // but inlined for faster encoding (~20% improvement)
      int inBuff =
          ((source[d + off] << 24) >>> 8)
              | ((source[d + 1 + off] << 24) >>> 16)
              | ((source[d + 2 + off] << 24) >>> 24);
      outBuff[e] = alphabet[(inBuff >>> 18)];
      outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f];
      outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f];
      outBuff[e + 3] = alphabet[(inBuff) & 0x3f];

      lineLength += 4;
      if (lineLength == maxLineLength) {
        outBuff[e + 4] = NEW_LINE;
        e++;
        lineLength = 0;
      } // end if: end of line
    } // end for: each piece of array

    if (d < len) {
      encode3to4(source, d + off, len - d, outBuff, e, alphabet);

      lineLength += 4;
      if (lineLength == maxLineLength) {
        // Add a last newline
        outBuff[e + 4] = NEW_LINE;
        e++;
      }
      e += 4;
    }

    assert (e == outBuff.length);
    return outBuff;
  }

  /* ********  D E C O D I N G   M E T H O D S  ******** */

  /**
   * Decodes four bytes from array <var>source</var>
   * and writes the resulting bytes (up to three of them)
   * to <var>destination</var>.
   * The source and destination arrays can be manipulated
   * anywhere along their length by specifying
   * <var>srcOffset</var> and <var>destOffset</var>.
   * This method does not check to make sure your arrays
   * are large enough to accommodate <var>srcOffset</var> + 4 for
   * the <var>source</var> array or <var>destOffset</var> + 3 for
   * the <var>destination</var> array.
   * This method returns the actual number of bytes that
   * were converted from the Base64 encoding.
   *
   *
   * @param source the array to convert
   * @param srcOffset the index where conversion begins
   * @param destination the array to hold the conversion
   * @param destOffset the index where output will be put
   * @param decodabet the decodabet for decoding Base64 content
   * @return the number of decoded bytes converted
   * @since 1.3
   */
  private int decode4to3(byte[] source, int srcOffset,
      byte[] destination, int destOffset, byte[] decodabet) {
    // Example: Dk==
    if (source[srcOffset + 2] == EQUALS_SIGN) {
      int outBuff =
          ((decodabet[source[srcOffset]] << 24) >>> 6)
              | ((decodabet[source[srcOffset + 1]] << 24) >>> 12);

      destination[destOffset] = (byte) (outBuff >>> 16);
      return 1;
    } else if (source[srcOffset + 3] == EQUALS_SIGN) {
      // Example: DkL=
      int outBuff =
          ((decodabet[source[srcOffset]] << 24) >>> 6)
              | ((decodabet[source[srcOffset + 1]] << 24) >>> 12)
              | ((decodabet[source[srcOffset + 2]] << 24) >>> 18);

      destination[destOffset] = (byte) (outBuff >>> 16);
      destination[destOffset + 1] = (byte) (outBuff >>> 8);
      return 2;
    } else {
      // Example: DkLE
      int outBuff =
          ((decodabet[source[srcOffset]] << 24) >>> 6)
              | ((decodabet[source[srcOffset + 1]] << 24) >>> 12)
              | ((decodabet[source[srcOffset + 2]] << 24) >>> 18)
              | ((decodabet[source[srcOffset + 3]] << 24) >>> 24);

      destination[destOffset] = (byte) (outBuff >> 16);
      destination[destOffset + 1] = (byte) (outBuff >> 8);
      destination[destOffset + 2] = (byte) (outBuff);
      return 3;
    }
  } // end decodeToBytes

  /**
   * Decodes data from Base64 notation.
   *
   * @param s the string to decode (decoded in default encoding)
   * @return the decoded data
   * @since 1.4
   */
  public byte[] decode(String s) throws Base64DecoderException {
    byte[] bytes = s.getBytes();
    return decode(bytes, 0, bytes.length);
  }

  /**
   * Decodes data from web safe Base64 notation.
   * Web safe encoding uses '-' instead of '+', '_' instead of '/'
   *
   * @param s the string to decode (decoded in default encoding)
   * @return the decoded data
   */
  public byte[] decodeWebSafe(String s) throws Base64DecoderException {
    byte[] bytes = s.getBytes();
    return decodeWebSafe(bytes, 0, bytes.length);
  }

  /**
   * Decodes Base64 content in byte array format and returns
   * the decoded byte array.
   *
   * @param source The Base64 encoded data
   * @return decoded data
   * @since 1.3
   * @throws Base64DecoderException
   */
  public byte[] decode(byte[] source) throws Base64DecoderException {
    return decode(source, 0, source.length);
  }

  /**
   * Decodes web safe Base64 content in byte array format and returns
   * the decoded data.
   * Web safe encoding uses '-' instead of '+', '_' instead of '/'
   *
   * @param source the string to decode (decoded in default encoding)
   * @return the decoded data
   */
  public byte[] decodeWebSafe(byte[] source)
      throws Base64DecoderException {
    return decodeWebSafe(source, 0, source.length);
  }

  /**
   * Decodes Base64 content in byte array format and returns
   * the decoded byte array.
   *
   * @param source The Base64 encoded data
   * @param off    The offset of where to begin decoding
   * @param len    The length of characters to decode
   * @return decoded data
   * @since 1.3
   * @throws Base64DecoderException
   */
  public byte[] decode(byte[] source, int off, int len)
      throws Base64DecoderException {
    return decode(source, off, len, DECODABET);
  }

  /**
   * Decodes web safe Base64 content in byte array format and returns
   * the decoded byte array.
   * Web safe encoding uses '-' instead of '+', '_' instead of '/'
   *
   * @param source The Base64 encoded data
   * @param off    The offset of where to begin decoding
   * @param len    The length of characters to decode
   * @return decoded data
   */
  public byte[] decodeWebSafe(byte[] source, int off, int len)
      throws Base64DecoderException {
    return decode(source, off, len, WEBSAFE_DECODABET);
  }

  /**
   * Decodes Base64 content using the supplied decodabet and returns
   * the decoded byte array.
   *
   * @param source    The Base64 encoded data
   * @param off       The offset of where to begin decoding
   * @param len       The length of characters to decode
   * @param decodabet the decodabet for decoding Base64 content
   * @return decoded data
   */
  public byte[] decode(byte[] source, int off, int len, byte[] decodabet)
      throws Base64DecoderException {
    int len34 = len * 3 / 4;
    byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output
    int outBuffPosn = 0;

    byte[] b4 = new byte[4];
    int b4Posn = 0;
    int i = 0;
    byte sbiCrop = 0;
    byte sbiDecode = 0;
    for (i = 0; i < len; i++) {
      sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven bits
      sbiDecode = decodabet[sbiCrop];

      if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or better
        if (sbiDecode >= EQUALS_SIGN_ENC) {
          // An equals sign (for padding) must not occur at position 0 or 1
          // and must be the last byte[s] in the encoded value
          if (sbiCrop == EQUALS_SIGN) {
            int bytesLeft = len - i;
            byte lastByte = (byte) (source[len - 1 + off] & 0x7f);
            if (b4Posn == 0 || b4Posn == 1) {
              throw new Base64DecoderException(
                  "invalid padding byte '=' at byte offset " + i);
            } else if ((b4Posn == 3 && bytesLeft > 2)
                || (b4Posn == 4 && bytesLeft > 1)) {
              throw new Base64DecoderException(
                  "padding byte '=' falsely signals end of encoded value "
                      + "at offset " + i);
            } else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) {
              throw new Base64DecoderException(
                  "encoded value has invalid trailing byte");
            }
            break;
          }

          b4[b4Posn++] = sbiCrop;
          if (b4Posn == 4) {
            outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet);
            b4Posn = 0;
          }
        }
      } else {
        throw new Base64DecoderException("Bad Base64 input character at " + i
            + ": " + source[i + off] + "(decimal)");
      }
    }

    // Because web safe encoding allows non padding base64 encodes, we
    // need to pad the rest of the b4 buffer with equal signs when
    // b4Posn != 0.  There can be at most 2 equal signs at the end of
    // four characters, so the b4 buffer must have two or three
    // characters.  This also catches the case where the input is
    // padded with EQUALS_SIGN
    if (b4Posn != 0) {
      if (b4Posn == 1) {
        throw new Base64DecoderException("single trailing character at offset "
            + (len - 1));
      }
      b4[b4Posn++] = EQUALS_SIGN;
      outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet);
    }

    byte[] out = new byte[outBuffPosn];
    System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
    return out;
  }
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize;

import android.app.Activity;
import com.socialize.api.action.view.ViewUtilsProxy;
import com.socialize.entity.Entity;
import com.socialize.listener.view.ViewAddListener;
import com.socialize.listener.view.ViewGetListener;

import java.lang.reflect.Proxy;

/**
 * @author Jason Polites
 *
 */
public class ViewUtils {

	static ViewUtilsProxy proxy;

	static {
		proxy = (ViewUtilsProxy) Proxy.newProxyInstance(
				ViewUtilsProxy.class.getClassLoader(),
				new Class[]{ViewUtilsProxy.class},
				new SocializeActionProxy("viewUtils"));	// Bean name
	}

	/**
	 * Records a view against the given entity for the current user.
	 * @param context The current context.
	 * @param e The entity to be viewed.
	 * @param listener A listener to handle the result.
	 */
	public static void view (Activity context, Entity e, ViewAddListener listener) {
		proxy.view(context, e, listener);
	}

	public static void getView (Activity context, long id, ViewGetListener listener) {
		proxy.getView(context, id, listener);
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize.demo.implementations.action;

import com.socialize.ActionUtils;
import com.socialize.demo.SDKDemoActivity;
import com.socialize.entity.ListResult;
import com.socialize.entity.SocializeAction;
import com.socialize.error.SocializeException;
import com.socialize.listener.activity.ActionListListener;

/**
 * @author Jason Polites
 *
 */
public class GetActionsByApplicationActivity extends SDKDemoActivity {

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#executeDemo()
	 */
	@Override
	public void executeDemo(String text) {
		ActionUtils.getActionsByApplication(this, 0, PAGE_SIZE, new ActionListListener() {
			@Override
			public void onList(ListResult<SocializeAction> result) {
				handleSocializeResult(result);
			}

			@Override
			public void onError(SocializeException error) {
				handleError(GetActionsByApplicationActivity.this, error);
			}
		});
	}

	@Override
	public boolean isTextEntryRequired() {
		return false;
	}

	/* (non-Javadoc)
	 * @see com.socialize.demo.DemoActivity#getButtonText()
	 */
	@Override
	public String getButtonText() {
		return "List " + PAGE_SIZE + " Actions for this app";
	}
}


/*
 * Copyright (c) 2012 Socialize Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.socialize;

import android.app.Activity;
import android.content.Context;
import com.socialize.android.ioc.IOCContainer;
import com.socialize.annotations.NoAuth;
import com.socialize.annotations.Synchronous;
import com.socialize.api.SocializeSession;
import com.socialize.error.AuthCanceledException;
import com.socialize.error.SocializeException;
import com.socialize.listener.SocializeAuthListener;
import com.socialize.listener.SocializeInitListener;
import com.socialize.listener.SocializeListener;
import com.socialize.log.SocializeLogger;
import org.apache.http.MethodNotSupportedException;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Proxies all requests to top level Socialize interfaces to ensure that clients are both initialized and authenticated.
 * @author Jason Polites
 */
public class SocializeActionProxy implements InvocationHandler {

	private String delegateBean;
	private boolean synchronous = false;

	public SocializeActionProxy(String delegateBean) {
		super();
		this.delegateBean = delegateBean;
	}

	public SocializeActionProxy(String delegateBean, boolean synchronous) {
		this(delegateBean);
		this.synchronous = synchronous;
	}

	/* (non-Javadoc)
	 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		try {
			if(synchronous || method.isAnnotationPresent(Synchronous.class) || !isVoidMethod(method)) {

				Context context = findContext(args);

				if(context != null) {
					synchronized (this) {
                        SocializeService socialize = Socialize.getSocialize();

                        if(!socialize.isInitialized(context)) {
							socialize.init(context);
							if(!socialize.isAuthenticated() && !method.isAnnotationPresent(NoAuth.class)) {
								socialize.authenticateSynchronous(context);
							}
						}
					}
				}

				return method.invoke(getBean(), args);
			}
			else {
				Activity context = findActivity(args);

				if(context != null) {
					SocializeListener listener = findListener(args);

					// Always init to set the context
					invokeWithInit(context, listener, method, args);
				}
				else {
					throw new MethodNotSupportedException("No activity found in method arguments for method [" +
							method.getName() +
							"]");
				}
			}

			// Always void
			return null;
		}
		catch (Throwable e) {
			SocializeLogger.e(e.getMessage(), e);
			throw e;
		}
	}

	protected boolean isVoidMethod(Method method) {
		Class<?> returnType = method.getReturnType();
		return (returnType == null || returnType.equals(Void.TYPE));
	}

	protected void invokeWithInit(final Activity context, final SocializeListener listener, final Method method, final Object[] args) throws Throwable {

		SocializeServiceImpl service = getSocialize();

		if(service.isInitialized(context)) {
			service.setContext(context);
			invoke(context, listener, method, args);
		}
		else {
			service.initAsync(context, new SocializeInitListener() {
				@Override
				public void onError(SocializeException error) {
					if(listener != null) {
						listener.onError(error);
					}
				}

				@Override
				public void onInit(Context ctx, IOCContainer container) {
					// Recurse
					try {
						invoke(context, listener, method, args);
					}
					catch (Throwable e) {
						if(listener != null) {
							listener.onError(SocializeException.wrap(e));
						}
					}
				}
			});
		}
	}

	protected void invoke(Activity context, SocializeListener listener, Method method, Object[] args) throws Throwable {

		SocializeService service = getSocialize();

		if(!service.isAuthenticated() && !method.isAnnotationPresent(NoAuth.class)) {
			doAuthAsync(context, listener, method, args);
		}
		else {
			method.invoke(getBean(), args);
		}
	}

	protected Object getBean() throws MethodNotSupportedException {
		Object bean = Socialize.getBean(delegateBean);

		if(bean != null) {
			return bean;
		}
		else {
			throw new MethodNotSupportedException("No bean with name [" +
					delegateBean +
					"] found");
		}
	}

	protected Activity findActivity(Object[] args) {
		for (Object object : args) {
			if(object instanceof Activity) {
				return (Activity) object;
			}
		}
		return null;
	}

	protected Context findContext(Object[] args) {
		for (Object object : args) {
			if(object instanceof Context) {
				return (Context) object;
			}
		}
		return null;
	}

	protected SocializeListener findListener(Object[] args) {
		for (Object object : args) {
			if(object instanceof SocializeListener) {
				return (SocializeListener) object;
			}
		}
		return null;
	}

	protected synchronized <L extends SocializeListener> void doAuthAsync(final Activity context, final SocializeListener listener, final Method method, final Object[] args) throws Throwable {
		final SocializeService service = getSocialize();

		if(!service.isAuthenticated()) {

			synchronized (this) {
				if(!service.isAuthenticated()) {
					context.runOnUiThread(new Runnable() {

						@Override
						public void run() {

							service.authenticate(context, new SocializeAuthListener() {

								@Override
								public void onError(SocializeException error) {
									if(listener != null) {
										listener.onError(error);
									}
								}

								@Override
								public void onCancel() {
									if(listener != null) {
										listener.onError(new AuthCanceledException("Authentication was canceled by the user"));
									}
								}

								@Override
								public void onAuthSuccess(SocializeSession session) {
									// Recurse
									try {
										invoke(context, listener, method, args);
									}
									catch (Throwable e) {
										if(listener != null) {
											listener.onError(SocializeException.wrap(e));
										}
									}
								}

								@Override
								public void onAuthFail(SocializeException error) {
									if(listener != null) {
										listener.onError(error);
									}
								}
							});
						}
					});
				}
				else {
					// Recurse
					invoke(context, listener, method, args);
				}
			}
		}
		else {
			// Recurse
			invoke(context, listener, method, args);
		}
	}

	protected SocializeServiceImpl getSocialize() {
		return (SocializeServiceImpl) Socialize.getSocialize();
	}
}