﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Security;
using ADAdmPwd.Models;

namespace ADAdmPwd.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Account/Index
        [HttpGet]
        //[AllowAnonymous]
        public Task<ActionResult> Index()
        {
            return Task.FromResult((ActionResult)View());
        }

        //
        // POST: /Account/Index
        [HttpPost]
        //[AllowAnonymous]
        [ValidateAntiForgeryToken]
        public Task<ActionResult> Index(IndexViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return Task.FromResult((ActionResult)View(model));
            }

            try
            {
                if (string.IsNullOrEmpty(model.UserName))
                {
                    throw new ValidationException(GetDisplayName<IndexViewModel>(m => m.UserName) + " が不正です.");
                }

                if (string.IsNullOrEmpty(model.OldPassword))
                {
                    throw new ValidationException(GetDisplayName<IndexViewModel>(m => m.OldPassword) + " が不正です.");
                }

                if (string.IsNullOrEmpty(model.NewPassword))
                {
                    throw new ValidationException(GetDisplayName<IndexViewModel>(m => m.NewPassword) + " が不正です.");
                }

                if (string.IsNullOrEmpty(model.ConfirmPassword))
                {
                    throw new ValidationException(GetDisplayName<IndexViewModel>(m => m.ConfirmPassword) + " が不正です.");
                }

                if (!Membership.ValidateUser(model.UserName, model.OldPassword))
                {
                    throw new ValidationException(GetDisplayName<IndexViewModel>(m => m.UserName) + " または " + GetDisplayName<IndexViewModel>(m => m.OldPassword) + " が不正です.");
                }

                if (model.NewPassword != model.ConfirmPassword)
                {
                    throw new ValidationException(GetDisplayName<IndexViewModel>(m => m.NewPassword) + " と " + GetDisplayName<IndexViewModel>(m => m.ConfirmPassword) + " が異なります.");
                }

                var user = Membership.GetUser(model.UserName);

                user.ChangePassword(model.OldPassword, model.NewPassword);
            }
            catch (Exception x)
            {
                this.ModelState.AddModelError(string.Empty, x.Message);
                return Task.FromResult((ActionResult)View(model));
            }

            ViewBag.IsPasswordChanged = true;

            return Task.FromResult((ActionResult)View(new IndexViewModel { UserName = model.UserName }));
        }

        static string GetDisplayName<TModel>(Expression<Func<TModel, object>> expression)
        {
            var type = typeof(TModel);
            var propertyList = default(IEnumerable<string>);

            switch (expression.Body.NodeType)
            {
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    var ue = expression.Body as UnaryExpression;
                    propertyList = (ue != null ? ue.Operand : null).ToString().Split(".".ToCharArray()).Skip(1);
                    break;
                default:
                    propertyList = expression.Body.ToString().Split(".".ToCharArray()).Skip(1);
                    break;
            }

            var propertyName = propertyList.Last();
            var properties = propertyList.Take(propertyList.Count() - 1).ToArray();

            var expr = default(Expression);

            foreach (string property in properties)
            {
                var propertyInfo = type.GetProperty(property);

                expr = Expression.Property(expr, type.GetProperty(property));
                type = propertyInfo.PropertyType;
            }

            var attr = (DisplayAttribute)type.GetProperty(propertyName).GetCustomAttributes(typeof(DisplayAttribute), true).SingleOrDefault();

            if (attr == null)
            {
                MetadataTypeAttribute metadataType = (MetadataTypeAttribute)type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
                if (metadataType != null)
                {
                    var property = metadataType.MetadataClassType.GetProperty(propertyName);
                    if (property != null)
                    {
                        attr = (DisplayAttribute)property.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
                    }
                }
            }

            return (attr != null) ? attr.Name : String.Empty;
        }
    }
}