/*
 * 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.user;

import android.content.Context;
import com.socialize.android.ioc.IBeanFactory;
import com.socialize.api.*;
import com.socialize.auth.*;
import com.socialize.config.SocializeConfig;
import com.socialize.entity.User;
import com.socialize.error.SocializeException;
import com.socialize.listener.SocializeAuthListener;
import com.socialize.listener.user.UserListener;
import com.socialize.listener.user.UserSaveListener;
import com.socialize.log.SocializeLogger;
import com.socialize.notifications.NotificationRegistrationSystem;
import com.socialize.provider.SocializeProvider;
import com.socialize.ui.profile.UserSettings;
import com.socialize.util.BitmapUtils;
import com.socialize.util.DeviceUtils;
import com.socialize.util.StringUtils;

/**
 * @author Jason Polites
 */
public class SocializeUserSystem extends SocializeApi<User, SocializeProvider<User>> implements UserSystem {

	private IBeanFactory<AuthProviderData> authProviderDataFactory;
	private SocializeSessionPersister sessionPersister;
	private DeviceUtils deviceUtils;
	private SocializeLogger logger;
	private AuthProviderInfoBuilder authProviderInfoBuilder;
	private SocializeAuthProviderInfoFactory socializeAuthProviderInfoFactory;
	private NotificationRegistrationSystem notificationRegistrationSystem;
	private BitmapUtils bitmapUtils;

	public SocializeUserSystem(SocializeProvider<User> provider) {
		super(provider);
	}

	@Override
	public void authenticate(Context context, SocializeAuthListener listener, SocializeSessionConsumer sessionConsumer) {
		String consumerKey = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_KEY);
		String consumerSecret = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_SECRET);
		authenticate(context, consumerKey, consumerSecret, listener, sessionConsumer);
	}

	@Override
	public void authenticate(Context context, String consumerKey, String consumerSecret, AuthProviderInfo authProviderInfo, SocializeAuthListener listener, SocializeSessionConsumer sessionConsumer) {
		AuthProviderData data = this.authProviderDataFactory.getBean();
		data.setAuthProviderInfo(authProviderInfo);
		authenticate(context, consumerKey, consumerSecret, data, listener, sessionConsumer, true);
	}

	@Override
	public void authenticateKnownUser(Context context, UserProviderCredentials userProviderCredentials, SocializeAuthListener listener, SocializeSessionConsumer sessionConsumer) {
		String consumerKey = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_KEY);
		String consumerSecret = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_SECRET);
		AuthProviderData authProviderData = this.authProviderDataFactory.getBean();
		authProviderData.setAuthProviderInfo(userProviderCredentials.getAuthProviderInfo());
		authProviderData.setToken3rdParty(userProviderCredentials.getAccessToken());
		authProviderData.setSecret3rdParty(userProviderCredentials.getTokenSecret());
		authProviderData.setUserId3rdParty(userProviderCredentials.getUserId());
		authenticate(context, consumerKey, consumerSecret, authProviderData, listener, sessionConsumer, false);
	}

	@Override
	public void authenticate(Context context, String consumerKey, String consumerSecret, SocializeAuthListener listener, SocializeSessionConsumer sessionConsumer) {
		AuthProviderData authProviderData = authProviderDataFactory.getBean();
		authProviderData.setAuthProviderInfo(socializeAuthProviderInfoFactory.getInstanceForRead());
		authenticate(context, consumerKey, consumerSecret, authProviderData, listener, sessionConsumer, false);
	}

	@Override
	public void authenticate(Context context, AuthProviderType authProviderType, SocializeAuthListener listener, SocializeSessionConsumer sessionConsumer) {
		String consumerKey = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_KEY);
		String consumerSecret = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_SECRET);
		AuthProviderInfo authProviderInfo = authProviderInfoBuilder.getFactory(authProviderType).getInstanceForRead();
		authenticate(context, consumerKey, consumerSecret, authProviderInfo, listener, sessionConsumer);
	}

	@Override
	public void authenticate(Context ctx, String consumerKey, String consumerSecret, AuthProviderData authProviderData, SocializeAuthListener listener, SocializeSessionConsumer sessionConsumer, boolean do3rdPartyAuth) {
		if(checkKeys(consumerKey, consumerSecret, listener)) {
			String udid = deviceUtils.getUDID(ctx);
			String advertiserId = deviceUtils.getAndroidID(ctx);

			if(StringUtils.isEmpty(udid)) {
				if(listener != null) {
					listener.onError(new SocializeException("No UDID provided"));
				}
			}
			else {
				// All Api instances have authenticate, so we can just use any old one
				authenticateAsync(ctx, consumerKey, consumerSecret, udid, advertiserId, authProviderData, listener, sessionConsumer, do3rdPartyAuth);
			}
		}
	}

	@Override
	public SocializeSession authenticateSynchronous(Context context) {
		String consumerKey = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_KEY);
		String consumerSecret = config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_SECRET);
		try {
			if(checkKeys(consumerKey, consumerSecret)) {
				return authenticateSynchronous(context, consumerKey, consumerSecret);
			}
			else {
				throw new SocializeException("Consumer key and/or secret not provided");
			}
		}
		catch (Exception e) {
			logError("Error during synchronous authentication", e);
			return null;
		}
	}

	@Override
	public SocializeSession authenticateSynchronous(Context ctx, String consumerKey, String consumerSecret) throws SocializeException {
		String udid = deviceUtils.getUDID(ctx);
		String advertiserId = deviceUtils.getAndroidID(ctx);
		SocializeSession session = authenticate(ctx, "/authenticate/",consumerKey, consumerSecret, udid, advertiserId);
		return session;
	}

	@Override
	public void saveSession(Context context, SocializeSession session) {
		if(sessionPersister != null) {
			sessionPersister.save(context, session);
		}
	}

	// For mocking
	protected SocializeAuthProviderInfo newSocializeAuthProviderInfo() {
		return new SocializeAuthProviderInfo();
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.action.UserSystem#getUser(com.socialize.api.SocializeSession, long, com.socialize.listener.user.UserListener)
	 */
	@Override
	public void getUser(SocializeSession session, long id, UserListener listener) {
		getAsync(session, ENDPOINT, String.valueOf(id), listener);
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.action.UserSystem#saveUserProfile(android.content.Context, com.socialize.api.SocializeSession, com.socialize.ui.profile.UserProfile, com.socialize.listener.user.UserListener)
	 */
	@Override
	public void saveUserSettings(final Context context, final SocializeSession session, final UserSettings settingsToBeSaved, final UserListener listener) {
		User sessionUser = session.getUser();
		UserSettings sessionSettings = session.getUserSettings();

		boolean wasNotificationsEnabled = sessionSettings.isNotificationsEnabled();

		// Update the settings and the user in the session so they are saved
		sessionUser.setFirstName(settingsToBeSaved.getFirstName());
		sessionUser.setLastName(settingsToBeSaved.getLastName());

		sessionSettings.update(settingsToBeSaved);

		boolean isNotificationsEnabled = sessionSettings.isNotificationsEnabled();

		if(settingsToBeSaved.getImage() != null) {
			sessionUser.setProfilePicData(bitmapUtils.encode(settingsToBeSaved.getImage()));
		}

		// If notifications was not previously enabled, we may need to register.
		if(isNotificationsEnabled && !wasNotificationsEnabled && notificationRegistrationSystem != null) {
			notificationRegistrationSystem.registerC2DMAsync(context);
		}

		saveUserAsync(context, session, sessionUser, listener);
	}

	@Override
	public void saveUserAsync(final Context context, final SocializeSession session, final User userToBeSaved, final UserListener listener) {

		final UserSettings settings = session.getUserSettings();

		settings.update(userToBeSaved);

		String endpoint = ENDPOINT + userToBeSaved.getId() + "/";

		putAsPostAsync(session, endpoint, userToBeSaved, new UserSaveListener() {

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

			@Override
			public void onUpdate(User savedUser) {
				handleUserUpdate(context, session, savedUser, settings, listener);
			}
		});
	}

	protected void handleUserUpdate(final Context context, final SocializeSession session, User savedUser, UserSettings userSettings, final UserListener listener) {

		try {
			SessionLock.lock();

			// Update local in-memory user
			User sessionUser = session.getUser();
			sessionUser.update(savedUser);

			// Save this user to the local session for next load
			if(sessionPersister != null) {
				sessionPersister.saveUser(context, sessionUser, userSettings);
			}

			if(listener != null) {
				listener.onUpdate(sessionUser);
			}
		}
		finally {
			SessionLock.unlock();
		}
	}

	protected boolean checkKeys(String consumerKey, String consumerSecret) {
		return checkKeys(consumerKey, consumerSecret, null);
	}

	protected boolean checkKeys(String consumerKey, String consumerSecret, SocializeAuthListener authListener) {
		return  checkKey("consumer key", consumerKey, authListener) &&
				checkKey("consumer secret", consumerSecret, authListener);
	}
	protected boolean checkKey(String name, String key, SocializeAuthListener authListener) {
		if(StringUtils.isEmpty(key)) {
			String msg = "No key specified in authenticate";
			if(authListener != null) {
				authListener.onError(new SocializeException(msg));
			}
			logErrorMessage(msg);
			return false;
		} else {
			return true;
		}
	}
	protected void logError(String message, Throwable error) {
		if(logger != null) {
			logger.error(message, error);
		}
		else {
			SocializeLogger.e(error.getMessage(), error);
		}
	}

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

	public void setSessionPersister(SocializeSessionPersister sessionPersister) {
		this.sessionPersister = sessionPersister;
	}

	public void setAuthProviderDataFactory(IBeanFactory<AuthProviderData> authProviderDataFactory) {
		this.authProviderDataFactory = authProviderDataFactory;
	}

	public void setDeviceUtils(DeviceUtils deviceUtils) {
		this.deviceUtils = deviceUtils;
	}

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

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

	public void setAuthProviderInfoBuilder(AuthProviderInfoBuilder authProviderInfoBuilder) {
		this.authProviderInfoBuilder = authProviderInfoBuilder;
	}

	public void setSocializeAuthProviderInfoFactory(SocializeAuthProviderInfoFactory socializeAuthProviderInfoFactory) {
		this.socializeAuthProviderInfoFactory = socializeAuthProviderInfoFactory;
	}

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

	public void setBitmapUtils(BitmapUtils bitmapUtils) {
		this.bitmapUtils = bitmapUtils;
	}
}


/*
 * 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.v3;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.facebook.*;
import com.facebook.Session.StatusCallback;
import com.facebook.model.GraphUser;
import com.socialize.auth.AuthProviderResponse;
import com.socialize.config.SocializeConfig;
import com.socialize.error.SocializeException;
import com.socialize.listener.AuthProviderListener;
import com.socialize.listener.SocializeAuthListener;
import com.socialize.listener.SocializeListener;
import com.socialize.networks.SocialNetwork;
import com.socialize.networks.SocialNetworkPostListener;
import com.socialize.networks.facebook.BaseFacebookFacade;
import com.socialize.networks.facebook.OnPermissionResult;
import com.socialize.util.StringUtils;

import java.util.Arrays;

/**
 * @author Jason Polites
 */
public class FacebookFacadeV3 extends BaseFacebookFacade {

	@Override
	public void onActivityResult(Activity context, int requestCode, int resultCode, Intent data) {
		Session activeSession = getActiveSession(context);
		if(activeSession != null) {
			activeSession.onActivityResult(context, requestCode, resultCode, data);
		}
	}

	@Override
	public int getSDKMajorVersion() {
		return 3;
	}

	@Deprecated
	@Override
	public void authenticate(Activity context, String appId, String[] permissions, boolean sso, final AuthProviderListener listener) {
		// Clear current session
		logout(context);
		login(context, appId, permissions, sso, true, listener);
	}

	@Override
	public void authenticate(Activity context, String appId, String[] permissions, boolean sso, boolean read, AuthProviderListener listener) {
		login(context, appId, permissions, sso, read, listener);
	}

	// Protected so we can mock
	protected void login(Activity context, boolean read, final AuthProviderListener listener) {
		login(context, config.getProperty(SocializeConfig.FACEBOOK_APP_ID), (read) ? READ_PERMISSIONS : WRITE_PERMISSIONS, config.getBooleanProperty(SocializeConfig.FACEBOOK_SSO_ENABLED, true), read, listener);
	}

	@Override
	public void onResume(Activity context, SocializeAuthListener listener) {
		Session session = Session.getActiveSession();
	    if (session == null) {
	        session = createNewSession(context, config.getProperty(SocializeConfig.FACEBOOK_APP_ID));
			String strToken = getAccessToken(context);
			if(!StringUtils.isEmpty(strToken)) {
				AccessToken accessToken = AccessToken.createFromExistingAccessToken(
						strToken,
	                    null,
						null,
						null,
						null);

				openSessionWithToken(session, accessToken);

				Session.setActiveSession(session);
			}
	    }
	}

	// So we can mock
	protected Session createNewSession(Activity context, String appId) {
		return new Session.Builder(context).setApplicationId(appId).build();
	}

	// So we can mock
	protected void openSessionWithToken(Session session, AccessToken token) {
		session.open(token, null);
	}

	// So we can mock
	protected void openSessionForRead(Session session, Session.OpenRequest auth) {
		session.openForRead(auth);
	}

	// So we can mock
	protected void openSessionForPublish(Session session, Session.OpenRequest auth) {
		session.openForPublish(auth);
	}

	// Protected so we can mock
	protected void login(Activity context, String appId, String[] permissions, boolean sso, boolean read, final AuthProviderListener listener) {

		Session.OpenRequest auth = new Session.OpenRequest(context);

		if(permissions != null) {
			auth.setPermissions(Arrays.asList(permissions));
		}

		if(sso) {
			auth.setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK);
		}
		else {
			auth.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
		}

		auth.setCallback(createLoginCallback(listener));

		Session session = createNewSession(context, appId);
		Session.setActiveSession(session);

		if(read) {
			openSessionForRead(session ,auth);
		}
		else {
			openSessionForPublish(session ,auth);
		}
	}

	// So we can mock
	protected Session.StatusCallback createLoginCallback(final AuthProviderListener listener) {

		return new Session.StatusCallback() {

			// callback when session changes state
			@Override
			public void call(final Session session, SessionState state, Exception exception) {

				if(exception != null && exception instanceof FacebookOperationCanceledException) {
					if(logger != null) {
						logger.error("Facebook operation failed", exception);
					}
					handleCancel(listener);
					return;
				}

				switch(state) {

					case OPENED:
						if (isSessionOpen(session)) {
							// make request to the /me API
							getUser(session, listener);
						}

						break;

					case CLOSED:
						if(exception != null) {
							handleError(exception, listener);
						}
						break;

					case CLOSED_LOGIN_FAILED:
						if(exception != null) {
							handleAuthFail(exception, listener);
						}
						break;
				}
			}
		};
	}

	protected boolean isSessionOpen(Session session) {
		return session.isOpened();
	}

	// so we can mock
	protected void getUser(final Session session, final AuthProviderListener listener) {
		Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
			// callback after Graph API response with user object
			@Override
			public void onCompleted(GraphUser user, Response response) {
				if(response.getError() != null) {
					handleError(response.getError().getException(), listener);
				}
				else if (user != null) {
					handleResult(session, user, listener);
				}
			}
		});
	}

	// Protected so we can mock
	protected void handleError(Exception exception, SocializeListener listener) {
		if(listener != null) {
			listener.onError(SocializeException.wrap(exception));
		}
	}

	// Protected so we can mock
	protected void handleAuthFail(Exception exception, AuthProviderListener listener) {
		if(listener != null) {
			listener.onAuthFail(SocializeException.wrap(exception));
		}
	}

	// Protected so we can mock
	protected void handleCancel(AuthProviderListener listener) {
		if(listener != null) {
			listener.onCancel();
		}
	}

	// Protected so we can mock
	protected void handleResult(Session session, GraphUser user, AuthProviderListener listener) {
		if(listener != null) {
			AuthProviderResponse response = new AuthProviderResponse();
			response.setUserId(user.getId());
			response.setToken(session.getAccessToken());
			listener.onAuthSuccess(response);
		}
	}

	@Override
	public void extendAccessToken(Activity context, SocializeAuthListener listener) {
		// Do Nothing.  Session refreshes this automatically
	}

	@Override
	public void getCurrentPermissions(Activity context, String token, final OnPermissionResult callback) {
		Session activeSession = getActiveSession(context);

		if(activeSession != null) {
			if(activeSession.getAccessToken().equals(token)) {
				callback.onSuccess((String[])activeSession.getPermissions().toArray(new String[activeSession.getPermissions().size()]));
			}
			else {
				AccessToken accessToken = AccessToken.createFromExistingAccessToken(
						token,
	                    null, null, null, null);

				// We must close the current session
				if(activeSession.isOpened()) {
					activeSession.closeAndClearTokenInformation();
					activeSession = new Session.Builder(context).setApplicationId(config.getProperty(SocializeConfig.FACEBOOK_APP_ID)).build();
				}

				activeSession.open(accessToken, new StatusCallback() {
					@Override
					public void call(Session session, SessionState state, Exception exception) {
						if(exception != null) {
							if(callback != null) {
								callback.onError(SocializeException.wrap(exception));
							}
							else if(logger != null) {
								logger.error("Error accessing permissions for alternate token", exception);
							}
							else {
								Log.e("Socialize", "Error accessing permissions for alternate token", exception);
							}
						}
						else {
							Session.setActiveSession(session);
							if(callback != null) {
								callback.onSuccess((String[])session.getPermissions().toArray(new String[session.getPermissions().size()]));
							}
						}
					}
				});
			}
		}
		else {
			handleNotSignedIn(context, callback);
		}
	}

	@Override
	public void logout(Context context) {
		Session activeSession = getActiveSession(context);
		if(activeSession != null) {
			activeSession.closeAndClearTokenInformation();
		}
	}

	@Deprecated
	@Override
	public boolean isLinked(Context context) {
		return super.isLinked(context) && getActiveSession(context) != null;
	}

	@Override
	protected void doFacebookCall(final Activity context, final Bundle data, final String graphPath, final HttpMethod method, final SocialNetworkPostListener listener) {
		Session activeSession = getActiveSession(context);

		boolean read = method.equals(HttpMethod.GET);

		if(activeSession != null) {
			if(activeSession.isOpened()) {
				Request request = new Request(activeSession, graphPath, data, method, new Request.Callback() {
					@Override
					public void onCompleted(Response response) {
						handleFBResponse(context, response, listener);
					}
				});

				RequestAsyncTask task = new RequestAsyncTask(request);
				task.execute();
			}
			else {
				login(context, read, new AuthProviderListener() {

					@Override
					public void onError(SocializeException error) {
						if(listener != null) {
							listener.onNetworkError(context, SocialNetwork.FACEBOOK, error);
						}

						handleNonListenerError("", error);
					}

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

					@Override
					public void onAuthSuccess(AuthProviderResponse response) {
						doFacebookCall(context, data, graphPath, method, listener);
					}

					@Override
					public void onAuthFail(SocializeException error) {
						if(listener != null) {
							listener.onNetworkError(context, SocialNetwork.FACEBOOK, error);
						}

						handleNonListenerError("", error);

						unlink(context, null);
					}
				});
			}
		}
		else {
			handleNotSignedIn(context, listener);
		}
	}

	// Protected so we can mock
	protected Session getActiveSession(Context context) {
		Session activeSession = Session.getActiveSession();
		if(activeSession == null) {
			activeSession = new Session.Builder(context).setApplicationId(config.getProperty(SocializeConfig.FACEBOOK_APP_ID)).build();
			Session.setActiveSession(activeSession);
		}
		return activeSession;
	}

	// Protected so we can mock
	protected void handleFBResponse(final Activity context, Response response, final SocialNetworkPostListener listener) {
		FacebookRequestError error = response.getError();

		if(error != null) {
			if(listener != null) {
				listener.onNetworkError(context, SocialNetwork.FACEBOOK, error.getException());
			}

			if(logger != null) {
				logger.error(error.getErrorMessage(), error.getException());
			}
			else {
				Log.e("Socialize", error.getErrorMessage(), error.getException());
			}

			switch(error.getCategory()) {

				case AUTHENTICATION_REOPEN_SESSION:
					unlink(context, null);
					break;

				case AUTHENTICATION_RETRY:
					unlink(context, null);
					break;

				case PERMISSION:
					unlink(context, null);
					break;
			}

		}
		else if(listener != null) {
			listener.onAfterPost(context, SocialNetwork.FACEBOOK, response
                    .getGraphObject()
                    .getInnerJSONObject());
		}
	}

	// Protected so we can mock
	protected void handleNotSignedIn(final Activity context, SocializeListener listener) {
		String msg = "Not signed into Facebook";
		if(listener != null) {
			listener.onError(new SocializeException(msg));
		}
		else {
			handleNonListenerError(msg, new SocializeException(msg));
		}
	}

	// Protected so we can mock
	protected void handleNotSignedIn(final Activity context, SocialNetworkPostListener listener) {
		String msg = "Not signed into Facebook";
		if(listener != null) {
			listener.onNetworkError(context, SocialNetwork.FACEBOOK, new SocializeException(msg));
		}
		else {
			handleNonListenerError(msg, new SocializeException(msg));
		}
	}

	// Protected so we can mock
	protected void handleNonListenerError(String msg, Exception error) {
		if(logger != null) {
			logger.error(msg, error);
		}
		else {
			Log.e("Socialize", msg, error);
		}
	}
}


/*
 * 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.activity.ActionUtilsProxy;
import com.socialize.listener.activity.ActionListListener;

import java.lang.reflect.Proxy;

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

	static ActionUtilsProxy proxy;

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

	/**
	 * Gets the application-wide actions.
	 * @param context The current context.
	 * @param start The start index for pagination (0 based).
	 * @param end The end index for pagination (0 based).
	 * @param listener A listener to handle the result.
	 */
	public static void getActionsByApplication (Activity context, int start, int end, ActionListListener listener) {
		proxy.getActionsByApplication(context, start, end, listener);
	}

	/**
	 * Gets the actions of a single user.
	 * @param context The current context.
	 * @param userId The user for whom the actions will be returned.
	 * @param start The start index for pagination (0 based).
	 * @param end The end index for pagination (0 based).
	 * @param listener A listener to handle the result.
	 */
	public static void getActionsByUser (Activity context, long userId, int start, int end, ActionListListener listener) {
		proxy.getActionsByUser(context, userId, start, end, listener);
	}

	/**
	 * Gets the actions for a given entity.
	 * @param context The current context.
	 * @param entityKey The entity key.
	 * @param start The start index for pagination (0 based).
	 * @param end The end index for pagination (0 based).
	 * @param listener A listener to handle the result.
	 */
	public static void getActionsByEntity (Activity context, String entityKey, int start, int end, ActionListListener listener) {
		proxy.getActionsByEntity(context, entityKey, start, end, listener);
	}

	/**
	 * Gets the actions of a single user on a single entity.
	 * @param context The current context.
	 * @param userId The user for whom the actions will be returned.
	 * @param entityKey The entity key.
	 * @param start The start index for pagination (0 based).
	 * @param end The end index for pagination (0 based).
	 * @param listener A listener to handle the result.
	 */
	public static void getActionsByUserAndEntity (Activity context, long userId, String entityKey, int start, int end, ActionListListener listener) {
		proxy.getActionsByUserAndEntity(context, userId, entityKey, start, end, listener);
	}
}


/*
 * Copyright (C) 2010 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.google.gson.stream;

import java.io.Closeable;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

/**
 * Writes a JSON (RFC 4627)
 * encoded value to a stream, one token at a time. The stream includes both
 * literal values (strings, numbers, booleans and nulls) as well as the begin
 * and end delimiters of objects and arrays.
 *
 *
Encoding JSON

 * To encode your data as JSON, create a new {@code JsonWriter}. Each JSON
 * document must contain one top-level array or object. Call methods on the
 * writer as you walk the structure's contents, nesting arrays and objects as
 * necessary:
 *

 *
To write arrays, first call {@link #beginArray()}.
 *       Write each of the array's elements with the appropriate {@link #value}
 *       methods or by nesting other arrays and objects. Finally close the array
 *       using {@link #endArray()}.
 *
To write objects, first call {@link #beginObject()}.
 *       Write each of the object's properties by alternating calls to
 *       {@link #name} with the property's value. Write property values with the
 *       appropriate {@link #value} method or by nesting other objects or arrays.
 *       Finally close the object using {@link #endObject()}.
 *

 *
 *
Example

 * Suppose we'd like to encode a stream of messages such as the following:
 {@code
 * [
 *   {
 *     "id": 912345678901,
 *     "text": "How do I stream JSON in Java?",
 *     "geo": null,
 *     "user": {
 *       "name": "json_newb",
 *       "followers_count": 41
 *      }
 *   },
 *   {
 *     "id": 912345678902,
 *     "text": "@json_newb just use JsonWriter!",
 *     "geo": [50.454722, -104.606667],
 *     "user": {
 *       "name": "jesse",
 *       "followers_count": 2
 *     }
 *   }
 * ]}

 * This code encodes the above structure:
   {@code
 *   public void writeJsonStream(OutputStream out, List<Message> messages) throws IOException {
 *     JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
 *     writer.setIndentSpaces(4);
 *     writeMessagesArray(writer, messages);
 *     writer.close();
 *   }
 *
 *   public void writeMessagesArray(JsonWriter writer, List<Message> messages) throws IOException {
 *     writer.beginArray();
 *     for (Message message : messages) {
 *       writeMessage(writer, message);
 *     }
 *     writer.endArray();
 *   }
 *
 *   public void writeMessage(JsonWriter writer, Message message) throws IOException {
 *     writer.beginObject();
 *     writer.name("id").value(message.getId());
 *     writer.name("text").value(message.getText());
 *     if (message.getGeo() != null) {
 *       writer.name("geo");
 *       writeDoublesArray(writer, message.getGeo());
 *     } else {
 *       writer.name("geo").nullValue();
 *     }
 *     writer.name("user");
 *     writeUser(writer, message.getUser());
 *     writer.endObject();
 *   }
 *
 *   public void writeUser(JsonWriter writer, User user) throws IOException {
 *     writer.beginObject();
 *     writer.name("name").value(user.getName());
 *     writer.name("followers_count").value(user.getFollowersCount());
 *     writer.endObject();
 *   }
 *
 *   public void writeDoublesArray(JsonWriter writer, List<Double> doubles) throws IOException {
 *     writer.beginArray();
 *     for (Double value : doubles) {
 *       writer.value(value);
 *     }
 *     writer.endArray();
 *   }}

 *
 *
Each {@code JsonWriter} may be used to write a single JSON stream.
 * Instances of this class are not thread safe. Calls that would result in a
 * malformed JSON string will fail with an {@link IllegalStateException}.
 *
 * @author Jesse Wilson
 * @since 1.6
 */
public class JsonWriter implements Closeable {

  /** The output data, containing at most one top-level array or object. */
  private final Writer out;

  private final List<JsonScope> stack = new ArrayList<JsonScope>();
  {
    stack.add(JsonScope.EMPTY_DOCUMENT);
  }

  /**
   * A string containing a full set of spaces for a single level of
   * indentation, or null for no pretty printing.
   */
  private String indent;

  /**
   * The name/value separator; either ":" or ": ".
   */
  private String separator = ":";

  private boolean lenient;

  private boolean htmlSafe;

  private String deferredName;

  private boolean serializeNulls = true;

  /**
   * Creates a new instance that writes a JSON-encoded stream to {@code out}.
   * For best performance, ensure {@link Writer} is buffered; wrapping in
   * {@link java.io.BufferedWriter BufferedWriter} if necessary.
   */
  public JsonWriter(Writer out) {
    if (out == null) {
      throw new NullPointerException("out == null");
    }
    this.out = out;
  }

  /**
   * Sets the indentation string to be repeated for each level of indentation
   * in the encoded document. If {@code indent.isEmpty()} the encoded document
   * will be compact. Otherwise the encoded document will be more
   * human-readable.
   *
   * @param indent a string containing only whitespace.
   */
  public final void setIndent(String indent) {
    if (indent.length() == 0) {
      this.indent = null;
      this.separator = ":";
    } else {
      this.indent = indent;
      this.separator = ": ";
    }
  }

  /**
   * Configure this writer to relax its syntax rules. By default, this writer
   * only emits well-formed JSON as specified by RFC 4627. Setting the writer
   * to lenient permits the following:
   *

   *
Top-level values of any type. With strict writing, the top-level
   *       value must be an object or an array.
   *
Numbers may be {@link Double#isNaN() NaNs} or {@link
   *       Double#isInfinite() infinities}.
   *

   */
  public final void setLenient(boolean lenient) {
    this.lenient = lenient;
  }

  /**
   * Returns true if this writer has relaxed syntax rules.
   */
  public boolean isLenient() {
    return lenient;
  }

  /**
   * Configure this writer to emit JSON that's safe for direct inclusion in HTML
   * and XML documents. This escapes the HTML characters {@code <}, {@code >},
   * {@code &} and {@code =} before writing them to the stream. Without this
   * setting, your XML/HTML encoder should replace these characters with the
   * corresponding escape sequences.
   */
  public final void setHtmlSafe(boolean htmlSafe) {
    this.htmlSafe = htmlSafe;
  }

  /**
   * Returns true if this writer writes JSON that's safe for inclusion in HTML
   * and XML documents.
   */
  public final boolean isHtmlSafe() {
    return htmlSafe;
  }

  /**
   * Sets whether object members are serialized when their value is null.
   * This has no impact on array elements. The default is true.
   */
  public final void setSerializeNulls(boolean serializeNulls) {
    this.serializeNulls = serializeNulls;
  }

  /**
   * Returns true if object members are serialized when their value is null.
   * This has no impact on array elements. The default is true.
   */
  public final boolean getSerializeNulls() {
    return serializeNulls;
  }

  /**
   * Begins encoding a new array. Each call to this method must be paired with
   * a call to {@link #endArray}.
   *
   * @return this writer.
   */
  public JsonWriter beginArray() throws IOException {
    writeDeferredName();
    return open(JsonScope.EMPTY_ARRAY, "[");
  }

  /**
   * Ends encoding the current array.
   *
   * @return this writer.
   */
  public JsonWriter endArray() throws IOException {
    return close(JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY, "]");
  }

  /**
   * Begins encoding a new object. Each call to this method must be paired
   * with a call to {@link #endObject}.
   *
   * @return this writer.
   */
  public JsonWriter beginObject() throws IOException {
    writeDeferredName();
    return open(JsonScope.EMPTY_OBJECT, "{");
  }

  /**
   * Ends encoding the current object.
   *
   * @return this writer.
   */
  public JsonWriter endObject() throws IOException {
    return close(JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT, "}");
  }

  /**
   * Enters a new scope by appending any necessary whitespace and the given
   * bracket.
   */
  private JsonWriter open(JsonScope empty, String openBracket) throws IOException {
    beforeValue(true);
    stack.add(empty);
    out.write(openBracket);
    return this;
  }

  /**
   * Closes the current scope by appending any necessary whitespace and the
   * given bracket.
   */
  private JsonWriter close(JsonScope empty, JsonScope nonempty, String closeBracket)
      throws IOException {
    JsonScope context = peek();
    if (context != nonempty && context != empty) {
      throw new IllegalStateException("Nesting problem: " + stack);
    }
    if (deferredName != null) {
      throw new IllegalStateException("Dangling name: " + deferredName);
    }

    stack.remove(stack.size() - 1);
    if (context == nonempty) {
      newline();
    }
    out.write(closeBracket);
    return this;
  }

  /**
   * Returns the value on the top of the stack.
   */
  private JsonScope peek() {
    return stack.get(stack.size() - 1);
  }

  /**
   * Replace the value on the top of the stack with the given value.
   */
  private void replaceTop(JsonScope topOfStack) {
    stack.set(stack.size() - 1, topOfStack);
  }

  /**
   * Encodes the property name.
   *
   * @param name the name of the forthcoming value. May not be null.
   * @return this writer.
   */
  public JsonWriter name(String name) throws IOException {
    if (name == null) {
      throw new NullPointerException("name == null");
    }
    if (deferredName != null) {
      throw new IllegalStateException();
    }
    deferredName = name;
    return this;
  }

  private void writeDeferredName() throws IOException {
    if (deferredName != null) {
      beforeName();
      string(deferredName);
      deferredName = null;
    }
  }

  /**
   * Encodes {@code value}.
   *
   * @param value the literal string value, or null to encode a null literal.
   * @return this writer.
   */
  public JsonWriter value(String value) throws IOException {
    if (value == null) {
      return nullValue();
    }
    writeDeferredName();
    beforeValue(false);
    string(value);
    return this;
  }

  /**
   * Encodes {@code null}.
   *
   * @return this writer.
   */
  public JsonWriter nullValue() throws IOException {
    if (deferredName != null) {
      if (serializeNulls) {
        writeDeferredName();
      } else {
        deferredName = null;
        return this; // skip the name and the value
      }
    }
    beforeValue(false);
    out.write("null");
    return this;
  }

  /**
   * Encodes {@code value}.
   *
   * @return this writer.
   */
  public JsonWriter value(boolean value) throws IOException {
    writeDeferredName();
    beforeValue(false);
    out.write(value ? "true" : "false");
    return this;
  }

  /**
   * Encodes {@code value}.
   *
   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
   *     {@link Double#isInfinite() infinities}.
   * @return this writer.
   */
  public JsonWriter value(double value) throws IOException {
    if (Double.isNaN(value) || Double.isInfinite(value)) {
      throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
    }
    writeDeferredName();
    beforeValue(false);
    out.append(Double.toString(value));
    return this;
  }

  /**
   * Encodes {@code value}.
   *
   * @return this writer.
   */
  public JsonWriter value(long value) throws IOException {
    writeDeferredName();
    beforeValue(false);
    out.write(Long.toString(value));
    return this;
  }

  /**
   * Encodes {@code value}.
   *
   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
   *     {@link Double#isInfinite() infinities}.
   * @return this writer.
   */
  public JsonWriter value(Number value) throws IOException {
    if (value == null) {
      return nullValue();
    }

    writeDeferredName();
    String string = value.toString();
    if (!lenient
        && (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
      throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
    }
    beforeValue(false);
    out.append(string);
    return this;
  }

  /**
   * Ensures all buffered data is written to the underlying {@link Writer}
   * and flushes that writer.
   */
  public void flush() throws IOException {
    out.flush();
  }

  /**
   * Flushes and closes this writer and the underlying {@link Writer}.
   *
   * @throws IOException if the JSON document is incomplete.
   */
  public void close() throws IOException {
    out.close();

    if (peek() != JsonScope.NONEMPTY_DOCUMENT) {
      throw new IOException("Incomplete document");
    }
  }

  private void string(String value) throws IOException {
    out.write("\"");
    for (int i = 0, length = value.length(); i < length; i++) {
      char c = value.charAt(i);

      /*
       * From RFC 4627, "All Unicode characters may be placed within the
       * quotation marks except for the characters that must be escaped:
       * quotation mark, reverse solidus, and the control characters
       * (U+0000 through U+001F)."
       *
       * We also escape '\u2028' and '\u2029', which JavaScript interprets as
       * newline characters. This prevents eval() from failing with a syntax
       * error. http://code.google.com/p/google-gson/issues/detail?id=341
       */
      switch (c) {
      case '"':
      case '\\':
        out.write('\\');
        out.write(c);
        break;

      case '\t':
        out.write("\\t");
        break;

      case '\b':
        out.write("\\b");
        break;

      case '\n':
        out.write("\\n");
        break;

      case '\r':
        out.write("\\r");
        break;

      case '\f':
        out.write("\\f");
        break;

      case '<':
      case '>':
      case '&':
      case '=':
      case '\'':
        if (htmlSafe) {
          out.write(String.format("\\u%04x", (int) c));
        } else {
          out.write(c);
        }
        break;

      case '\u2028':
      case '\u2029':
        out.write(String.format("\\u%04x", (int) c));
        break;

      default:
        if (c <= 0x1F) {
          out.write(String.format("\\u%04x", (int) c));
        } else {
          out.write(c);
        }
        break;
      }
    }
    out.write("\"");
  }

  private void newline() throws IOException {
    if (indent == null) {
      return;
    }

    out.write("\n");
    for (int i = 1; i < stack.size(); i++) {
      out.write(indent);
    }
  }

  /**
   * Inserts any necessary separators and whitespace before a name. Also
   * adjusts the stack to expect the name's value.
   */
  private void beforeName() throws IOException {
    JsonScope context = peek();
    if (context == JsonScope.NONEMPTY_OBJECT) { // first in object
      out.write(',');
    } else if (context != JsonScope.EMPTY_OBJECT) { // not in an object!
      throw new IllegalStateException("Nesting problem: " + stack);
    }
    newline();
    replaceTop(JsonScope.DANGLING_NAME);
  }

  /**
   * Inserts any necessary separators and whitespace before a literal value,
   * inline array, or inline object. Also adjusts the stack to expect either a
   * closing bracket or another element.
   *
   * @param root true if the value is a new array or object, the two values
   *     permitted as top-level elements.
   */
  private void beforeValue(boolean root) throws IOException {
    switch (peek()) {
    case EMPTY_DOCUMENT: // first in document
      if (!lenient && !root) {
        throw new IllegalStateException(
            "JSON must start with an array or an object.");
      }
      replaceTop(JsonScope.NONEMPTY_DOCUMENT);
      break;

    case EMPTY_ARRAY: // first in array
      replaceTop(JsonScope.NONEMPTY_ARRAY);
      newline();
      break;

    case NONEMPTY_ARRAY: // another in array
      out.append(',');
      newline();
      break;

    case DANGLING_NAME: // value for name
      out.append(separator);
      replaceTop(JsonScope.NONEMPTY_OBJECT);
      break;

    case NONEMPTY_DOCUMENT:
        throw new IllegalStateException(
            "JSON must have only one top-level value.");

    default:
      throw new IllegalStateException("Nesting problem: " + stack);
    }
  }
}


/*
 * 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.content.Context;
import android.os.Bundle;
import com.socialize.Socialize;
import com.socialize.error.SocializeException;

/**
 * @author Jason Polites
 *
 */
public abstract class BaseMessageTranslator<T> implements MessageTranslator<T> {

	/* (non-Javadoc)
	 * @see com.socialize.notifications.MessageTranslator#translate(android.content.Context, android.os.Bundle, com.socialize.notifications.NotificationMessage)
	 */
	@Override
	public T translate(Context context, Bundle data, NotificationMessage message) throws SocializeException {

		data.putString( Socialize.ACTION_ID , String.valueOf( message.getActionId() ));
		data.putString( Socialize.ACTION_TYPE , String.valueOf( message.getActionType().name() ));

		// The action detail view expects this, but will handle the -1 case.
		data.putString( Socialize.USER_ID , "-1");

		return translate(context, message);
	}

	public abstract T translate(Context context, NotificationMessage message) throws SocializeException;

}


/*
 * Copyright (C) 2009 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.google.gson;

import com.socialize.google.gson.internal.Streams;
import com.socialize.google.gson.stream.JsonReader;
import com.socialize.google.gson.stream.JsonToken;
import com.socialize.google.gson.stream.MalformedJsonException;

import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

/**
 * A parser to parse Json into a parse tree of {@link JsonElement}s
 *
 * @author Inderjeet Singh
 * @author Joel Leitch
 * @since 1.3
 */
public final class JsonParser {

  /**
   * Parses the specified JSON string into a parse tree
   *
   * @param json JSON text
   * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
   * @throws JsonParseException if the specified text is not valid JSON
   * @since 1.3
   */
  public JsonElement parse(String json) throws JsonSyntaxException {
    return parse(new StringReader(json));
  }

  /**
   * Parses the specified JSON string into a parse tree
   *
   * @param json JSON text
   * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
   * @throws JsonParseException if the specified text is not valid JSON
   * @since 1.3
   */
  public JsonElement parse(Reader json) throws JsonIOException, JsonSyntaxException {
    try {
      JsonReader jsonReader = new JsonReader(json);
      JsonElement element = parse(jsonReader);
      if (!element.isJsonNull() && jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonSyntaxException("Did not consume the entire document.");
      }
      return element;
    } catch (MalformedJsonException e) {
      throw new JsonSyntaxException(e);
    } catch (IOException e) {
      throw new JsonIOException(e);
    } catch (NumberFormatException e) {
      throw new JsonSyntaxException(e);
    }
  }

  /**
   * Returns the next value from the JSON stream as a parse tree.
   *
   * @throws JsonParseException if there is an IOException or if the specified
   *     text is not valid JSON
   * @since 1.6
   */
  public JsonElement parse(JsonReader json) throws JsonIOException, JsonSyntaxException {
    boolean lenient = json.isLenient();
    json.setLenient(true);
    try {
      return Streams.parse(json);
    } catch (StackOverflowError e) {
      throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
    } catch (OutOfMemoryError e) {
      throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
    } catch (JsonParseException e) {
      if (e.getCause() instanceof EOFException) {
        return JsonNull.INSTANCE;
      }
      throw e;
    } finally {
      json.setLenient(lenient);
    }
  }
}


/*
 * 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.content.Intent;
import android.os.Bundle;
import com.socialize.util.AppUtils;
import com.socialize.util.EntityLoaderUtils;

/**
 * @author Jason Polites
 *
 */
public abstract class ActivityLauncher extends BaseLauncher {

	private AppUtils appUtils;
	private EntityLoaderUtils entityLoaderUtils;

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

		if(entityLoaderUtils != null) {
			entityLoaderUtils.initEntityLoader();
		}

		Class<?>[] activityClasses = getActivityClasses();
		Class<?> activityClass = null;

		for (Class<?> cls : activityClasses) {
			if(appUtils.isActivityAvailable(context, cls)) {
				activityClass = cls;
				break;
			}
		}

		if(activityClass != null) {
			Intent intent = newIntent(context, activityClass);
			intent.putExtras(data);
			handleIntent(context, intent, data);
			context.startActivity(intent);
			return true;
		}

		return false;
	}

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

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

	// So we can mock
	protected Intent newIntent(Activity context, Class<?> activityClass) {
		return new Intent(context, activityClass);
	}

	protected void handleIntent(Activity context, Intent intent, Bundle data) {}

	public abstract Class<?>[] getActivityClasses();

}


/*
 * 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 android.app.Activity;
import com.socialize.api.SocializeSession;
import com.socialize.demo.SDKDemoActivity;
import com.socialize.error.SocializeException;
import com.socialize.listener.SocializeAuthListener;
import com.socialize.networks.SocialNetwork;
import com.socialize.networks.SocialNetworkPostListener;
import com.socialize.networks.facebook.FacebookUtils;
import org.json.JSONException;
import org.json.JSONObject;

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

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

		// We need additional permissions for this
		String[] permissions = {"user_tagged_places"};

		FacebookUtils.linkForRead(this, new SocializeAuthListener() {

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

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

			@Override
			public void onAuthSuccess(SocializeSession session) {

				FacebookUtils.get(ListCheckinsActivity.this, "me/tagged_places", null, new SocialNetworkPostListener() {

					@Override
					public void onNetworkError(Activity context, SocialNetwork network, Exception error) {
						handleError(context, error);
					}

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

					@Override
					public void onAfterPost(Activity parent, SocialNetwork socialNetwork, JSONObject responseObject) {
						try {
							handleResult(responseObject.toString(4));
						}
						catch (JSONException e) {
							handleError(parent, e);
						}
					}
				});
			}

			@Override
			public void onAuthFail(SocializeException error) {
				handleError(ListCheckinsActivity.this, error);
			}
		}, permissions);
	}

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

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


/*
 * 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.action;

import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import com.socialize.Socialize;
import com.socialize.entity.SocializeAction;
import com.socialize.log.SocializeLogger;
import com.socialize.ui.util.CompatUtils;
import com.socialize.ui.view.EntityView;
import com.socialize.util.Drawables;

/**
 * @author Jason Polites
 */
public class ActionDetailView extends EntityView {

	private ActionDetailLayoutView actionLayoutView;

	private View view;

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

	/* (non-Javadoc)
	 * @see com.socialize.ui.view.EntityView#getView(android.os.Bundle, java.lang.Object[])
	 */
	@Override
	protected View getView(Bundle bundle, Object... bundleKeys) {
		if (bundleKeys != null) {
			if(actionLayoutView == null) {
				actionLayoutView = container.getBean("actionDetailLayoutView", bundleKeys);

				LayoutParams scrollViewLayout = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);
				LayoutParams childViewLayout = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);

				ScrollView scrollView = new ScrollView(getContext());
				scrollView.setFillViewport(true);
				scrollView.setLayoutParams(scrollViewLayout);
				scrollView.addView(actionLayoutView, childViewLayout);

				LinearLayout layout = new LinearLayout(getContext());
				LayoutParams masterParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);

				layout.setLayoutParams(masterParams);

				CompatUtils.setBackgroundDrawable(layout, ((Drawables)container.getBean("drawables")).getDrawable("slate.png", true, true, true));

				layout.addView(scrollView);

				view = layout;
			}

			return view;
		}
		else {
			SocializeLogger.e("No user id specified for " + getClass().getSimpleName());
			return null;
		}
	}

	/* (non-Javadoc)
	 * @see com.socialize.ui.view.EntityView#getEntityKeys()
	 */
	@Override
	protected String[] getBundleKeys() {
		return new String[]{Socialize.USER_ID, Socialize.ACTION_ID};
	}

	public void onProfileUpdate() {
		if(actionLayoutView != null) {
			actionLayoutView.onProfileUpdate();
		}
	}

	public void reload(String userId, String actionId) {
		if(actionLayoutView != null) {
			actionLayoutView.setUserId(userId);
			actionLayoutView.setActionId(actionId);
			actionLayoutView.reload();
		}
	}

	public SocializeAction getCurrentAction() {
		return (actionLayoutView == null) ? null : actionLayoutView.getCurrentAction();
	}

	@Override
	public View getLoadingView() {
		return null;
	}
}


/*
 * 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.listener.like;

import com.socialize.entity.Like;
import com.socialize.error.SocializeApiError;
import com.socialize.error.SocializeException;
import com.socialize.log.SocializeLogger;

/**
 * @author Jason Polites
 */
public abstract class IsLikedListener extends LikeGetListener {

	/* (non-Javadoc)
	 * @see com.socialize.listener.AbstractSocializeListener#onGet(com.socialize.entity.SocializeObject)
	 */
	@Override
	public void onGet(Like like) {
		if(like != null) {
			onLiked(like);
		}
		else {
			onNotLiked();
		}
	}

	/* (non-Javadoc)
	 * @see com.socialize.listener.AbstractSocializeListener#onError(com.socialize.error.SocializeException)
	 */
	@Override
	public void onError(SocializeException error) {

		if(error instanceof SocializeApiError) {
			SocializeApiError aError = (SocializeApiError) error;

			if(aError.getResultCode() != 404) {
				SocializeLogger.e(error.getMessage(), error);
			}
		}
		else {
			SocializeLogger.e(error.getMessage(), error);
		}

		onNotLiked();
	}

	public abstract void onLiked(Like like);

	public abstract void onNotLiked();

}


/*
 * 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.share;

import android.app.Activity;
import android.content.Intent;
import android.text.Html;
import com.socialize.ShareUtils;
import com.socialize.api.action.ShareType;
import com.socialize.entity.Entity;
import com.socialize.entity.PropagationInfo;
import com.socialize.entity.SocializeAction;
import com.socialize.networks.PostData;
import com.socialize.networks.SocialNetworkListener;

/**
 * @author Jason Polites
 */
public class EmailShareHandler extends IntentShareHandler {

	private SharePostDataFactory sharePostDataFactory;

	/* (non-Javadoc)
	 * @see com.socialize.share.AbstractShareHandler#handle(android.app.Activity, com.socialize.entity.SocializeAction, java.lang.String, com.socialize.entity.PropagationInfo, com.socialize.share.ShareHandlerListener)
	 */
	@Override
	protected void handle(Activity context, SocializeAction action, String text, PropagationInfo info, SocialNetworkListener listener) throws Exception {

		boolean shareCancelled = false;

		Entity entity = action.getEntity();

		PostData postData = sharePostDataFactory.create(entity, info, text, isHtml(), true);

		if(listener != null) {
			shareCancelled = listener.onBeforePost(context, null, postData);
		}

		if(!shareCancelled) {
			String title = String.valueOf(postData.getPostValues().get(ShareUtils.EXTRA_TITLE));
			String body = String.valueOf(postData.getPostValues().get(ShareUtils.EXTRA_TEXT));
			Intent msg = getIntent(context);
			msg.putExtra(Intent.EXTRA_TITLE, title);

			if(isHtml()) {
				msg.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(body));
			}
			else {
				msg.putExtra(Intent.EXTRA_TEXT, body);
			}

            msg.putExtra(Intent.EXTRA_SUBJECT, String.valueOf(postData.getPostValues().get(ShareUtils.EXTRA_SUBJECT)));

			startActivity(context, msg, title);
		}

		if(listener != null) {
			listener.onAfterPost(context, null, null);
		}
	}

	protected void startActivity(Activity context, Intent intent, String title) {
		Intent chooser = Intent.createChooser(intent, title);
		chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		context.startActivity(chooser);
	}

	@Override
	protected String getMimeType() {
		return "message/rfc822";
	}

	protected boolean isHtml() {
		return true;
	}

	/* (non-Javadoc)
	 * @see com.socialize.share.AbstractShareHandler#getShareType()
	 */
	@Override
	protected ShareType getShareType() {
		return ShareType.EMAIL;
	}

    @SuppressWarnings("unused")
    public void setSharePostDataFactory(SharePostDataFactory sharePostDataFactory) {
        this.sharePostDataFactory = sharePostDataFactory;
    }
}


/*
 * 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.entity;

import org.json.JSONException;
import org.json.JSONObject;

/**
 * @author Jason Polites
 *
 */
public class DeviceRegistrationFactory extends SocializeObjectFactory<DeviceRegistration> {

	/* (non-Javadoc)
	 * @see com.socialize.entity.SocializeObjectFactory#postFromJSON(org.json.JSONObject, com.socialize.entity.SocializeObject)
	 */
	@Override
	protected void postFromJSON(JSONObject from, DeviceRegistration to) throws JSONException {
		// Never done
	}

	/* (non-Javadoc)
	 * @see com.socialize.entity.SocializeObjectFactory#postToJSON(com.socialize.entity.SocializeObject, org.json.JSONObject)
	 */
	@Override
	protected void postToJSON(DeviceRegistration from, JSONObject to) throws JSONException {
		to.put("gcm_registration_id", from.getRegistrationId());
		to.put("device_type", "Android");
		to.put("service_type", "ANDROID_GCM");
	}

	/* (non-Javadoc)
	 * @see com.socialize.entity.JSONFactory#instantiateObject(org.json.JSONObject)
	 */
	@Override
	public Object instantiateObject(JSONObject object) {
		return new DeviceRegistration();
	}

}


/*
 * 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.twitter;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import com.socialize.SocializeActionProxy;
import com.socialize.api.SocializeSession;
import com.socialize.api.action.share.SocialNetworkShareListener;
import com.socialize.entity.Entity;
import com.socialize.error.SocializeException;
import com.socialize.listener.SocializeAuthListener;
import com.socialize.networks.SocialNetwork;
import com.socialize.networks.SocialNetworkListener;
import com.socialize.networks.SocialNetworkPostListener;

import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.Map;

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

	static TwitterUtilsProxy proxy;

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

	/**
	 * Links the current user to their Twitter account.  This method will request authentication from the user if their credentials are not currently known.
	 * @param context The current activity.
	 * @param listener A listener to handle the result.
	 */
	public static void link (Activity context, SocializeAuthListener listener) {
		proxy.link(context, listener);
	}

	/**
	 * Links the current user to their Twitter account using an existing Twitter oAuth token and secret.
	 * @param context The current activity.
	 * @param token The user's Twitter token.
	 * @param secret The user's Twitter token secret.
	 * @param listener A listener to handle the result.
	 */
	public static void link (Activity context, String token, String secret, SocializeAuthListener listener) {
		proxy.link(context, token, secret, listener);
	}

	/**
	 * Removes the association between a user and their Twitter account.
	 * This method executes synchronously.
	 * @param context The current activity.
	 */
	public static void unlink (Context context) {
		proxy.unlink(context);
	}

	/**
	 * Determines if the current user is linked to a Twitter account.
	 * @param context The current activity.
	 * @return True if the current user is already linked to a Twitter account.  False otherwise.
	 */
	public static boolean isLinked(Context context) {
		return proxy.isLinked(context);
	}

	/**
	 * Determines if Twitter has been configured correctly for the application.
	 * @param context The current activity.
	 * @return True if Twitter is configured correctly.  False otherwise.
	 */
	public static boolean isAvailable(Context context) {
		return proxy.isAvailable(context);
	}

	/**
	 * Sets the Twitter App credentials for the application.  This sets the same configuration properties as twitter.consumer.key and twitter.consumer.secret
	 * @param context The current context.
	 * @param consumerKey The Twitter App Consumer Key
	 * @param consumerSecret The Twitter App Consumer Secret
	 */
	public static void setCredentials(Context context, String consumerKey, String consumerSecret) {
		proxy.setCredentials(context, consumerKey, consumerSecret);
	}

	/**
	 * Returns the user's Twitter access token.
	 * @param context The current context.
	 * @return The user's Twitter access token or null if the user is not linked to a Twitter account.
	 */
	public static String getAccessToken(Context context) {
		return proxy.getAccessToken(context);
	}

	/**
	 * Returns the user's Twitter access token secret.
	 * @param context The current context.
	 * @return The user's Twitter access token secret or null if the user is not linked to a Twitter account.
	 */
	public static String getTokenSecret(Context context) {
		return proxy.getTokenSecret(context);
	}

	/**
	 * "Tweets" an entity.  A "share" event will be recorded in Socialize and the entity URL generated by Socialize will be posted to the user's Twitter feed.
	 * If the user is not currently linked to a Twitter account they will be prompted to authenticate.
	 * @param context The current activity.
	 * @param entity The entity to be tweeted.
	 * @param text The text to be posted along with the tweet.
	 * @param listener A listener to handle the result.
	 */
	public static void tweetEntity(final Activity context, final Entity entity, final String text, final SocialNetworkShareListener listener) {
		if(proxy.isLinked(context)) {
			proxy.tweetEntity(context, entity, text, listener);
		}
		else {
			proxy.link(context, new SocializeAuthListener() {

				@Override
				public void onError(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}

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

				@Override
				public void onAuthSuccess(SocializeSession session) {
					proxy.tweetEntity(context, entity, text, listener);
				}

				@Override
				public void onAuthFail(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}
			});
		}
	}

	/**
	 * Performs a simple HTTP POST to the Twitter resource endpoint specified. If the user is not currently linked to a Twitter account they will be prompted to authenticate.
	 * @param context The current Activity.
	 * @param resource The resource to be called.  NOTE: This should NOT include the full url (e.g. http://api.twitter.com) but just the resource.
	 * Changing the full URL endpoint can be done via the SocialNetworkPostListener onBeforePost callback.
	 * @param postData The parameters to be posted.
	 * @param listener A listener to handle the result.
	 */
	public static void post(final Activity context, final String resource, final Map<String, Object> postData, final SocialNetworkPostListener listener) {
		if(proxy.isLinked(context)) {
			proxy.post(context, resource, postData, listener);
		}
		else {
			proxy.link(context, new SocializeAuthListener() {

				@Override
				public void onError(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}

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

				@Override
				public void onAuthSuccess(SocializeSession session) {
					proxy.post(context, resource, postData, listener);
				}

				@Override
				public void onAuthFail(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}
			});
		}
	}

	/**
	 * Performs a simple HTTP GET to the Twitter resource endpoint specified. If the user is not currently linked to a Twitter account they will be prompted to authenticate.
	 * @param context The current Activity.
	 * @param resource The resource to be called.  NOTE: This should NOT include the full url (e.g. http://api.twitter.com) but just the resource.
	 * Changing the full URL endpoint can be done via the SocialNetworkPostListener onBeforePost callback.
	 * @param params The parameters to be posted.
	 * @param listener A listener to handle the result.
	 */
	public static void get(final Activity context, final String resource, final Map<String, Object> params, final SocialNetworkPostListener listener) {
		if(proxy.isLinked(context)) {
			proxy.get(context, resource, params, listener);
		}
		else {
			proxy.link(context, new SocializeAuthListener() {

				@Override
				public void onError(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}

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

				@Override
				public void onAuthSuccess(SocializeSession session) {
					proxy.get(context, resource, params, listener);
				}

				@Override
				public void onAuthFail(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}
			});
		}
	}

	/**
	 * Performs a simple "tweet". If the user is not currently linked to a Twitter account they will be prompted to authenticate.
	 * @param context The current Activity.
	 * @param tweet The Tweet to be tweeted.
	 * @param listener A listener to handle the result.
	 */
	public static void tweet(final Activity context, final Tweet tweet, final SocialNetworkListener listener) {
		if(proxy.isLinked(context)) {
			proxy.tweet(context, tweet, listener);
		}
		else {
			proxy.link(context, new SocializeAuthListener() {

				@Override
				public void onError(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}

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

				@Override
				public void onAuthSuccess(SocializeSession session) {
					proxy.tweet(context, tweet, listener);
				}

				@Override
				public void onAuthFail(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}
			});
		}
	}

	/**
	 * Publishes a photo to a user's Twitter feed.  If the user is not currently linked to a Twitter account they will be prompted to authenticate.
	 * @param context The current Activity.
	 * @param photo The image to be tweeted.
	 * @param listener A listener to handle the result.
	 */
	public static void tweetPhoto(final Activity context, final PhotoTweet photo, final SocialNetworkPostListener listener) {
		if(proxy.isLinked(context)) {
			proxy.tweetPhoto(context, photo, listener);
		}
		else {
			proxy.link(context, new SocializeAuthListener() {

				@Override
				public void onError(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}

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

				@Override
				public void onAuthSuccess(SocializeSession session) {
					proxy.tweetPhoto(context, photo, listener);
				}

				@Override
				public void onAuthFail(SocializeException error) {
					if(listener != null) {
						listener.onNetworkError(context, SocialNetwork.TWITTER, error);
					}
				}
			});
		}
	}

	/**
	 * Returns image data suitable for posting to twitter.
	 * @param context The current context.
	 * @param imagePath The path to the image.
	 * @return A byte array containing the bytes to be posted.
	 * @throws IOException
	 */
	public static byte[] getImageForPost(Activity context, Uri imagePath) throws IOException {
		return proxy.getImageForPost(context, imagePath);
	}

	/**
	 * Returns image data suitable for posting to twitter.
	 * @param context The current context.
	 * @param image The image to be compressed.
	 * @param format The compression format to use (one of JPEG or PNG).
	 * @return A byte array containing the bytes to be posted.
	 * @throws IOException
	 */
	public static byte[] getImageForPost(Activity context, Bitmap image, CompressFormat format) throws IOException {
		return proxy.getImageForPost(context, image, format);
	}
}


/*
 * 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;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import com.socialize.Socialize;
import com.socialize.auth.*;
import com.socialize.auth.facebook.FacebookAuthProviderInfo;
import com.socialize.entity.User;
import com.socialize.entity.UserFactory;
import com.socialize.log.SocializeLogger;
import com.socialize.ui.profile.UserSettings;
import com.socialize.ui.profile.UserSettingsFactory;
import com.socialize.util.JSONUtils;
import com.socialize.util.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Persists session data to private preferences.
 * @author Jason Polites
 */
public class PreferenceSessionPersister implements SocializeSessionPersister {

	private static final String PREFERENCES = "SocializeSession";

	private static final String SOCIALIZE_VERSION = "socialize_version";
	private static final String USER_AUTH_DATA = "user_auth_data";

	private UserFactory userFactory;
	private UserSettingsFactory userSettingsFactory;
	private SocializeSessionFactory sessionFactory;

	private SocializeLogger logger = null;
	private JSONUtils jsonUtils;

	public PreferenceSessionPersister() {
		super();
	}

	public PreferenceSessionPersister(UserFactory userFactory, SocializeSessionFactory sessionFactory) {
		super();
		this.userFactory = userFactory;
		this.sessionFactory = sessionFactory;
	}

	@Override
	public synchronized void saveUser(Context context, User user, UserSettings userSettings) {
		SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
		Editor editor = prefs.edit();
		saveUser(editor, user, userSettings);
		editor.commit();
	}

	@Override
	public void saveUserSettingsAsync(final Context context, final UserSettings settings) {
		new Thread() {
			@Override
			public void run() {
				SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
				Editor editor = prefs.edit();
				try {
					String userJSON = userSettingsFactory.toJSON(settings).toString();
					editor.putString("user-settings", userJSON);
					editor.commit();
				}
				catch (JSONException e) {
					if(logger != null) {
						logger.error("Failed to serialize user settings object", e);
					}
					else {
						SocializeLogger.e("Failed to serialize user settings object", e);
					}
				}
			}
		}.start();
	}

	public synchronized void saveUser(Editor editor, User user, UserSettings userSettings) {
		if(user != null) {
			try {
				String userJSON = userFactory.toJSON(user).toString();
				editor.putString("user", userJSON);
			}
			catch (JSONException e) {
				if(logger != null) {
					logger.error("Failed to serialize user object", e);
				}
				else {
					SocializeLogger.e("Failed to serialize user object", e);
				}
			}

			if(userSettings == null) {
				// Legacy
				userSettings = createSettingsLegacy(user);
			}

			try {
				String userJSON = userSettingsFactory.toJSON(userSettings).toString();
				editor.putString("user-settings", userJSON);
			}
			catch (JSONException e) {
				if(logger != null) {
					logger.error("Failed to serialize user settings object", e);
				}
				else {
					SocializeLogger.e("Failed to serialize user settings object", e);
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.socialize.api.SocializeSessionPersister#delete(android.content.Context, com.socialize.auth.AuthProviderType)
	 */
	@Override
	public synchronized void delete(Context context, AuthProviderType type) {

		SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);

		String authData = prefs.getString(USER_AUTH_DATA, null);

		Editor editor = prefs.edit();

		if(!StringUtils.isEmpty(authData)) {
			 UserProviderCredentialsMap map = jsonUtils.fromJSON(authData, UserProviderCredentialsMap.class);

			 map.remove(type);

			 editor.putString(USER_AUTH_DATA, jsonUtils.toJSON(map));
		}
		else {
			editor.putString(USER_AUTH_DATA, jsonUtils.toJSON(makeDefaultUserProviderCredentials()));
		}

		editor.commit();
	}

	protected UserProviderCredentials makeDefaultUserProviderCredentials() {
		DefaultUserProviderCredentials userProviderCredentials = newDefaultUserProviderCredentials();
		SocializeAuthProviderInfo info = new SocializeAuthProviderInfo();
		userProviderCredentials.setAuthProviderInfo(info);
		return userProviderCredentials;
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.SocializeSessionPersister#save(android.content.Context, com.socialize.api.SocializeSession)
	 */
	@Override
	public synchronized void save(Context context, SocializeSession session) {
		SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);

		Editor editor = prefs.edit();

		editor.putString("consumer_key", session.getConsumerKey());
		editor.putString("consumer_secret", session.getConsumerSecret());
		editor.putString("consumer_token", session.getConsumerToken());
		editor.putString("consumer_token_secret", session.getConsumerTokenSecret());

		editor.putString(SOCIALIZE_VERSION, Socialize.VERSION);

		String userProviderCredentials = jsonUtils.toJSON(session.getUserProviderCredentials());

		editor.putString(USER_AUTH_DATA, userProviderCredentials);

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

		saveUser(editor, user, settings);

		editor.commit();
	}

	@SuppressWarnings("deprecation")
	protected UserSettings createSettingsLegacy(User user) {
		UserSettings userSettings = new UserSettings();
		userSettings.setAutoPostFacebook(user.isAutoPostToFacebook());
		userSettings.setAutoPostTwitter(user.isAutoPostToTwitter());
		userSettings.setFirstName(user.getFirstName());
		userSettings.setLastName(user.getLastName());
		userSettings.setLocationEnabled(user.isShareLocation());
		userSettings.setNotificationsEnabled(user.isNotificationsEnabled());
		return userSettings;
	}

	protected UserProviderCredentialsMap loadUserProviderCredentials(SharedPreferences prefs) {
		String authData = prefs.getString(USER_AUTH_DATA, null);

		UserProviderCredentialsMap map = null;

		if(StringUtils.isEmpty(authData)) {

			String userId3rdParty = prefs.getString("3rd_party_userid", null);
			String token3rdParty = prefs.getString("3rd_party_token", null);

			int iProviderType = prefs.getInt("3rd_party_type", AuthProviderType.SOCIALIZE.getId());

			AuthProviderType type = AuthProviderType.valueOf(iProviderType);

			map = newDefaultUserProviderCredentialsMap();

			// Legacy
			if(type.equals(AuthProviderType.FACEBOOK)) {

				// Legacy, must only be FB
				DefaultUserProviderCredentials data = newDefaultUserProviderCredentials();

				String appId3rdParty = prefs.getString("3rd_party_app_id", null);

				data.setAccessToken(token3rdParty);
				data.setUserId(userId3rdParty);

				FacebookAuthProviderInfo info = new FacebookAuthProviderInfo();
				info.setAppId(appId3rdParty);

				data.setAuthProviderInfo(info);

				map.put(type, data);
			}
			else {
				if(!type.equals(AuthProviderType.SOCIALIZE)) {
					if(logger != null) {
						logger.warn("Unexpected auth type [" +
								type +
								"].  Legacy session loading only supports [" +
								AuthProviderType.FACEBOOK +
								"] or [" +
								AuthProviderType.SOCIALIZE +
								"].");
					}
					type = AuthProviderType.SOCIALIZE;
				}
			}

			// Always add Socialize
			SocializeAuthProviderInfo info = new SocializeAuthProviderInfo();
			DefaultUserProviderCredentials data = newDefaultUserProviderCredentials();
			data.setAuthProviderInfo(info);
			map.put(AuthProviderType.SOCIALIZE, data);
		}
		else {
			map = jsonUtils.fromJSON(authData, UserProviderCredentialsMap.class);
		}

		return map;
	}

	protected DefaultUserProviderCredentials newDefaultUserProviderCredentials() {
		return new DefaultUserProviderCredentials();
	}

	protected DefaultUserProviderCredentialsMap newDefaultUserProviderCredentialsMap() {
		return new DefaultUserProviderCredentialsMap();
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.SocializeSessionPersister#load(android.content.Context)
	 */
	@Override
	public synchronized WritableSession load(Context context) {

		SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);

		String key = prefs.getString("consumer_key", null);
		String secret = prefs.getString("consumer_secret", null);

		UserProviderCredentialsMap userProviderCredentials = loadUserProviderCredentials(prefs);

		WritableSession session = sessionFactory.create(key, secret, userProviderCredentials);

		session.setRestored(true);

		String oauth_token = prefs.getString("consumer_token", null);
		String oauth_token_secret = prefs.getString("consumer_token_secret", null);

		if(StringUtils.isEmpty(oauth_token) || StringUtils.isEmpty(oauth_token_secret)) {
			return null;
		}

		session.setConsumerToken(oauth_token);
		session.setConsumerTokenSecret(oauth_token_secret);

		String userJson = prefs.getString("user", null);

		User user = null;

		if(userJson != null) {
			try {
				JSONObject json = new JSONObject(userJson);
				user = userFactory.fromJSON(json);
				session.setUser(user);
			}
			catch (JSONException e) {
				if(logger != null) {
					logger.error("Failed to deserialize user object", e);
				}
				else {
					SocializeLogger.e("Failed to deserialize user object", e);
				}
			}
		}

		String userSettingsJson = prefs.getString("user-settings", null);

		if(userSettingsJson != null) {
			try {
				JSONObject json = new JSONObject(userSettingsJson);
				UserSettings userSettings = userSettingsFactory.fromJSON(json);
				session.setUserSettings(userSettings);
			}
			catch (JSONException e) {
				if(logger != null) {
					logger.error("Failed to deserialize user settings object", e);
				}
				else {
					SocializeLogger.e("Failed to deserialize user settings object", e);
				}
			}
		}
		else if(user != null) {
			session.setUserSettings(createSettingsLegacy(user));
		}

		return session;
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.SocializeSessionPersister#delete(android.content.Context)
	 */
	@Override
	public synchronized void delete(Context context) {
		SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
		prefs.edit().clear().commit();
	}

	public void setUserFactory(UserFactory userFactory) {
		this.userFactory = userFactory;
	}

	public void setSessionFactory(SocializeSessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

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

	public void setJsonUtils(JSONUtils jsonUtils) {
		this.jsonUtils = jsonUtils;
	}

	public void setUserSettingsFactory(UserSettingsFactory userSettingsFactory) {
		this.userSettingsFactory = userSettingsFactory;
	}
}


/*
 * 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.activity;

import android.app.Activity;
import com.socialize.Socialize;
import com.socialize.listener.activity.ActionListListener;

/**
 * @author Jason Polites
 *
 */
public class SocializeActionUtils implements ActionUtilsProxy {

	private ActivitySystem activitySystem;

	/* (non-Javadoc)
	 * @see com.socialize.api.action.activity.ActivityUtilsProxy#getActivityByApplication(android.app.Activity, int, int, com.socialize.listener.activity.UserActivityListListener)
	 */
	@Override
	public void getActionsByApplication(Activity context, int start, int end, ActionListListener listener) {
		activitySystem.getActivityByApplication(Socialize.getSocialize().getSession(), start, end, listener);
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.action.activity.ActivityUtilsProxy#getActivityByUser(android.app.Activity, com.socialize.entity.User, int, int, com.socialize.listener.activity.UserActivityListListener)
	 */
	@Override
	public void getActionsByUser(Activity context, long userId, int start, int end, ActionListListener listener) {
		activitySystem.getActivityByUser(Socialize.getSocialize().getSession(), userId, start, end, listener);
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.action.activity.ActivityUtilsProxy#getActivityByEntity(android.app.Activity, com.socialize.entity.Entity, int, int, com.socialize.listener.activity.UserActivityListListener)
	 */
	@Override
	public void getActionsByEntity(Activity context, String entityKey, int start, int end, ActionListListener listener) {
		activitySystem.getActivityByEntity(Socialize.getSocialize().getSession(), entityKey, start, end, listener);
	}

	/* (non-Javadoc)
	 * @see com.socialize.api.action.activity.ActivityUtilsProxy#getActivityByUserAndEntity(android.app.Activity, com.socialize.entity.User, com.socialize.entity.Entity, int, int, com.socialize.listener.activity.UserActivityListListener)
	 */
	@Override
	public void getActionsByUserAndEntity(Activity context, long userId, String entityKey, int start, int end, ActionListListener listener) {
		activitySystem.getActivityByUserAndEntity(Socialize.getSocialize().getSession(), userId, entityKey, start, end, listener);
	}

	public void setActivitySystem(ActivitySystem activitySystem) {
		this.activitySystem = activitySystem;
	}
}


/*
 * 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.util;

import com.socialize.android.ioc.BeanBuilder;
import com.socialize.error.SocializeException;

/**
 * @author Jason Polites
 *
 */
public class DefaultObjectUtils implements ObjectUtils {

	private BeanBuilder builder;

	/* (non-Javadoc)
	 * @see com.socialize.util.ObjectUtils#construct(java.lang.String)
	 */
	@Override
	public <T> T construct(String className) throws SocializeException {
		try {
			return builder.construct(className);
		}
		catch (Exception e) {
			throw new SocializeException(e);
		}
	}

	public void setBuilder(BeanBuilder builder) {
		this.builder = builder;
	}
}