/*
 * Copyright (c) 2014 European Bioinformatics Institute (EMBL-EBI)
 *                    John May <jwmay@users.sf.net>
 *   
 * Contact: cdk-devel@lists.sourceforge.net
 *   
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version. All we ask is that proper credit is given
 * for our work, which includes - but is not limited to - adding the above 
 * copyright notice to the beginning of your source code files, and to any
 * copyright notice that you may distribute with programs based on this work.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 U
 */

package org.openscience.cdk.nfp;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.List;

/**
 * @author John May
 */
public final class FingerprintSort {

    static List<BinaryFingerprint> sort(List<BinaryFingerprint> src, int length) {        
        if (src.size() < 2)
            return src;
        int[] count = new int[length + 1];
        BinaryFingerprint[] dest = new BinaryFingerprint[src.size()];
        for (BinaryFingerprint fp : src)
            count[fp.cardinality() + 1]++;
        for (int i = 1; i < count.length; i++)
            count[i] += count[i - 1];
        for (BinaryFingerprint fp : src)
            dest[count[fp.cardinality()]++] = fp;
        return Arrays.asList(dest);
    }

    static List<BinaryFingerprint> index(List<BinaryFingerprint> src, int length, File f) throws IOException {

        FileChannel channel = new RandomAccessFile(f, "rw").getChannel();

        int[] count        = new int[length + 1];
        int   step         = (length / 8);


        ByteBuffer  buffer  = channel.map(FileChannel.MapMode.READ_WRITE,
                                          0,
                                          4 + (4 * count.length) + (step * src.size()));
        
        
        BinaryFingerprint[] dest = new BinaryFingerprint[src.size()];
        for (BinaryFingerprint fp : src)
            count[fp.cardinality() + 1]++;
        for (int i = 1; i < count.length; i++)
            count[i] += count[i - 1];
        
        buffer.putInt(count.length);
        buffer.asIntBuffer().put(count);
        int offset = buffer.position() + (count.length * 4);
        
        for (BinaryFingerprint fp : src) {
            put(buffer, offset + (step * count[fp.cardinality()]++), fp);
        }
        return Arrays.asList(dest);
    }

    static void put(ByteBuffer buffer, int pos, BinaryFingerprint fp) {
        buffer.position(pos);
        fp.write(buffer);
    }
}

@@ -2047,39 +2047,21 @@
  static 
-List%3CBinaryFingerpr
 int
-%3E
+%5B%5D
  index(L
@@ -2129,16 +2129,33 @@
 ption %7B%0A
+        %0A        
 %0A       
@@ -2316,17 +2316,16 @@
  / 8);%0A%0A
-%0A
         
@@ -2546,78 +2546,8 @@
    %0A
-        BinaryFingerprint%5B%5D dest = new BinaryFingerprint%5Bsrc.size()%5D;%0A
     
@@ -2880,161 +2880,365 @@
     
-for (BinaryFingerprint fp : src) %7B%0A            put(buffer, offset + (step * count%5Bfp.cardinality()%5D++), fp);%0A        %7D%0A        return Arrays.asList(dest)
+// order stores where each fingerprint appears%0A        int%5B%5D ordering = new int%5Bsrc.size()%5D;%0A        int n = 0;%0A        %0A        for (BinaryFingerprint fp : src) %7B%0A            int idx = count%5Bfp.cardinality()%5D++;%0A            put(buffer,%0A                offset + (step * idx), fp);%0A            ordering%5Bidx%5D = n++; %0A        %7D%0A        %0A        return ordering
 ;%0A  

return the location of the index in the fp.