context: using CmsData;
  using CmsData.Codes;
  using CmsWeb.Areas.Manage.Models;
  using CmsWeb.Areas.OnlineReg.Models;
  using CmsWeb.Code;
  using CmsWeb.Membership;
  using CmsWeb.Models;
  using Elmah;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Web.Mvc;
  using System.Web.Routing;
  using System.Web.Security;
  using CmsWeb.Areas.Org.Models.Ticketing;
  using UtilityExtensions;
  using System.Web.WebPages;
  using CMSShared.SharedUtil;
  
  namespace CmsWeb.Areas.OnlineReg.Controllers
  {
      [ValidateInput(false)]
      [RouteArea("OnlineReg", AreaPrefix = "OnlineReg"), Route("{action}/{id?}")]
      public partial class OnlineRegController : CmsController
      {
          private string fromMethod;
  
          [HttpGet]
          [Route("~/OnlineReg/Index/{id:int}")]
          [Route("~/OnlineReg/{id:int}")]
          public ActionResult Index(int? id, bool? testing, string email, bool? login, string registertag,
              bool? showfamily, int? goerid, int? gsid, string source, int? pledgeFund, int? assistedby, int? eventid,
              bool oneTimeGiving = false, bool recurringGiving = false, bool pledge = false)
          {
              Response.NoCache();
  
              var m = new OnlineRegModel(Request, CurrentDatabase, id, testing, email, login, source);
              m.FlowPattern = "Flow2"; // Original Flow
              if (m.IsTicketing)
              {
                  var list = m.TicketingEventList();
                  if (!eventid.HasValue && list.Count == 1)
                      eventid = list[0].EventKey.ToInt();
                  m.EventId = eventid;
                  m.ValidateAssistedBy(assistedby, User);
                  if(m.AssistedBy == null)
                      m.FlowPattern = "FlowTicketing";
              }
  
              var isMissionTrip = (m.org?.IsMissionTrip).GetValueOrDefault();
  
              if (isMissionTrip)
              {
                  m.ProcessType = PaymentProcessTypes.OnlineRegistration;
              }
              else
              {
                  AssignPaymentProcessType(ref m);
              }
  
              if (pledgeFund != null)
              {
                  m.pledgeFundId = pledgeFund.Value;
              }
  
              SetHeaders(m);
  
              var GatewayId = MultipleGatewayUtils.GatewayId(CurrentDatabase, m.ProcessType);
              var gatewayRequired = (m.PayAmount() > 0 || m.ProcessType == PaymentProcessTypes.OneTimeGiving ||
                                     m.ProcessType == PaymentProcessTypes.RecurringGiving);
  
              if (GatewayId.IsNull() && gatewayRequired)
              {
                  return View("OnePageGiving/NotConfigured");
              }
  
              if ((int)GatewayTypes.Pushpay == GatewayId && string.IsNullOrEmpty(
                      MultipleGatewayUtils.Setting(CurrentDatabase, "PushpayMerchant", "", (int)m.ProcessType)))
              {
                  ViewBag.Header = m.Header;
                  ViewBag.Instructions = m.Instructions;
                  return View("OnePageGiving/NotConfigured");
              }
  
              if (m.ManageGiving())
              {
                  RequestManager.SessionProvider.Add($"Campus-{m.Orgid}", m.Campus = Request.QueryString["campus"]);
                  m.DefaultFunds = Util.DefaultFunds = Request.QueryString["funds"];
              }
  
              if (isMissionTrip)
              {
                  if (gsid != null || goerid != null)
                  {
                      m.PrepareMissionTrip(gsid, goerid);
                  }
              }
  
              var pid = m.CheckRegisterLink(registertag, assistedby.HasValue);
              if (m.NotActive())
              {
                  return View("OnePageGiving/NotActive", m);
              }
  
              if (m.MissionTripSelfSupportPaylink.HasValue() && m.GoerId > 0)
              {
                  return Redirect(m.MissionTripSelfSupportPaylink);
              }
  
              string redirectLink = m.org?.RedirectUrl ?? m.masterorg?.RedirectUrl;
              if (redirectLink.IsEmpty() && m.OnlineGiving() && CurrentDatabase.Setting("UseGivingPages"))
              {
                  if (CurrentDatabase.CurrentUserPerson?.CampusId.HasValue == true)
                  {
                      var givingPage = (from g in CurrentDatabase.GivingPages where g.CampusId == CurrentDatabase.CurrentUserPerson.CampusId && g.MainCampusPageFlag == true select g).FirstOrDefault();
                      if (givingPage.IsNull())
                      {
                          var defaultGivingPage = (from g in CurrentDatabase.GivingPages where g.DefaultPage == true select g).FirstOrDefault();
                          redirectLink = "/Give/" + defaultGivingPage.PageUrl;
                          redirectLink += SharedUtil.GivingTypeRedirectLink(pledgeFund, oneTimeGiving, recurringGiving, pledge);
                          return Redirect(redirectLink);
                      }
                      else
                      {
                          redirectLink = "/Give/" + givingPage.PageUrl;
                          redirectLink += SharedUtil.GivingTypeRedirectLink(pledgeFund, oneTimeGiving, recurringGiving, pledge);
                          return Redirect(redirectLink);
                      }
                  }
                  else
                  {
                      var givingPage = (from g in CurrentDatabase.GivingPages where g.DefaultPage == true select g).FirstOrDefault();
                      redirectLink = "/Give/" + givingPage.PageUrl;
                      redirectLink += SharedUtil.GivingTypeRedirectLink(pledgeFund, oneTimeGiving, recurringGiving, pledge);
                  }
              }
  
              if (redirectLink.HasValue())
              {
                  return Redirect(redirectLink);
              }
  
              return RouteRegistration(m, pid, showfamily);
          }
  
          private void AssignPaymentProcessType(ref OnlineRegModel m)
          {
              switch (m.org?.RegistrationTypeId.GetValueOrDefault())
              {
                  case RegistrationTypeCode.OnlineGiving:
                      m.ProcessType = PaymentProcessTypes.OneTimeGiving;
                      break;
                  case RegistrationTypeCode.ManageGiving:
                      m.ProcessType = PaymentProcessTypes.RecurringGiving;
                      break;
                  default:
                      m.ProcessType = PaymentProcessTypes.OnlineRegistration;
                      break;
              }
          }
  
          [HttpGet]
          [Route("~/TestQuestions/{id:int}")]
          public ActionResult TestQuestions(int id)
          {
              var m = new OnlineRegModel(Request, CurrentDatabase, id, null, null, null, null);
              m.ProcessType = PaymentProcessTypes.OnlineRegistration;
              SetHeaders(m);
              var pid = m.CheckRegisterLink(null);
              return RouteRegistration(m, pid, false);
          }
  
          [HttpPost]
          public ActionResult Login(OnlineRegModel m)
          {
              fromMethod = "Login";
              var ret = AccountModel.AuthenticateLogon(m.username, m.password, Request, CurrentDatabase,
                  CurrentImageDatabase);
  
              if (ret.ErrorMessage.HasValue())
              {
                  ModelState.AddModelError("authentication", ret.ErrorMessage);
                  return FlowList(m);
              }
              else if (MembershipService.ShouldPromptForTwoFactorAuthentication(ret.User, CurrentDatabase, Request))
              {
                  Util.MFAUserId = ret.User.UserId;
                  ViewData["hasshell"] = true;
                  var orgId = m.Orgid ?? m.masterorgid;
                  return View("Auth", new AccountInfo
                  {
                      UsernameOrEmail = ret.User.Username,
                      ReturnUrl = RouteExistingRegistration(m) ?? $"/OnlineReg/{orgId}"
                  });
              }
              else
              {
                  AccountModel.FinishLogin(ret.User.Username, CurrentDatabase, CurrentImageDatabase);
                  if (ret.User.UserId.Equals(Util.MFAUserId))
                  {
                      MembershipService.SaveTwoFactorAuthenticationToken(CurrentDatabase, Response);
                      Util.MFAUserId = null;
                  }
              }
  
              Util.OnlineRegLogin = true;
  
              if (m.Orgid == Util.CreateAccountCode)
              {
                  DbUtil.LogActivity("OnlineReg CreateAccount Existing", peopleid: ret.User.PeopleId, datumId: m.DatumId);
                  return
                      Content("/Person2/" +
                              ret.User.PeopleId); // they already have an account, so take them to their page
              }
  
              m.UserPeopleId = ret.User.PeopleId;
              var route = RouteSpecialLogin(m);
              if (route != null)
              {
                  return route;
              }
  
              m.HistoryAdd("login");
              if (m.org != null && m.org.IsMissionTrip == true && m.SupportMissionTrip)
              {
                  PrepareFirstRegistrant(ref m, m.UserPeopleId.Value, false, out OnlineRegPersonModel p);
              }
  
              return FlowList(m);
          }
  
          private void PrepareFirstRegistrant(ref OnlineRegModel m, int pid, bool? showfamily, out OnlineRegPersonModel p)
          {
              p = null;
              if (showfamily != true)
              {
                  // No need to pick family, so prepare first registrant ready to answer questions
                  p = m.LoadExistingPerson(pid, 0);
                  if (p == null)
                      throw new Exception($"No person found with PeopleId = {pid}");
                  p.ProcessType = m.ProcessType;
                  p.ValidateModelForFind(ModelState, 0);
                  if (m.masterorg == null)
                  {
                      if (m.List.Count == 0)
                          m.List.Add(p);
                      else
                          m.List[0] = p;
                  }
              }
          }
  
          [HttpPost]
          public ActionResult NoLogin(OnlineRegModel m)
          {
              fromMethod = "NoLogin";
              // Clicked the register without logging in link
              m.nologin = true;
              m.CreateAnonymousList();
              m.Log("NoLogin");
              return FlowList(m);
          }
  
          [HttpPost]
          public ActionResult YesLogin(OnlineRegModel m)
          {
              fromMethod = "YesLogin";
              // clicked the Login Here button
              m.HistoryAdd("yeslogin");
              m.nologin = false;
              m.List = new List<OnlineRegPersonModel>();
  #if DEBUG
              m.username = "David";
  #endif
              return FlowList(m);
          }
  
          [HttpPost]
          public ActionResult RegisterFamilyMember(int id, OnlineRegModel m)
          {
              // got here by clicking on a link in the Family list
              var msg = m.CheckExpiredOrCompleted();
              if (msg.HasValue())
              {
                  return PageMessage(msg);
              }
  
              fromMethod = "Register";
  
              m.StartRegistrationForFamilyMember(id, ModelState);
  
              // show errors or take them to the Questions page
              return FlowList(m);
          }
  
          [HttpPost]
          public ActionResult Cancel(int id, OnlineRegModel m)
          {
              // After clicking Cancel, remove a person from the completed registrants list
              fromMethod = "Cancel";
              m.CancelRegistrant(id);
              return FlowList(m);
          }
  
          [HttpPost]
          public ActionResult FindRecord(int id, OnlineRegModel m)
          {
              // Anonymous person clicks submit to find their record
              var msg = m.CheckExpiredOrCompleted();
              if (msg.HasValue())
              {
                  return PageMessage(msg);
              }
  
              fromMethod = "FindRecord";
              m.HistoryAdd("FindRecord id=" + id);
              if (id >= m.List.Count)
              {
                  return FlowList(m);
              }
  
gt:             var p = m.List[0];