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

namespace MathModEduPr02
{
    internal class JohnsonsAlg
    {
        List<(int, int)> data;
        List<(int, int)> newScheme;
        int oldResult;
        public List<(int, int)> NewScheme { get => newScheme; }
        public int OldResult { get => oldResult; }
        public int NewResult { get => EvaluateDowntime(newScheme); }
        public int ResultDiff { get => OldResult - NewResult; }

        public JohnsonsAlg(List<(int, int)> data)
        {
            this.data = new List<(int, int)>(data);
            newScheme = Enumerable.Repeat((0,0), data.Count()).ToList();
            oldResult = EvaluateDowntime(data);
        }
        public void Solve()
        {
            int curFirstIndex = 0, curLastIndex = data.Count() - 1;
            int minEl;
            List<(int, int)> minEls;
            while (newScheme.FindAll(x=> x.Item1==0).Count()>0)
            {
                minEl = data.Min(x => x.Item1 < x.Item2 ? x.Item1 : x.Item2);
                minEls = data.FindAll(x => x.Item1 == minEl || x.Item2 == minEl);
                AddToNewScheme(minEls, ref curFirstIndex, ref curLastIndex);
            }
        }
        void AddToNewScheme(List<(int, int)> minEls, ref int curFirstIndex, 
            ref int curLastIndex)
        {
            if (minEls.Count > 1)
            {
                if (minEls[0].Item1 == minEls[1].Item1)
                    minEls.OrderBy(x => x.Item2);
                else
                    minEls.OrderBy(x => x.Item1);
                foreach (var row in minEls)
                    AddOneRow(row, ref curFirstIndex, ref curLastIndex);
            }
            else
                AddOneRow(minEls[0], ref curFirstIndex, ref curLastIndex);
        }
        void AddOneRow((int, int) row, ref int curFirstIndex, ref int curLastIndex)
        {
            if (row.Item1 < row.Item2)
            {
                newScheme[curFirstIndex] = row;
                ++curFirstIndex;
            }
            else
            {
                newScheme[curLastIndex] = row;
                --curLastIndex;
            }
            data.RemoveAt(data.FindIndex(x => x == row));
        }
        int EvaluateDowntime(List<(int,int)> curScheme)
        {
            List<int> downtimes = new List<int> ();
            int curDowntime = curScheme[0].Item1;
            downtimes.Add (curDowntime);
            for(int i=1; i<curScheme.Count; ++i) 
            {
                curDowntime += curScheme[i].Item1 - curScheme[i-1].Item2;
                downtimes.Add (curDowntime);
            }
            return downtimes.Max();
        }
    }
}
