using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace U.ListOperations.ListSort
{
    class SortList
    {
        /*
        private List<SortValue> sortValues;
        private SortValue.ValueType valueType;

        // CONSTRUCTORS
        // int
        public SortList(List<int> valueList)
        {
            this.sortValues = new List<SortValue>();
            for (int i = 0; i < valueList.Count; i++) { this.sortValues.Add(new SortValue(i, valueList[i])); }
            this.valueType = SortValue.ValueType.Int;
        }
        public SortList(List<int> idList, List<int> valueList)
        {
            this.sortValues = new List<SortValue>();
            for (int i = 0; i < valueList.Count; i++) { this.sortValues.Add(new SortValue(idList[i], valueList[i])); }
            this.valueType = SortValue.ValueType.Int;
        }
        // double
        public SortList(List<double> valueList)
        {
            this.sortValues = new List<SortValue>();
            for (int i = 0; i < valueList.Count; i++) { this.sortValues.Add(new SortValue(i, valueList[i])); }
            this.valueType = SortValue.ValueType.Double;
        }
        public SortList(List<int> idList, List<double> valueList)
        {
            this.sortValues = new List<SortValue>();
            for (int i = 0; i < valueList.Count; i++) { this.sortValues.Add(new SortValue(idList[i], valueList[i])); }
            this.valueType = SortValue.ValueType.Double;
        }
        // long
        public SortList(List<long> valueList)
        {
            this.sortValues = new List<SortValue>();
            for (int i = 0; i < valueList.Count; i++) { this.sortValues.Add(new SortValue(i, valueList[i])); }
            this.valueType = SortValue.ValueType.Long;
        }
        public SortList(List<int> idList, List<long> valueList)
        {
            this.sortValues = new List<SortValue>();
            for (int i = 0; i < valueList.Count; i++) { this.sortValues.Add(new SortValue(idList[i], valueList[i])); }
            this.valueType = SortValue.ValueType.Long;
        }

        // PRIVATE METHODS
        private void sort(bool ascending, bool absolute)
        {
            if (ascending)
            {
                switch (this.valueType)
                {
                    case SortValue.ValueType.Int:
                        if (absolute) { this.sortValues = this.sortValues.OrderBy(x => x.getAbsValueInt()).ToList(); return; }
                        this.sortValues = this.sortValues.OrderBy(x => x.getValueInt()).ToList(); return;
                    case SortValue.ValueType.Double:
                        if (absolute) { this.sortValues = this.sortValues.OrderBy(x => x.getAbsValueDouble()).ToList(); return; }
                        this.sortValues = this.sortValues.OrderBy(x => x.getValueDouble()).ToList(); return;
                    case SortValue.ValueType.Long:
                        if (absolute) { this.sortValues = this.sortValues.OrderBy(x => x.getAbsValueLong()).ToList(); return; }
                        this.sortValues = this.sortValues.OrderBy(x => x.getValueLong()).ToList(); return;
                }
                
            }
            switch (this.valueType)
            {
                case SortValue.ValueType.Int:
                    if (absolute) { this.sortValues = this.sortValues.OrderByDescending(x => x.getAbsValueInt()).ToList(); return; }
                    this.sortValues = this.sortValues.OrderByDescending(x => x.getValueInt()).ToList(); return;
                case SortValue.ValueType.Double:
                    if (absolute) { this.sortValues = this.sortValues.OrderByDescending(x => x.getAbsValueDouble()).ToList(); return; }
                    this.sortValues = this.sortValues.OrderByDescending(x => x.getValueDouble()).ToList(); return;
                case SortValue.ValueType.Long:
                    if (absolute) { this.sortValues = this.sortValues.OrderByDescending(x => x.getAbsValueLong()).ToList(); return; }
                    this.sortValues = this.sortValues.OrderByDescending(x => x.getValueLong()).ToList(); return;
            }
        }
        private void sortBack() { this.sortValues = this.sortValues.OrderBy(x => x.getId()).ToList(); }
        private List<int> getIds(int firstN)
        {
            if (firstN > this.sortValues.Count || firstN < 0) { return null; }
            if (firstN == 0) { return new List<int>(); }
            List<int> ids = new List<int>();
            for (int i = 0; i < firstN; i++) { ids.Add(this.sortValues[i].getId()); }
            return ids;
        }

        // PUBLIC METHODS
        public List<int> getTopIds(bool ascending, bool absolute, int topN) { sort(ascending, absolute); return getIds(topN); }
        public List<double> calcGetSpearmanRanks(bool ascending)
        {
            sort(ascending, false);
            double curr = sortValues[0].getValue();
            int start = 0;
            double sum = 0.0;
            for (int i = 1; i < sortValues.Count; i++)
            {
                if (sortValues[i].getValue() != curr)
                {
                    for (int j = start; j < i; j++) { sum += (j + 1); }
                    for (int j = start; j < i; j++) { sortValues[j].setSpearmanRank(sum / (i - start)); }
                    start = i; curr = sortValues[i].getValue(); sum = 0.0;
                }
            }
            for (int j = start; j < sortValues.Count; j++) { sum += (j + 1); }
            for (int j = start; j < sortValues.Count; j++) { sortValues[j].setSpearmanRank(sum / (sortValues.Count - start)); }
            sortBack();
            List<double> ranks = new List<double>();
            foreach (SortValue sortValue in this.sortValues) { ranks.Add(sortValue.getSpearmanRank()); }
            return ranks;
        }
        //*/
    }
}
