using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DotNetOpenAuth.OpenId.RelyingParty;
using System.Web.Security;
using System.Data.SqlClient;
using edu.jhu.Cas.Util;
using edu.jhu.Cas.Users;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using System.Configuration;

namespace edu.jhu.Cas.Web
{
    public partial class Login : System.Web.UI.Page
    {
        protected string userid, pass, nexturl, lmessage;

        protected void Page_Load(object sender, EventArgs e)
        {
            lmessage = Request.Params["lmessage"];
            userid = Request.Params["userid"];
            pass = Request.Params["password"];
            nexturl = Request.Params["nexturl"];

            if (nexturl == null || nexturl.Length < 1)
            {
                nexturl = "SubmitJob.aspx";
            }

            try
            {
                if (ConfigurationManager.AppSettings["Keystone"] == "true") TryKeystoneLogin();
                if (ConfigurationManager.AppSettings["OpenID"] == "true") TryOpenIdLogin();
                TryCasJobsLogin();
            }
            catch (Exception ex) 
            {
                lmessage = "Login failed. " + ex.Message;
            }
            
            if (userid == null)
            {
                userid = "";
            }
        }

        private void TryCasJobsLogin()
        {
            if (userid != null && userid.Length > 0)
            {
                CasUsers cu = new CasUsers();
                long id = 0;
                try
                {
                    id = cu.GetWebServiceId(userid, pass);
                    if (id <= 0)
                    {
                        throw new Exception("Invalid User ID / Password combination, please try again.");
                    }
                    else
                    {
                        Session["USER"] = id;
                        Session["USERID"] = userid;
                        Global.users.Add(userid);
                        try
                        {
                            cu.HasPrivilege(id, PRIVS.ADMIN);
                            Session["ADMIN"] = true.ToString();
                        }
                        catch
                        {
                            Session["ADMIN"] = false.ToString();
                        }
                        Response.Redirect(nexturl);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("CasJobs error: " + ex.Message);
                }
            }
        }

        private void TryOpenIdLogin()
        {
            IAuthenticationResponse response = null;
            OpenIdRelyingParty openid = new OpenIdRelyingParty();
            response = openid.GetResponse();

            if (response != null)
            {
                try
                {
                    switch (response.Status)
                    {
                        case AuthenticationStatus.Authenticated:
                            CasUsers cu = new CasUsers();
                            long wsid;

                            try
                            {
                                wsid = GetWebServiceId(response.ClaimedIdentifier.ToString());
                            }
                            catch
                            {
                                // no matching account found 
                                Session["OID_RESPONSE"] = response;
                                Response.Redirect("NewAccount.aspx");
                                break;
                            }

                            userid = GetUserId(wsid);

                            Session["USER"] = wsid;
                            Session["USERID"] = userid;
                            Global.users.Add(userid);
                            try
                            {
                                cu.HasPrivilege(wsid, PRIVS.ADMIN);
                                Session["ADMIN"] = true.ToString();
                            }
                            catch
                            {
                                Session["ADMIN"] = false.ToString();
                            }
                            Response.Redirect(nexturl);
                            break;
                        case AuthenticationStatus.Canceled:
                        case AuthenticationStatus.Failed:
                        default:
                            throw new Exception("Authentication failed.");
                            //break;
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("OpenID error: " + ex.Message, ex);
                }
            }
        }

        private void TryKeystoneLogin()
        {
            long? wsid = null;

            try
            {
                if (Request["token"] != null)
                {
                    if (Request["token"] == "")
                    {
                        HttpCookie cookie = new HttpCookie("Keystone");
                        cookie.Expires = DateTime.Now.AddDays(-1);
                        Response.Cookies.Add(cookie);
                    }
                    else
                    {
                        string token = Request["token"];
                        var userAccess = Keystone.Authenticate(token);
                        /*
                        var wsidProperty = userAccess.Token.Tenant.Properties["CasJobs.WebServicesID"];
                        if (wsidProperty == null)
                            throw new Exception("CasJobs.WebServicesID not found.");
                        
                        wsid = (long)(wsidProperty);
                        */

                        HttpCookie cookie = new HttpCookie("Keystone");
                        cookie["token"] = token;
                        Response.Cookies.Add(cookie);

                        try
                        {
                            wsid = Keystone.GetWebServicesId(userAccess.User.Id);
                        }
                        catch (Exception ex)
                        {
                            Response.Redirect("NewAccountKS.aspx");
                        }
                    }
                }
                else
                {
                    HttpCookie cookie = Request.Cookies["Keystone"];
                    if (cookie != null)
                    {
                        string token = cookie["token"];
                        if (token == null || token == "")
                        {
                            HttpCookie fake = new HttpCookie("Keystone");
                            fake.Expires = DateTime.Now.AddDays(-1);
                            Response.Cookies.Add(fake);
                        }
                        else
                        {
                            var userAccess = Keystone.Authenticate(token);
                            /*
                            var wsidProperty = userAccess.Token.Tenant.Properties["CasJobs.WebServicesID"];
                            if (wsidProperty == null)
                                throw new Exception("CasJobs.WebServicesID not found.");
                            
                            wsid = (long)(wsidProperty);
                            */

                            try
                            {
                                wsid = Keystone.GetWebServicesId(userAccess.User.Id);
                            }
                            catch (Exception ex)
                            {
                                Response.Redirect("NewAccountKS.aspx");
                            }
                        }
                    }
                }

                if (wsid.HasValue)
                {
                    CasUsers cu = new CasUsers();
                    Session["USER"] = wsid.Value;
                    userid = GetUserId(wsid.Value);
                    Session["USERID"] = userid;
                    Global.users.Add(userid);
                    try
                    {
                        cu.HasPrivilege(wsid.Value, PRIVS.ADMIN);
                        Session["ADMIN"] = true.ToString();
                    }
                    catch
                    {
                        Session["ADMIN"] = false.ToString();
                    }
                    Response.Redirect(nexturl);
                }
            }
            catch (NotAuthorizedException ex)
            {
                Response.Redirect(ConfigurationManager.AppSettings["Keystone.Portal"] + "?message=" + Uri.EscapeDataString(ex.Message));
            }
            catch (Exception ex)
            {
                throw new Exception("Keystone error: " + ex.Message, ex);
            }
        }

        protected void KeystoneLogin_Click(object sender, EventArgs e)
        {
            Response.Redirect(ConfigurationManager.AppSettings["Keystone.Portal"] + "?callbackUrl=" + HttpUtility.UrlEncode(Request.Url.AbsoluteUri));
        }

        protected void LoginButton_Click(object sender, EventArgs e)
        {
            string discovery = "";

            FetchRequest fetch = new FetchRequest();
            fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, true));

            switch (((ImageButton)sender).CommandName)
            {
                case "LoginGoogle":
                    discovery = OPENID.DISCOVERY_GOOGLE;
                    fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.First, true));
                    fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Last, true));
                    break;
                case "LoginYahoo":
                    discovery = OPENID.DISCOVERY_YAHOO;
                    fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName, true));
                    break;
                case "LoginVAO":
                    discovery = OPENID.DISCOVERY_VAO;
                    fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName, true));
                    break;
                default:
                    break;
            }

            using (OpenIdRelyingParty openid = new OpenIdRelyingParty())
            {
                IAuthenticationRequest request = openid.CreateRequest(discovery);
                request.AddExtension(fetch);
                request.RedirectToProvider();
            }
        }


        // WARNING! There is a copy in NewAccount.aspx.cs. Consider moving somewhere else.
        private string GetUserId(long wsid)
        {
            object o = SqlFactory.scalar("select userid from users where webservicesid = '" + wsid + "'");
            if (o == null)
                throw new Exception("CasJobs user with the given WSID does not exist.");
            
            return o.ToString();
        }

        // WARNING! There is a copy in NewAccount.aspx.cs. Consider moving somewhere else.
        private long GetWebServiceId(string openId)
        {
            object o = SqlFactory.scalar("select wsid from openid where openid = '" + openId + "'");
            if (o == null)
                throw new Exception("CasJobs user with the given OpenID does not exist.");

            return long.Parse(o.ToString());
        }
    }
}