package com.florianmski.tracktoid.ui.fragments.login;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.WebView;
import android.widget.Toast;
import com.crashlytics.android.Crashlytics;
import com.florianmski.tracktoid.BuildConfig;
import com.florianmski.tracktoid.R;
import com.florianmski.tracktoid.TraktoidPrefs;
import com.florianmski.tracktoid.TraktoidTheme;
import com.florianmski.tracktoid.data.provider.TraktoidProvider;
import com.florianmski.tracktoid.rx.observables.TraktObservable;
import com.florianmski.tracktoid.services.sync.SyncAdapter;
import com.florianmski.tracktoid.trakt.TraktManager;
import com.florianmski.tracktoid.ui.activities.HomeActivity;
import com.florianmski.tracktoid.ui.fragments.base.list.ItemWebViewFragment;
import com.uwetrottmann.trakt.v2.TraktV2;
import com.uwetrottmann.trakt.v2.entities.User;
import com.uwetrottmann.trakt.v2.enums.Extended;
import com.uwetrottmann.trakt.v2.exceptions.OAuthUnauthorizedException;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import java.math.BigInteger;
import java.security.SecureRandom;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.observables.AndroidObservable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import rx.subscriptions.Subscriptions;
public class LoginFragment extends ItemWebViewFragment<User>
{
// TODO would be cool to extract the oauth flow in a base oauth fragment
private String clientId;
private String clientSecret;
private String redirectUri;
private String authCode;
private String state;
private Subscription subscriptionUser = Subscriptions.empty();
public static LoginFragment newInstance(Bundle args)
{
LoginFragment f = new LoginFragment();
f.setArguments(args);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
setRefreshOnStart(false);
retryListener = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
// if we already have the token
// if not, start from scratch
if(TraktoidPrefs.INSTANCE.isUserLoggedIn())
getUser();
else
loadUrlForAuthorization();
}
};
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
clientId = getString(R.string.trakt_client_id);
clientSecret = getString(R.string.trakt_client_secret);
redirectUri = getString(R.string.trakt_redirect_uri);
getGroupView().setBackgroundColor(Color.TRANSPARENT);
getGroupView().getSettings().setJavaScriptEnabled(true);
getGroupView().getSettings().setBuiltInZoomControls(true);
CookieManager.getInstance().removeAllCookie();
getToolbar().setVisibility(View.GONE);
loadUrlForAuthorization();
}
protected void loadUrlForAuthorization()
{
state = new BigInteger(130, new SecureRandom()).toString(32);
try
{
OAuthClientRequest request = TraktV2.getAuthorizationRequest(clientId, redirectUri, state, null);
getGroupView().loadUrl(request.getLocationUri());
}
catch (OAuthSystemException e)
{
e.printStackTrace();
}
}
protected Observable<User> createUserObservable()
{
return Observable.create(new TraktObservable<User>()
{
@Override
public User fire() throws OAuthUnauthorizedException
{
return TraktManager.getInstance().users().profile("me", Extended.DEFAULT_MIN);
}
}).doOnNext(new Action1<User>()
{
@Override
public void call(User user)
{
String username = user.username;
TraktoidPrefs.INSTANCE.putUsername(username);
if (!BuildConfig.DEBUG)
Crashlytics.setUserName(username);
// get the account or create one
AccountManager manager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);
Account[] accounts = manager.getAccountsByType(BuildConfig.APPLICATION_ID);
Account account;
if (accounts.length > 0)
account = accounts[0];
else
{
account = new Account(SyncAdapter.ACCOUNT_NAME, BuildConfig.APPLICATION_ID);
manager.addAccountExplicitly(account, null, null);
}
ContentResolver.setIsSyncable(account, TraktoidProvider.AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, TraktoidProvider.AUTHORITY, true);
ContentResolver.addPeriodicSync(account, TraktoidProvider.AUTHORITY, new Bundle(), 24 * 60 * 60);
}
}).doOnCompleted(new Action0()
{
@Override
public void call()
{
HomeActivity.launch(getActivity());
getActivity().finish();
}
});
}
protected void getUser()
{
subscribe(createUserObservable());
}
protected Observable<OAuthAccessTokenResponse> createTokenObservable()
{
return Observable.create(new Observable.OnSubscribe<OAuthAccessTokenResponse>()
{
@Override
public void call(Subscriber<? super OAuthAccessTokenResponse> subscriber)
{
try
{
OAuthAccessTokenResponse response = TraktV2.getAccessToken(clientId, clientSecret, redirectUri, authCode);
String accessToken = response.getAccessToken();
TraktoidPrefs.INSTANCE.putAccessToken(accessToken);
TraktManager.getInstance().setAccessToken(accessToken);
subscriber.onNext(response);
}
catch (OAuthSystemException | OAuthProblemException e)
{
e.printStackTrace();
subscriber.onError(e);
}
subscriber.onCompleted();
}
});
}
protected void getToken()
{
Observable<User> observable = createTokenObservable().flatMap(new Func1<OAuthAccessTokenResponse, Observable<User>>()
{
@Override
public Observable<User> call(OAuthAccessTokenResponse oAuthAccessTokenResponse)
{
return createUserObservable();
}
});
subscribe(observable);
}
protected void subscribe(Observable<User> observable)
{
subscriptions.remove(subscriptionUser);
subscriptionUser = AndroidObservable.bindFragment(this, observable.subscribeOn(Schedulers.io())).subscribe(this);
subscriptions.add(subscriptionUser);
showProgressBar(null);
}
@Override
protected Observable<User> createObservable()
{
return Observable.empty();
}
@Override
protected void refreshView(User data)
{
Toast.makeText(getActivity(), "Welcome " + data.username + "!", Toast.LENGTH_SHORT).show();
}
@Override
public void onCompleted()
{
super.onCompleted();
}
@Override
public TraktoidTheme getTheme()
{
return TraktoidTheme.DEFAULT;
}
@Override
protected RefreshWebViewClient getWebViewClient()
{
return new LoginWebViewClient();
}
public class LoginWebViewClient extends RefreshWebViewClient
{
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (url.startsWith(redirectUri))
{
Uri uri = Uri.parse(url);
String requestState = uri.getQueryParameter(OAuth.OAUTH_STATE);
if (state.equals(requestState))
{
authCode = uri.getQueryParameter(OAuth.OAUTH_CODE);
getToken();
// don't go to redirectUri
return true;
}
}
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onPageFinished(WebView view, String url)
{
super.onPageFinished(view, url);
int paddingTop = (int) (view.getPaddingTop() / view.getScale());
int paddingBottom = view.getPaddingBottom();
// tweak the height of the view
// view.loadUrl("javascript:(function() { " +
// "document.body.style.paddingTop = '" + paddingTop + "px'; " +
// "document.getElementById('auth-form-wrapper').style.top=(parseInt(window.getComputedStyle(document.getElementById('auth-form-wrapper'), null).getPropertyValue('top').replace('px', '')) + " + paddingTop + ") + 'px'\n" +
// // "document.getElementById('auth-bg-wrapper').style.height = ($('#auth-bg-wrapper').height() + " + paddingTop + ") + 'px'; " +
// "})()");
}
}
}