/*
 * 本代码受中华人民共和国著作权法保护，作者仅授权下载代码之人在学习和交流范围内
 * 自由使用与修改代码；欲将代码用于商业用途的，请与作者联系。
 * 使用本代码请保留此处信息。作者联系方式：ping3108@163.com, 欢迎进行技术交流
 */

using System;
//忽略没有注释警告
#pragma warning disable 1591
namespace MGdu.WinFormUI
{
    public class CutePointAndValuePresenter
    {
        #region 内部变量

        int eggCount = 10;
        int markCount = 10;
        bool fcp;

        double averageEggsInEachGab;
        int firstMarkN;
        int lastMarkN;

        #endregion

        #region 构造函数

        public CutePointAndValuePresenter()
        {
            UpdateEggAndMarkInfo();
        }

        #endregion

        #region 公开的属性，方法

        public int PointCount
        {
            get
            {
                return fcp ? eggCount : markCount;
            }
        }

        public int ValueCount
        {
            get
            {
                return fcp ? markCount : eggCount;
            }
        }

        public void SetPointAndValueCount(int pointCount, int valueCount)
        {
            if (pointCount < 1)
                pointCount = 1;
            if (valueCount < 1)
                valueCount = 1;
            if (pointCount >= valueCount)
            {
                fcp = true;
                eggCount = pointCount;
                markCount = valueCount;
            }
            else
            {
                fcp = false;
                eggCount = valueCount;
                markCount = pointCount;
            }
            UpdateEggAndMarkInfo();
        }

        public void GetPointIndexFromValueIndex(int vIndex, out int pIndexFrom, out int pIndexTo)
        {

            if (fcp)
            {
                if (vIndex < 0 || vIndex > markCount - 1)
                    throw new ArgumentOutOfRangeException("vIndex");

                GetEggsIndexFromMarkIndex(vIndex, out pIndexFrom, out pIndexTo);
            }
            else
            {
                if (vIndex < 0 || vIndex > eggCount - 1)
                    throw new ArgumentOutOfRangeException("vIndex");

                GetMarkIndexFromEggIndex(vIndex, out pIndexFrom);
                pIndexTo = pIndexFrom;
            }
        }

        public void GetValueIndexFromPointIndex(int pIndex, out int vIndexFrom, out int vIndexTo)
        {
            if (fcp)
            {
                if (pIndex < 0 || pIndex > eggCount - 1)
                    throw new ArgumentOutOfRangeException("pIndex");

                GetMarkIndexFromEggIndex(pIndex, out vIndexFrom);
                vIndexTo = vIndexFrom;
            }
            else
            {
                if (pIndex < 0 || pIndex > markCount - 1)
                    throw new ArgumentOutOfRangeException("pIndex");

                GetEggsIndexFromMarkIndex(pIndex, out vIndexFrom, out vIndexTo);
            }
        }

        public void GetExactPointIndexFromValueIndex(int vIndex, out int pIndex)
        {
            int pIndex2;
            GetPointIndexFromValueIndex(vIndex, out pIndex, out pIndex2);
            int maxIndex = fcp ? markCount - 1 : eggCount - 1;
            if (vIndex == maxIndex)
                pIndex = pIndex2;
            else if (vIndex != 0)
                pIndex = (pIndex + pIndex2) / 2;
        }

        public void GetExactValueIndexFromPointIndex(int pIndex, out int vIndex)
        {
            int vIndex2;
            GetValueIndexFromPointIndex(pIndex, out vIndex, out vIndex2);
            int maxIndex = fcp ? eggCount - 1 : markCount - 1;
            if (pIndex == maxIndex)
                vIndex = vIndex2;
            else if (pIndex != 0)
                vIndex = (vIndex + vIndex2) / 2;
        }

        #endregion

        #region 内部函数

        private int GetUpRoundedHalfValue(int a)
        {
            int t = a / 2;
            if (a % 2 != 0)
                t++;
            return t;
        }

        private int EggsCount(int markIndex)
        {
            return (markIndex + 1) +
                (int)Math.Round(averageEggsInEachGab * ((double)markIndex + 0.5), MidpointRounding.AwayFromZero);
        }

        private void UpdateEggAndMarkInfo()
        {
            if (markCount == 1)
            {
                firstMarkN = eggCount;
                return;
            }
            if (markCount == 2)
            {
                firstMarkN = GetUpRoundedHalfValue(eggCount);
                lastMarkN = eggCount / 2;
                return;
            }

            int remainEggs = eggCount - markCount;
            int gabs = markCount - 1;
            averageEggsInEachGab = (double)remainEggs / (double)gabs;
            firstMarkN = EggsCount(0);
            lastMarkN = eggCount - EggsCount(markCount - 2);
        }

        private void GetEggsIndexFromMarkIndex(int markIndex, out int eggIndexFrom, out int eggIndexTo)
        {
            if (markIndex == 0)
            {
                eggIndexFrom = 0;
                eggIndexTo = firstMarkN - 1;
                return;
            }
            if (markIndex == markCount - 1)
            {
                eggIndexTo = eggCount - 1;
                eggIndexFrom = eggIndexTo - lastMarkN + 1;
                return;
            }
            eggIndexFrom = EggsCount(markIndex - 1);
            eggIndexTo = EggsCount(markIndex) - 1;
        }

        private void GetMarkIndexFromEggIndex(int eggIndex, out int markIndex)
        {
            if (eggIndex < firstMarkN)
            {
                markIndex = 0;
                return;
            }
            if (eggIndex >= (eggCount - lastMarkN))
            {
                markIndex = markCount - 1;
                return;
            }

            //double rst = ((double)eggIndex + averageEggsInEachGab * 0.5) / (1 + averageEggsInEachGab);
            //markIndex = (int)rst;

            markIndex = (int)(((double)eggIndex + averageEggsInEachGab * 0.5) / (1 + averageEggsInEachGab));
            if (!IsRightEgg(markIndex, eggIndex))
            {
                if (markIndex == 1)
                    markIndex++;
                else if (markIndex == markCount - 2)
                    markIndex--;
                else
                {
                    if (IsRightEgg(markIndex - 1, eggIndex))
                        markIndex--;
                    else if (IsRightEgg(markIndex + 1, eggIndex))
                        markIndex++;
                    else
                    {
                        string msg = "Inner error in CutePointAndValuePresenter.GetMarkIndexFromEggIndex(), " +
                            "\r\n" + "can't find the correct markindex, please contact the author and " +
                            "report this error with the following data: " + "\r\n" +
                            "eggCount: " + eggCount.ToString() + "\r\n" +
                            "markCount: " + markCount.ToString() + "\r\n" +
                            "eggIndex: " + eggIndex.ToString();

                        throw new Exception(msg);
                    }

                }
            }
        }

        private bool IsRightEgg(int markIndex, int eggIndex)
        {
            int eggIndex1 = EggsCount(markIndex - 1);
            int eggIndex2 = EggsCount(markIndex) - 1;
            return (eggIndex1 <= eggIndex) && (eggIndex <= eggIndex2);
        }

        #endregion
    }
}
