using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;

using EQNetwork.Objects;
using EQNetwork.Utility;
using EQNetwork.Interfaces;

namespace EQNetwork.Services
{
    public partial class EQApiService : IEQApiService
    {
        public EQTask User_Get(string username, Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User user = User_Get(username);
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public User User_Get(string username)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid,
                "Username", username
                );
            return new User(ParseXml(MakeApi2Request("User_GetNode", parms)).FirstChild);
        }

        public EQTask User_Get(int userId, Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User user = User_Get(userId);
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public User User_Get(int userId)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid,
                "UserId", userId
                );
            return new User(ParseXml(MakeApi2Request("User_GetNode", parms)).FirstChild);
        }

        public EQTask User_Get(Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User user = User_Get();
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public User User_Get()
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            return new User(ParseXml(MakeApi2Request("User_GetNode", parms)).FirstChild);
        }

        public EQTask User_Create(User user, Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_Create(ref user);
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public void User_Create(ref User user)
        {
            Parameters parms = new Parameters();
            parms.AddChangedProperties(user);
            int userId = int.Parse(ParseXml(MakeApi2Request("User_Create", parms)).InnerText);
            user = User_Get(userId);
        }

        public EQTask User_AcceptEmailConfirmation(Guid confirmationGuid, Action<User, Guid, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    Guid sessionGuid;
                    User user = User_AcceptEmailConfirmation(out sessionGuid, confirmationGuid);
                    onComplete(user, sessionGuid, null);
                }
                catch (Exception ex) { onComplete(null, Guid.Empty, new EQException(ex)); }
            });
        }
        public User User_AcceptEmailConfirmation(out Guid sessionGuid, Guid confirmationGuid)
        {
            Parameters parms = new Parameters(
                "ConfirmationGuid", confirmationGuid
                );
            XmlNode root = ParseXml(MakeApi2Request("User_AcceptEmailConfirmation", parms));
            sessionGuid = Guid.Empty;
            User user = null;
            foreach (XmlNode node in root.ChildNodes)
            {
                if (node.Name.Equals("AcceptConfirmation", StringComparison.OrdinalIgnoreCase))
                {
                    foreach (XmlNode child in node.ChildNodes)
                    {
                        if (child.Name.Equals("SessionGuid", StringComparison.OrdinalIgnoreCase))
                            sessionGuid = new Guid(child.InnerText);
                        if (child.Name.Equals("User", StringComparison.OrdinalIgnoreCase))
                            user = new User(child);
                    }
                }
            }
            return user;
        }

        public EQTask User_Delete(Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_Delete();
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_Delete()
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            ParseXml(MakeApi2Request("User_Delete", parms));
        }

        public EQTask User_Delete(User user, Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_Delete(user);
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_Delete(User user)
        {
            User_Delete((int)user.UserId);
        }

        public EQTask User_Delete(int userId, Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_Delete(userId);
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_Delete(int userId)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid,
                "UserId", userId
                );
            ParseXml(MakeApi2Request("User_Delete", parms));
        }

        // User_Update2.aspx
        public EQTask User_Update(User user, Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_Update(ref user);
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public void User_Update(ref User user)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            parms.AddChangedProperties(user);
            user.ClearPropertyChanges();
            // User_Update2 does not need *all* of the parameters passed like User_Update does
            user = new User(ParseXml(MakeApi2Request("User_Update2", parms)).FirstChild);
        }

        // User_UpdateFacebook.aspx
        public EQTask User_UpdateFacebook(bool? isLinked, string accessToken, DateTime? expirationDate, Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User user = User_UpdateFacebook(isLinked, accessToken, expirationDate);
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public User User_UpdateFacebook(bool? isLinked, string accessToken, DateTime? expirationDate)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid,
                "AccessToken", accessToken,
                "ExpirationDate", expirationDate
                );
            if (isLinked != null)
                parms.Add("IsLinked", ((bool)isLinked) ? "y" : "n");

            return new User(ParseXml(MakeApi2Request("User_UpdateFacebook", parms)).FirstChild);
        }

        // User_UpdateTwitter.aspx
        public EQTask User_UpdateTwitter(bool? isLinked, string twitterUserId, string screenName, string oAuthToken, string oAuthTokenSecret, Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User user = User_UpdateTwitter(isLinked, twitterUserId, screenName, oAuthToken, oAuthTokenSecret);
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public User User_UpdateTwitter(bool? isLinked, string twitterUserId, string screenName, string oAuthToken, string oAuthTokenSecret)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid,
                "twUserId", twitterUserId,
                "twScreenName", screenName,
                "twOAuthToken", oAuthToken,
                "twOAuthTokenSecret", oAuthTokenSecret
                );
            if (isLinked != null)
                parms.Add("TwitterIsLinked", ((bool)isLinked) ? "y" : "n");

            return new User(ParseXml(MakeApi2Request("User_UpdateTwitter", parms)).FirstChild);
        }

        public EQTask User_ListCollections(ListCollectionsContext listCollectionsContext, PagingParameters pagingParameters, Action<List<Collection>, bool, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    List<Collection> collections = User_ListCollections(listCollectionsContext, pagingParameters);
                    onComplete(collections, pagingParameters.hasMore, null);
                }
                catch (Exception ex) { onComplete(null, false, new EQException(ex)); }
            });
        }
        public List<Collection> User_ListCollections(ListCollectionsContext listCollectionsContext, PagingParameters pagingParameters)
        {
            return User_ListCollections(null, listCollectionsContext, pagingParameters);
        }

        public EQTask User_ListCollections(int? userId,
            ListCollectionsContext listCollectionsContext,
            PagingParameters pagingParameters,
            Action<List<Collection>, bool, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    List<Collection> collections = User_ListCollections(userId, listCollectionsContext, pagingParameters);
                    onComplete(collections, pagingParameters.hasMore, null);
                }
                catch (Exception ex) { onComplete(null, false, new EQException(ex)); }
            });
        }
        public List<Collection> User_ListCollections(int? userId,
            ListCollectionsContext listCollectionsContext,
            PagingParameters pagingParameters)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            if (userId != null)
                parms.Add("UserId", userId);
            parms.AddChangedProperties(listCollectionsContext);
            parms.AddChangedProperties(pagingParameters);

            return Collection.ParseList(pagingParameters, MakeApi2Request("User_ListCollections", parms));
        }

        // User_EmailAccounts.aspx
        public EQTask User_EmailAccounts(string email, Action<string, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    string message = User_EmailAccounts(email);
                    onComplete(message, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public string User_EmailAccounts(string email)
        {
            Parameters parms = new Parameters(
                "Email", email
                );
            return (ParseXml(MakeApi2Request("User_EmailAccounts", parms)).FirstChild.InnerText);
        }

        public EQTask User_Search(string search, PagingParameters pagingParameters, Action<List<User>, bool, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    List<User> users = User_Search(search, pagingParameters);
                    onComplete(users, pagingParameters.hasMore, null);
                }
                catch (Exception ex) { onComplete(null, false, new EQException(ex)); }
            });
        }
        public List<User> User_Search(string search, PagingParameters pagingParameters)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            if (search != null)
                parms.Add("Search", search);
            parms.AddChangedProperties(pagingParameters);
            return User.ParseList(pagingParameters, MakeApi2Request("User_Search", parms));
        }

        public EQTask User_ListUser(ListUsersContext listUsersContext, PagingParameters pagingParameters, Action<List<User>, bool, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    List<User> users = User_ListUser(listUsersContext, pagingParameters);
                    onComplete(users, pagingParameters.hasMore, null);
                }
                catch (Exception ex) { onComplete(null, false, new EQException(ex)); }
            });
        }
        public List<User> User_ListUser(ListUsersContext listUsersContext, PagingParameters pagingParameters)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            parms.AddChangedProperties(listUsersContext);
            parms.AddChangedProperties(pagingParameters);
            return User.ParseList(pagingParameters, MakeApi2Request("User_ListUser", parms));
        }

        public EQTask User_ListFavoritedContentFiles(
            ListContentFilesContext listContentFilesContext,
            PagingParameters pagingParameters,
            Action<List<ContentFile>, bool, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    List<ContentFile> contentFiles = User_ListFavoritedContentFiles(listContentFilesContext, pagingParameters);
                    onComplete(contentFiles, pagingParameters.hasMore, null);
                }
                catch (Exception ex) { onComplete(null, false, new EQException(ex)); }
            });
        }
        public List<ContentFile> User_ListFavoritedContentFiles(
            ListContentFilesContext listContentFilesContext,
            PagingParameters pagingParameters)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            parms.AddChangedProperties(listContentFilesContext);
            parms.AddChangedProperties(pagingParameters);
            return ContentFile.ParseList(pagingParameters, MakeApi2Request("User_ListFavoritedContentFiles", parms));
        }

        public EQTask User_RequestPasswordReset(string username, Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_RequestPasswordReset(username);
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_RequestPasswordReset(string username)
        {
            Parameters parms = new Parameters(
                "Username", username
                );
            ParseXml(MakeApi2Request("User_RequestPasswordReset", parms));
        }

        public EQTask User_ResendConfirmationEmail(Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_ResendConfirmationEmail();
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_ResendConfirmationEmail()
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            ParseXml(MakeApi2Request("User_ResendConfirmationEmail", parms));
        }

        public EQTask User_ResetPassword(Guid passwordResetGuid, string password, Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_ResetPassword(passwordResetGuid, password);
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_ResetPassword(Guid passwordResetGuid, string password)
        {
            Parameters parms = new Parameters(
                "PasswordResetGuid", passwordResetGuid,
                "Password", password
                );
            ParseXml(MakeApi2Request("User_ResetPassword", parms));
        }

        public EQTask User_Purchase(PurchaseContext purchaseContext, Action<PurchaseTransaction, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    PurchaseTransaction purchaseTransaction = User_Purchase(purchaseContext);
                    onComplete(purchaseTransaction, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public PurchaseTransaction User_Purchase(PurchaseContext purchaseContext)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            parms.AddChangedProperties(purchaseContext);
            return new PurchaseTransaction(ParseXml(MakeApi2Request("User_Purchase", parms)));
        }

        public EQTask User_FacebookFindFriends(string search, Db.SocialSearchType socialSearchType, PagingParameters pagingParameters, Action<List<Friend>, bool, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    List<Friend> friends = User_FacebookFindFriends(search, socialSearchType, pagingParameters);
                    onComplete(friends, pagingParameters.hasMore, null);
                }
                catch (Exception ex) { onComplete(null, false, new EQException(ex)); }
            });
        }
        public List<Friend> User_FacebookFindFriends(string search, Db.SocialSearchType socialSearchType, PagingParameters pagingParameters)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            if (search != null) parms.Add("Search", search);
            switch (socialSearchType)
            {
                case Db.SocialSearchType.SearchAll:
                    break;
                case Db.SocialSearchType.SearchEqMembers:
                    parms.Add("OnlyEqMembers", true);
                    break;
                case Db.SocialSearchType.SearchNonEqMembers:
                    parms.Add("OnlyNonEqMembers", true);
                    break;
            }
            parms.AddChangedProperties(pagingParameters);
            return Friend.ParseList(pagingParameters, MakeApi2Request("User_FacebookFindFriends", parms));
        }

        public EQTask User_TwitterFindFriends(string search, Db.SocialSearchType socialSearchType, PagingParameters pagingParameters, Action<List<Friend>, bool, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    List<Friend> friends = User_TwitterFindFriends(search, socialSearchType, pagingParameters);
                    onComplete(friends, pagingParameters.hasMore, null);
                }
                catch (Exception ex) { onComplete(null, false, new EQException(ex)); }
            });
        }
        public List<Friend> User_TwitterFindFriends(string search, Db.SocialSearchType socialSearchType, PagingParameters pagingParameters)
        {
            Parameters parms = new Parameters(
                "SessionGuid", _eq.SessionGuid
                );
            if (search != null) parms.Add("Search", search);
            switch (socialSearchType)
            {
                case Db.SocialSearchType.SearchAll:
                    break;
                case Db.SocialSearchType.SearchEqMembers:
                    parms.Add("OnlyEqMembers", true);
                    break;
                case Db.SocialSearchType.SearchNonEqMembers:
                    parms.Add("OnlyNonEqMembers", true);
                    break;
            }
            parms.AddChangedProperties(pagingParameters);
            return Friend.ParseList(pagingParameters, MakeApi2Request("User_TwitterFindFriends", parms));
        }

        public EQTask User_UpdateSocial(bool isSocialOn, int fbBits, int twitterBits, Action<User, EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User user = User_UpdateSocial(isSocialOn, fbBits, twitterBits);
                    onComplete(user, null);
                }
                catch (Exception ex) { onComplete(null, new EQException(ex)); }
            });
        }
        public User User_UpdateSocial(bool isSocialOn, int fbBits, int twitterBits)
        {
            Parameters parms = new Parameters(
                "isSocialOn", isSocialOn,
                "fbBits", fbBits,
                "twitterBits", twitterBits
                );
            return new User(ParseXml(MakeApi2Request("User_UpdateSocial", parms)).FirstChild);
        }

        public EQTask User_SocialAdd(string action, int? collectionId, int? contentFileId, bool force, Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_SocialAdd(action, collectionId, contentFileId, force);
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_SocialAdd(string action, int? collectionId, int? contentFileId, bool force)
        {
            Parameters parms = new Parameters(
                "Action", action,
                "Force", force
                );
            if (collectionId != null) parms.Add("CollectionId", collectionId);
            if (contentFileId != null) parms.Add("ContentFileId", contentFileId);
            ParseXml(MakeApi2Request("User_SocialAdd", parms));
        }

        public EQTask User_SocialRemove(string action, int? collectionId, int? contentFileId, bool force, Action<EQException> onComplete)
        {
            return new EQTask((EQTask task) =>
            {
                try
                {
                    User_SocialRemove(action, collectionId, contentFileId, force);
                    onComplete(null);
                }
                catch (Exception ex) { onComplete(new EQException(ex)); }
            });
        }
        public void User_SocialRemove(string action, int? collectionId, int? contentFileId, bool force)
        {
            Parameters parms = new Parameters(
                "Action", action,
                "Force", force
                );
            if (collectionId != null) parms.Add("CollectionId", collectionId);
            if (contentFileId != null) parms.Add("ContentFileId", contentFileId);
            ParseXml(MakeApi2Request("User_SocialRemove", parms));
        }
    }
}
