////////////// Main Functions //////////////

        /*Run new offline (minDist) */
        public static List <double> RunOfflineMinDist(List <double> inputData, int NLength, int maxEntry, int minEntry, int R, int D, ref int this_id_item, ref List <int> this_id_itemList, ref List <Rectangle> this_rectList, ref RTree <int> this_RTree, bool is_first_time)
        {
            int         id_item = int.MinValue;
            RTree <int> rtree   = new RTree <int>(maxEntry, minEntry);

            List <int> candidateList   = new List <int>();
            List <int> beginIndexInner = new List <int>();
            List <int> indexOfLeafMBRS = new List <int>();

            double best_so_far_dist = 0;
            int    best_so_far_loc  = -1;

            double nearest_neighbor_dist = 0;
            double dist = 0;
            bool   break_to_outer_loop = false;

            bool[] is_skipped_at_p = new bool[inputData.Count];
            for (int i = 0; i < inputData.Count; i++)
            {
                is_skipped_at_p[i] = false;
            }

            if (minEntry > maxEntry / 2)
            {
                MessageBox.Show("Requirement: MinNodePerEntry <= MaxNodePerEntry/2");
                return(new List <double> {
                    best_so_far_dist, best_so_far_loc
                });
            }

            List <Rectangle> recList     = new List <Rectangle>();
            List <int>       id_itemList = new List <int>();

            for (int i = 0; i <= inputData.Count - NLength; i++)
            {
                List <double> subseq = inputData.GetRange(i, NLength);
                id_item++;
                Rectangle new_rec = new Rectangle(MathFuncs.PAA_Lower(subseq, D, R).ToArray(), MathFuncs.PAA_Upper(subseq, D, R).ToArray(), i);
                rtree.Add(new_rec, id_item);
                recList.Add(new_rec);
                id_itemList.Add(id_item);
            }


            Dictionary <int, Node <int> > nodeMap   = rtree.getNodeMap();
            List <Node <int> >            leafNodes = nodeMap.Values.Where(node => node.level == 1).OrderBy(node => node.entryCount).ToList();

            List <Rectangle> leafMBRs = leafNodes.Select(node => node.mbr).ToList(); // List rectangle of leaf nodes in order of list leafNodes

            for (int i = 0; i < leafNodes.Count; i++)
            {
                List <Rectangle> leafEntries = leafNodes[i].entries.Where(mbr => mbr != null).Select(mbr => mbr).ToList();
                if (leafEntries.Count > 0)
                {
                    int beginIndex = candidateList.Count;
                    candidateList.AddRange(leafEntries.Select(mbr => mbr.getIndexSubSeq()));
                    beginIndexInner.AddRange(Enumerable.Repeat(beginIndex, leafEntries.Count));
                    indexOfLeafMBRS.AddRange(Enumerable.Repeat(i, leafEntries.Count));
                }
            }

            for (int i = 0; i < candidateList.Count; i++)//outer loop
            {
                int p = candidateList[i];

                // rectangle of subseq in p postion
                if (is_skipped_at_p[p])
                {
                    //p was visited at inner loop before
                    continue;
                }
                else
                {
                    List <double> subseq_p = inputData.GetRange(p, NLength);
                    //Rectangle p_rectangle = recList[p];
                    List <double> P_PAA = MathFuncs.PAA(subseq_p, D);

                    nearest_neighbor_dist = Constants.INFINITE;

                    List <bool> eliminatedMBR = new List <bool>();
                    for (int k = 0; k < leafMBRs.Count; k++)
                    {
                        eliminatedMBR.Add(false);
                    }

                    int indexMBRLeaf   = -1;
                    int num_leaf_skips = 0;

                    for (int j = 0; j < candidateList.Count; j++)// inner loop
                    {
                        // int q = innerList[j];
                        int index_inner = (beginIndexInner[i] + j) % candidateList.Count;
                        int q           = candidateList[index_inner];

                        int index_MBRInnner = (beginIndexInner[i] + j) % candidateList.Count;
                        int MBRInnner       = indexOfLeafMBRS[index_MBRInnner];

                        if (indexMBRLeaf < MBRInnner)//the first entry of the next node ?
                        {
                            indexMBRLeaf++;


                            /* Test:
                             * if (indexMBRInnner[j] == MBRInnner)
                             *  Console.WriteLine("OK");*/

                            //calc minDist:
                            //double minDist = MathFuncss.MINDIST(p_rectangle, leafMBRs[MBRInnner], (NLength / (double)(D)));
                            double minDist = MathFuncs.MINDIST(P_PAA, leafMBRs[MBRInnner], (NLength / (double)(D)));

                            //if (minDist_keo > minDist)
                            //{
                            //   Console.WriteLine("STOPPP");
                            //  return;
                            //}

                            if (minDist >= nearest_neighbor_dist)
                            {
                                num_leaf_skips++;
                                eliminatedMBR[MBRInnner] = true;

                                continue;// pruned => skip to the next one
                            }
                            else
                            {
                                if (Math.Abs(p - q) < NLength)
                                {
                                    continue;// self-match => skip to the next one
                                }

                                //calculate the Distance between p and q
                                dist = MathFuncs.EuDistance(subseq_p, inputData.GetRange(q, NLength));

                                if (dist < best_so_far_dist)
                                {
                                    //skip the element q at oute_loop, 'cuz if (p,q) is not a solution, neither is (q,p).
                                    is_skipped_at_p[q] = true;

                                    break_to_outer_loop = true; //break, to the next loop at outer_loop
                                    break;                      // break at inner_loop first
                                }

                                if (dist < nearest_neighbor_dist)
                                {
                                    nearest_neighbor_dist = dist;
                                }
                            }
                        }
                        else // still the same node
                        {
                            if (eliminatedMBR[MBRInnner]) // can prune ?
                            {
                                continue;
                            }
                            else //do it normally
                            {
                                if (Math.Abs(p - q) < NLength)
                                {
                                    continue;// self-match => skip to the next one
                                }
                                else
                                {
                                    //calculate the Distance between p and q
                                    dist = MathFuncs.EuDistance(subseq_p, inputData.GetRange(q, NLength));

                                    if (dist < best_so_far_dist)
                                    {
                                        //skip the element q at oute_loop, 'cuz if (p,q) is not a solution, neither is (q,p).
                                        is_skipped_at_p[q] = true;

                                        break_to_outer_loop = true; //break, to the next loop at outer_loop
                                        break;                      // break at inner_loop first
                                    }

                                    if (dist < nearest_neighbor_dist)
                                    {
                                        nearest_neighbor_dist = dist;
                                    }
                                }
                            }
                        } //end ELSE
                    }     //end for inner loop

                    //Console.WriteLine("num_leaf_skips="+ num_leaf_skips);
                    if (break_to_outer_loop)
                    {
                        break_to_outer_loop = false; //reset
                        continue;                    //go to the next p in outer loop
                    }

                    if (nearest_neighbor_dist > best_so_far_dist)
                    {
                        best_so_far_dist = nearest_neighbor_dist;
                        best_so_far_loc  = p;
                    }
                }
            }//end outer loop
            if (is_first_time)
            {
                this_id_item     = id_item;
                this_id_itemList = id_itemList;
                this_RTree       = rtree;
                this_rectList    = recList;
            }
            return(new List <double> {
                best_so_far_dist, best_so_far_loc
            });
        }