//
// MainPage.xaml.cpp
// Implementation of the MainPage class.
//

#include "pch.h"
#include "MainPage.xaml.h"

using namespace OAuth2Live;

using namespace Concurrency;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::Security::Authentication::Web;

using namespace web::http;
using namespace web::http::client;
using namespace web::http::oauth2::experimental;

//
// NOTE: You must set this Live key and secret for app to work.
//
static const utility::string_t s_live_key(U(""));
static const utility::string_t s_live_secret(U(""));


MainPage::MainPage()
    : m_live_oauth2_config(
        s_live_key,
        s_live_secret,
        L"https://login.live.com/oauth20_authorize.srf",
        L"https://login.live.com/oauth20_token.srf",
        L"https://login.live.com/oauth20_desktop.srf")
{
    InitializeComponent();
}

/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached.  The Parameter
/// property is typically used to configure the page.</param>
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
{
	(void) e;	// Unused parameter
}

void OAuth2Live::MainPage::_UpdateButtonState()
{
    const bool has_access_token = !m_live_oauth2_config.token().access_token().empty();
    GetInfoButton->IsEnabled = has_access_token;
    GetContactsButton->IsEnabled = has_access_token;
    GetEventsButton->IsEnabled = has_access_token;

    const bool has_refresh_token = !m_live_oauth2_config.token().refresh_token().empty();
    RefreshTokenButton->IsEnabled = has_refresh_token;
}

void OAuth2Live::MainPage::_GetToken()
{
    m_live_oauth2_config.set_scope(L"wl.basic wl.calendars");

    // Start over, clear tokens and button state.
    m_live_oauth2_config.set_token(oauth2_token());
    AccessToken->Text = "";
    _UpdateButtonState();

    String^ authURI = ref new String(m_live_oauth2_config.build_authorization_uri(true).c_str());
    auto startURI = ref new Uri(authURI);
    String^ redirectURI = ref new String(m_live_oauth2_config.redirect_uri().c_str());
    auto endURI = ref new Uri(redirectURI);

    try
    {
        DebugArea->Text += "> Navigating WebAuthenticationBroker to " + authURI + "\n";

#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
		WebAuthenticationBroker::AuthenticateAndContinue(startURI, endURI, nullptr, WebAuthenticationOptions::None);
#else
        concurrency::create_task(WebAuthenticationBroker::AuthenticateAsync(WebAuthenticationOptions::None, startURI, endURI))
            .then([this](WebAuthenticationResult^ result)
        {
            String^ statusString;

            DebugArea->Text += "< WebAuthenticationBroker returned: ";
            switch (result->ResponseStatus)
            {
                case WebAuthenticationStatus::ErrorHttp:
                {
                    DebugArea->Text += "ErrorHttp: " + result->ResponseErrorDetail + "\n";
                    break;
                }
                case WebAuthenticationStatus::Success:
                {
                    DebugArea->Text += "Success\n";
                    utility::string_t data = result->ResponseData->Data();
                    DebugArea->Text += "Redirected URI:\n" + result->ResponseData + "\n";
                    DebugArea->Text += "> Obtaining token using the redirected URI\n";
                    m_live_oauth2_config.token_from_redirected_uri(data).then([this](pplx::task<void> token_task)
                    {
                        try
                        {
                            token_task.wait();
                            DebugArea->Text += "< Got token\n";
                            AccessToken->Text = ref new String(m_live_oauth2_config.token().access_token().c_str());
                        }
                        catch (const oauth2_exception& e)
                        {
                            DebugArea->Text += "< Failed to get token\n";
                            String^ error = ref new String(utility::conversions::to_string_t(e.what()).c_str());
                            DebugArea->Text += "Error: " + error + "\n";
                        }
                    }, pplx::task_continuation_context::use_current());
                    break;
                }
                default:
                case WebAuthenticationStatus::UserCancel:
                {
                    DebugArea->Text += "UserCancel\n";
                    break;
                }
            }
        });
#endif
    }
    catch (Exception^ ex)
    {
        DebugArea->Text += "< Error launching WebAuthenticationBroker: " + ex->Message + "\n";
    }
}

void OAuth2Live::MainPage::GetTokenButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
{
    if (m_live_oauth2_config.client_key().empty() || m_live_oauth2_config.client_secret().empty())
    {
        DebugArea->Text += "Error: Cannot get token because Live app key or secret is empty. Please see instructions.\n";
    }
    else
    {
        _GetToken();
    }
}

void OAuth2Live::MainPage::GetInfoButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
{
    DebugArea->Text += "> Get user info\n";
    m_live_client->request(methods::GET, U("me"))
    .then([](http_response resp)
    {
        return resp.extract_json();
    })
    .then([this](web::json::value j) -> void
    {
        String^ json_code = ref new String(j.serialize().c_str());
        DebugArea->Text += "< User info (JSON): " + json_code + "\n";
    }, pplx::task_continuation_context::use_current());
}

void OAuth2Live::MainPage::GetContactsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
{
    DebugArea->Text += "> Get user contacts\n";
    m_live_client->request(methods::GET, U("me/contacts"))
    .then([](http_response resp)
    {
        return resp.extract_json();
    })
    .then([this](web::json::value j) -> void
    {
        String^ json_code = ref new String(j.serialize().c_str());
        DebugArea->Text += "< User contacts (JSON): " + json_code + "\n";
    }, pplx::task_continuation_context::use_current());
}

void OAuth2Live::MainPage::GetEventsButtonClick(Platform::Object^ sender, Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
{
    DebugArea->Text += "> Get user events\n";
    m_live_client->request(methods::GET, U("me/events"))
    .then([](http_response resp)
    {
        return resp.extract_json();
    })
    .then([this](web::json::value j) -> void
    {
        String^ json_code = ref new String(j.serialize().c_str());
        DebugArea->Text += "< User calendar events (JSON): " + json_code + "\n";
    }, pplx::task_continuation_context::use_current());
}

void OAuth2Live::MainPage::AccessTokenTextChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs^ e)
{
    http_client_config http_config;
    http_config.set_oauth2(m_live_oauth2_config);
    m_live_client.reset(new http_client(U("https://apis.live.net/v5.0/"), http_config));
    _UpdateButtonState();
}

void OAuth2Live::MainPage::ImplicitGrantUnchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    m_live_oauth2_config.set_implicit_grant(false);
}

void OAuth2Live::MainPage::ImplicitGrantChecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    m_live_oauth2_config.set_implicit_grant(true);
}


void OAuth2Live::MainPage::RefreshTokenButtonClick(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    DebugArea->Text += "> Refreshing token\n";

    m_live_oauth2_config.token_from_refresh().then([this](pplx::task<void> refresh_task)
    {
        try
        {
            refresh_task.wait();
            DebugArea->Text += "< Got token\n";
            AccessToken->Text = ref new String(m_live_oauth2_config.token().access_token().c_str());
        }
        catch (const oauth2_exception& e)
        {
            DebugArea->Text += "< Failed to get token\n";
            String^ error = ref new String(utility::conversions::to_string_t(e.what()).c_str());
            DebugArea->Text += "Error: " + error + "\n";
        }
    }, pplx::task_continuation_context::use_current());
}
