/// <summary>
        /// Adds a submission to the given assignment for the given student
        /// The submission should use the current time as its DateTime
        /// You can get the current time with DateTime.Now
        /// The score of the submission should start as 0 until a Professor grades it
        /// If a Student submits to an assignment again, it should replace the submission contents
        /// and the submission time (the score should remain the same).
        /// </summary>
        /// <param name="subject">The course subject abbreviation</param>
        /// <param name="num">The course number</param>
        /// <param name="season">The season part of the semester for the class the assignment belongs to</param>
        /// <param name="year">The year part of the semester for the class the assignment belongs to</param>
        /// <param name="category">The name of the assignment category in the class</param>
        /// <param name="asgname">The new assignment name</param>
        /// <param name="uid">The student submitting the assignment</param>
        /// <param name="contents">The text contents of the student's submission</param>
        /// <returns>A JSON object containing {success = true/false}</returns>
        public IActionResult SubmitAssignmentText(string subject, int num, string season, int year,
                                                  string category, string asgname, string uid, string contents)
        {
            //sub, num --> catalogID
            // catalogID, year, season --> ClassID
            // classID, category --> acID
            // acID, asgname -- > aID
            // aID, uID, Constents --> add to submission
            using (Team9LMSContext db = new Team9LMSContext())
            {
                var aIDQuery = from acID in (from ci in (from cid in (from c in db.Courses
                                                                      where c.Subject == subject && c.Num == num
                                                                      select new { CatalogId = c.CatalogId })
                                                         join cl in db.Classes
                                                         on cid.CatalogId equals cl.CatalogId
                                                         where cl.Semester == year.ToString() + season
                                                         select new { classID = cl.ClassId })
                                             join ac in db.AssignmentCategories
                                             on ci.classID equals ac.ClassId
                                             where ac.Name == category
                                             select new { acID = ac.AcId })
                               join asg in db.Assignments
                               on acID.acID equals asg.AcId
                               where asg.Name == asgname
                               select new { asg.AId, asg.Points };
                uint aID = aIDQuery.First().AId;

                var subQuery = from s in db.Submission
                               where s.AId == aID && s.UId == uid
                               select s;

                if (subQuery.Count() > 0)
                {
                    subQuery.First().Time     = DateTime.Now;
                    subQuery.First().Contents = contents;
                    try
                    {
                        db.Update(subQuery.First());
                        db.SaveChanges();
                    }
                    catch (Exception e)
                    {
                        System.Diagnostics.Debug.WriteLine(e);
                    }
                }
                else
                {
                    Submission newSub = new Submission();
                    newSub.AId      = aID;
                    newSub.UId      = uid;
                    newSub.Time     = DateTime.Now;
                    newSub.Contents = contents;
                    //newSub.Score = 0;
                    db.Submission.Add(newSub);
                    db.SaveChanges();
                }
            }
            return(Json(new { success = true }));
        }
        /// <summary>
        /// Set the score of an assignment submission
        /// </summary>
        /// <param name="subject">The course subject abbreviation</param>
        /// <param name="num">The course number</param>
        /// <param name="season">The season part of the semester for the class the assignment belongs to</param>
        /// <param name="year">The year part of the semester for the class the assignment belongs to</param>
        /// <param name="category">The name of the assignment category in the class</param>
        /// <param name="asgname">The name of the assignment</param>
        /// <param name="uid">The uid of the student who's submission is being graded</param>
        /// <param name="score">The new score for the submission</param>
        /// <returns>A JSON object containing success = true/false</returns>
        public IActionResult GradeSubmission(string subject, int num, string season, int year, string category, string asgname, string uid, int score)
        //works
        {
            uint classID = 0;

            using (Team9LMSContext db = new Team9LMSContext())
            {
                var subQuery = from aid in (from acID in (from ci in (from cid in (from c in db.Courses
                                                                                   where c.Subject == subject && c.Num == num
                                                                                   select new { CatalogId = c.CatalogId })
                                                                      join cl in db.Classes
                                                                      on cid.CatalogId equals cl.CatalogId
                                                                      where cl.Semester == year.ToString() + season
                                                                      select new { classID = cl.ClassId })
                                                          join ac in db.AssignmentCategories
                                                          on ci.classID equals ac.ClassId
                                                          where ac.Name == category
                                                          select new { acID = ac.AcId })
                                            join asg in db.Assignments
                                            on acID.acID equals asg.AcId
                                            where asg.Name == asgname
                                            select new { asg.AId, asg.Points })
                               join s in db.Submission
                               on aid.AId equals s.AId
                               where s.UId == uid
                               select new { s, aid.Points };

                uint points = (uint)subQuery.First().Points;
                if (score < 0 || score > points)
                {
                    return(Json(new { success = false }));
                }

                subQuery.First().s.Score = (uint)score;
                db.Update(subQuery.First().s);
                db.SaveChanges();

                //update student's letter grade.
                var classIDQuery = from cid in (from c in db.Courses
                                                where c.Subject == subject && c.Num == num
                                                select new { CatalogId = c.CatalogId })
                                   join cl in db.Classes
                                   on cid.CatalogId equals cl.CatalogId
                                   where cl.Semester == year.ToString() + season
                                   select new { classID = cl.ClassId };
                classID = (uint)Convert.ToInt32(classIDQuery.First().classID);
                GPA.GradeUpdate(uid, classID);
            }

            return(Json(new { success = true }));
        }
        public static void GradeUpdate(string uid, uint classID)
        {
            Dictionary <uint, uint> acIDAndWeight      = new Dictionary <uint, uint>();
            Dictionary <uint, uint> acIDAndTotalPoints = new Dictionary <uint, uint>();
            Dictionary <uint, uint> acIDAndTotalScores = new Dictionary <uint, uint>();
            Dictionary <uint, uint> acIDAndTotalAsgs   = new Dictionary <uint, uint>();
            List <uint>             acIDs = new List <uint>();
            uint totalWeight = 0;

            using (Team9LMSContext db = new Team9LMSContext())
            {
                //Get all categories of this class
                var awQuery = from ac in db.AssignmentCategories
                              where ac.ClassId == classID
                              select new { ac.AcId, ac.Weight };
                foreach (var aw in awQuery)
                {
                    acIDAndWeight.Add(aw.AcId, (uint)aw.Weight);
                    acIDAndTotalPoints.Add(aw.AcId, 0);
                    acIDAndTotalScores.Add(aw.AcId, 0);
                    acIDs.Add(aw.AcId);
                }

                //Get all score of each assignment in each assignment category
                var asgsQuery = from asg1 in (from acID in (from ac in db.AssignmentCategories
                                                            where ac.ClassId == classID
                                                            select new { ac.AcId })
                                              join asg in db.Assignments
                                              on acID.AcId equals asg.AcId
                                              select new { asg.AId, asg.Points, asg.AcId })
                                join s in db.Submission
                                on asg1.AId equals s.AId
                                where s.UId == uid
                                select new { s, points = asg1.Points, acID = asg1.AcId };

                foreach (var a1 in asgsQuery)
                {
                    uint acID  = (uint)a1.acID;
                    uint score = (uint?)a1.s.Score ?? 0;
                    acIDAndTotalScores[acID] += score;
                }

                //Get all point of each assignment
                var pointsQuery = from acID in (from ac in db.AssignmentCategories
                                                where ac.ClassId == classID
                                                select new { ac.AcId })
                                  join asg in db.Assignments
                                  on acID.AcId equals asg.AcId
                                  select new { asg.AId, points = asg.Points, acID = asg.AcId };

                foreach (var pq in pointsQuery)
                {
                    uint acID   = (uint)pq.acID;
                    uint points = (uint)pq.points;
                    acIDAndTotalPoints[acID] += points;
                }

                //Get number of assignments for each assignment category
                var asgNumQuery = from ac in db.AssignmentCategories
                                  where ac.ClassId == classID
                                  select new { acID = ac.AcId, numAsg = numAssignments(ac.AcId) };

                foreach (var aNQ in asgNumQuery)
                {
                    acIDAndTotalAsgs.Add(aNQ.acID, aNQ.numAsg);
                }

                //calculation of total weight and scalefactor
                for (int i = 0; i < acIDs.Count(); i++)
                {
                    var tempAcID = acIDs[i];
                    if (acIDAndTotalAsgs[tempAcID] != 0)
                    {
                        totalWeight += acIDAndWeight[tempAcID];
                    }
                }

                double scaleFactor = 100.00 / totalWeight;

                //Calculation for final score for this class
                double finalScore = 0.0;
                for (int i = 0; i < acIDs.Count(); i++)
                {
                    var tempAcID = acIDs[i];
                    if (acIDAndTotalPoints[tempAcID] != 0)  // denominator should not be zero  --- mean no assigments in this category or this assignment will not be counted.
                    {
                        double tempScore = (double)acIDAndTotalScores[tempAcID] / acIDAndTotalPoints[tempAcID] * acIDAndWeight[tempAcID] * scaleFactor;
                        finalScore += tempScore;
                    }
                }

                //convert score to letter grade
                List <int> percentage = new List <int> {
                    93, 90, 87, 83, 80, 77, 73, 70, 67, 63, 60, 0
                };
                List <string> letters = new List <string> {
                    "A", "A-", "B+", "B", "B-", "C+", "C", "C-", "D+", "D", "D-", "E"
                };
                int    index       = indexOfLetters(percentage, finalScore);
                string letterGrade = letters[index];

                //update letter grade to DB
                var gradeQuery = from e in db.Enrolled
                                 where e.ClassId == classID && e.UId == uid
                                 select e;
                gradeQuery.First().Grade = letterGrade;
                db.Update(gradeQuery.First());
                db.SaveChanges();
            }
        }