// k := window size
void MotionGraph::genCandidates(std::ofstream &os, int motionIdxA, int motionIdxB, int k)
{
    Skeleton *skeleton = library->getSkeleton();
    Motion *motionA = library->getMotion(motionIdxA);
    Motion *motionB = library->getMotion(motionIdxB);
    if (skeleton == NULL || motionA == NULL || motionB == NULL)
    {
        printf("Error: in genCandidates().\n");
        exit(-1);
    }

    int numFramesA = motionA->GetNumFrames();
    int numFramesB = motionB->GetNumFrames();

    printf("motionIdxA = %d, motionIdxB = %d\n", motionIdxA, motionIdxB);
    printf("numFramesA = %d, numFramesB = %d\n", numFramesA, numFramesB);
    os << "#motionIndex" << std::endl << motionIdxA << ' ' << motionIdxB << std::endl;
    os << "#motionName" << std::endl << library->getName(motionIdxA) << ' ' << library->getName(motionIdxB) << std::endl;
    os << "#numFrames" << std::endl << numFramesA << ' ' << numFramesB << std::endl;

    PointCloud **pcListA = new PointCloud *[numFramesA];
    PointCloud **pcListB = new PointCloud *[numFramesB];

    for (int i = 0; i < numFramesA; i++)
    {
        skeleton->setPosture(*(motionA->GetPosture(i)));
        pcListA[i] = new PointCloud(skeleton);
    }
    for (int i = 0; i < numFramesB; i++)
    {
        skeleton->setPosture(*(motionB->GetPosture(i)));
        pcListB[i] = new PointCloud(skeleton);
    }

    printf("Form distance matrix...\n");

    double *dist = new double[numFramesA * numFramesB]();   // distance of any pair of windows

    int iBegin = 0;
    int iEnd = numFramesA - k;
    int jBegin = k - 1;
    int jEnd = numFramesB - 1;

    printf("Calculating distances...\n");

    for (int i = iBegin; i <= iEnd; i++)             // window of motionA: [i..i+k-1]
    {
        if (i % 10 == 0)
            printf("Calculating (%d, %d)...\n", i, 0);

        for (int j = jBegin; j <= jEnd; j++)         // window of motionB: [j-k+1..j]
        {
            // form point cloud over k frames
            PointCloud pcA(&pcListA[i], k);
            PointCloud pcB(&pcListB[j - k + 1], k);

            int index = i * numFramesB + j;
            dist[index] = distance(&pcA, &pcB);     // distance
        }
    }

    printf("Calculating distances... done.\n");

    //std::vector< std::pair<int, int> > minList;     // local minimum list
    // local minimum list
    std::vector<WindowPair> minList;
    
    // search local minimums
    //bool *mark = new bool[numFramesA * numFramesB]();   // traversed
    for (int i = iBegin; i <= iEnd; i++)
    {
        for (int j = jBegin; j <= jEnd; j++)
        {
            int index = i * numFramesB + j;
            bool isMin = true;
            for (int ii = i - 2; ii <= i + 2; ii++)
            {
                for (int jj = j - 2; jj <= j + 2; jj++)
                {
                    if (ii >= iBegin && ii <= iEnd &&
                        jj >= jBegin && jj <= jEnd &&
                        dist[index] > dist[ii * numFramesB + jj])
                        isMin = false;
                }
            }
            if (isMin)
            {
                WindowPair pair;
                pair.i = i;
                pair.j = j;
                pair.dist = dist[index];
                minList.push_back(pair);
            }
        }
    }

    std::sort(minList.begin(), minList.end());

    printf("Local minimum list:\n");

    int minListSize = 0;
    for (size_t i = 0; i < minList.size(); i++)
    {
        if (!(motionIdxA == motionIdxB && minList[i].i + 39 == minList[i].j))
            minListSize++;
    }

    os << "#minListSize" << std::endl << minListSize << std::endl;
    os << "#i j distance theta x0 z0" << std::endl;

    for (size_t i = 0; i < minList.size(); i++)
    {
        double theta, x0, z0;
        PointCloud pcA(&pcListA[minList[i].i], k);
        PointCloud pcB(&pcListB[minList[i].j - k + 1], k);
        distance(&pcA, &pcB, &theta, &x0, &z0);
        //printf("%4d %4d %8.4lf   %lf %lf %lf\n", minList[i].i, minList[i].j, minList[i].dist, theta, x0, z0);
        if (!(motionIdxA == motionIdxB && minList[i].i + 39 == minList[i].j))
            os << minList[i].i << ' ' << minList[i].j << ' ' << minList[i].dist << ' ' << theta << ' ' << x0 << ' ' << z0 << std::endl;
    }
    
    delete [] dist;

    for (int i = 0; i < numFramesA; i++)
        delete pcListA[i];
    for (int i = 0; i < numFramesB; i++)
        delete pcListB[i];
    delete [] pcListA;
    delete [] pcListB;
    
    printf("genCandidates(): done.\n");
}