using System;
using System.Collections.Generic;
using System.Linq;
namespace mxdemo.Mind
{
    #region models
    /// 
    /// 选科组合
    /// 
    public class SubjectGroup
    {
        public int Limitation { get; set; } // 人数限制
        public string Name { get; set; }
        public string Code { get; set; }
        public long Id { get; set; }
    }
    /// 
    /// 志愿
    /// 
    public class Preference
    {
        public int Rank { get; set; } // 第1、2、3志原 越小优先级越高
        public long GroupId {get;set;}
        public long StudentId { get; set; }
        public long Id { get; set; }
    }
    /// 
    /// 得分情况
    /// 
    public class GroupScore
    {
        public decimal Score { get; set; }
        public long StudentId { get; set; }
        public long GroupId { get; set; }
    }
    /// 
    /// 学生信息
    /// 
    public class Student
    {
        public long Id { get; set; }
        public string No { get; set; }
        public string Name { get; set; }
    }
    public class ElectiveElement
    {
        public Student Student { get; set; }
        public Preference Preference { get; set; }
        public SubjectGroup Group { get; set; }
        // 计算属性
        public int PreferenceRank { get; set; } // 志愿排名
        public int GroupRank { get; set; }  // 组合排名,即成绩排名(组合全校排名),同样越小优先级越高
    }
    #endregion
    public class ElectiveResult
    {
        public ElectiveResult(List students)
        {
            this.UnmatchedStudents = students;
        }
        public List MatchedStudents { get; set; }
            = new List();
        public Dictionary> MatchedDetails { get; set; }
            = new Dictionary>();
        public List UnmatchedStudents { get; set; }
        public void AppendMatched(ElectiveElement element)
        {
            // 应该还有更多细节需要考虑
            var appendStudent = element.Student;
            if (MatchedStudents.Contains(appendStudent)) return;
            if (UnmatchedStudents.Contains(appendStudent))
                RemoveUnmatched(appendStudent);
            var appendGroup = MatchedDetails.ContainsKey(element.Group)
                ? MatchedDetails[element.Group]
                : new List();
            if (appendGroup.Count < element.Group.Limitation)
            {
                MatchedDetails[element.Group] = appendGroup;
                AddMatchedAndDetails(element);
            }
            else
            {
                AddUnmatched(appendStudent);
            }
        }
        private void AddMatchedAndDetails(ElectiveElement element)
        {
            // 应该还有更多细节需要考虑
            MatchedDetails[element.Group].Add(element);
            MatchedStudents.Add(element.Student);
        }
        private void AddUnmatched(Student student)
        {
            // 应该还有更多细节需要考虑
            UnmatchedStudents.Add(student);
        }
        private void RemoveUnmatched(Student student)
        {
            // 应该还有更多细节需要考虑
            UnmatchedStudents.Remove(student);
        }
    }
    public interface IElectiveStrategy
    {
        /// 
        /// 从开放选科中取出按优先级分组的选科
        /// 
        /// 
        List> GetAllPrioritizedGroups();
        /// 
        /// 参与这次运算的志愿优先级集合
        /// 
        /// 
        List> GetAllPrioritizedPreferenceRanks();
        /// 
        /// 参与这次运算的所有学生
        /// 
        /// 
        List GetAllStudents();
    }
    public abstract class ElectiveEngine: IComparer
    { 
        protected IElectiveStrategy ElectiveStrategy { get; set; }
        protected ElectiveEngine(IElectiveStrategy electiveStrategy)
        {
            ElectiveStrategy = electiveStrategy;
        }
        public ElectiveResult Execute()
        {
            var prioritizedGroups = ElectiveStrategy.GetAllPrioritizedGroups();
            var prioritizedPreferenceRanks = ElectiveStrategy.GetAllPrioritizedPreferenceRanks();
            var allStudents = ElectiveStrategy.GetAllStudents();
            var electiveResult = new ElectiveResult(allStudents);
            foreach(var groups in prioritizedGroups)
            {
                foreach(var ranks in prioritizedPreferenceRanks)
                {
                    var students = electiveResult.UnmatchedStudents;
                    var elements = BuildElectiveElements(students, groups, ranks);
                    ExecuteCore(elements, electiveResult);
                }
            }
            return electiveResult;
        }
        private void ExecuteCore(List elements, ElectiveResult context)
        {
            // 核心方法优先级排序, 已经按期望排好了录取顺序
            elements.Sort(this);  // this.IComparer.Compare
            // 接下来考虑每个组合容量的问题
            foreach(var element in elements)
            {
                context.AppendMatched(element);
            }
        }
        protected virtual List BuildElectiveElements(List students, List groups, List ranks)
        {
            // 根据组合与志愿 生成不同的选科元素
            // 可以按计算需要,相互挂一些引用,方便计算过程中的删除操作
            // TODO: 如果引入意向专业,也可以改写这个生成的逻辑
            throw new NotImplementedException();
        }
        /// 
        /// 优先级比较
        /// 
        /// 
        /// 
        /// 
        public abstract int Compare(ElectiveElement x, ElectiveElement y);
    }
    public class PreferenceAheadElectiveEngine : ElectiveEngine
    {
        public PreferenceAheadElectiveEngine(IElectiveStrategy electiveStrategy)
            :base(electiveStrategy)
        {
        }
        public override int Compare(ElectiveElement x, ElectiveElement y)
        {
            // TODO: 容错处理
            if (x.PreferenceRank == y.PreferenceRank) return y.GroupRank - x.GroupRank;
            return y.PreferenceRank - x.PreferenceRank;
        }
    }
    public class ScoreAheadElectiveEngine : ElectiveEngine
    {
        public ScoreAheadElectiveEngine(IElectiveStrategy electiveStrategy)
            : base(electiveStrategy)
        {
        }
        public override int Compare(ElectiveElement x, ElectiveElement y)
        {
            // TODO: 容错处理
            if (x.GroupRank == y.GroupRank) return y.PreferenceRank - x.PreferenceRank;
            return y.GroupRank - x.GroupRank;
        }
    }
}