// --------------------------------------------------------------
// class PoolCreator - port of Mario's DeconvoluteIt C/C++ code.
// Algorithm is described in: 
// Journal of Immunological Methods 274 (2003) 221-228
// --------------------------------------------------------------

public class PoolCreator {

    // ----------------
    // Fields
    // ----------------

    int numberOfPools;


    // ------------------------------
    // Constructor
    // ------------------------------

    public PoolCreator(int totalPeptides, int coverage, int poolSize) {

        // Check inputs

        if(totalPeptides % poolSize != 0){
            // Pop-up Window -> Msg: poolSize must be a factor of totalPeptides
            // or, write to TextOutput window
            // exit Constructor
        }

        if(poolSize <= 0){
            // Pop-up Window -> Msg: poolSize must be greater than zero.
            // or, write to TextOutput window
            // exit Constructor
        }

        numberOfPools = (totalPeptides*coverage)/poolSize;

        if(totalPeptides < numberOfPools){
            // Pop-up Window -> Msg:
            // or, write to TextOutput window
            // exit Constructor
        }

        createPools(totalPeptides, coverage, poolSize);

    } // end Constructor



    // ----------------------------------------------------- 
    // Methods
    // -----------------------------------------------------


    // ------------------------------------
    // createPools - 
    // ------------------------------------
    private void createPools(int totalPeptides, int coverage, int poolSize){

        DeconvoluteIt.window.setTextArea("Creating " + Integer.toString(numberOfPools) + " pools...");

        // dim1: numberOfPools dim2: totalPeptides
        boolean[][] poolMembership;
        poolMembership = new boolean[numberOfPools][totalPeptides];

        // length = totalPeptides
        boolean[] pepAssigned;
        pepAssigned = new boolean[totalPeptides];

        // Keeps counts of number of pools in together
        // dim1: totalPeptides, dim2: totalPeptides
        int[][] pepSharing;
        pepSharing = new int[totalPeptides][totalPeptides];

        // length = poolSize
        int[] poolPeptides;
        poolPeptides = new int[poolSize];

        int lastAssignedPeptide = -1;
        int nextPep = 0;
        int lowestSharePeptide;
        int lowestShareMax;
        int lowestShareCount;
        boolean doneSearching;
        int curShareCount;
        int curShareMax;

 
        //Initialize the arrays which keep track of the peptides and pools
        for(int i=0; i < totalPeptides; i++){
            pepAssigned[i] = false;
            for(int j=0; j < numberOfPools; j++){
                poolMembership[j][i] = false;
            }
            for(int j=0; j < totalPeptides; j++){
                pepSharing[j][i] = 0;
            }
        }
        for(int i=0; i < poolSize; i++){
            poolPeptides[i] = 0;
        }

        // Loop pool-by-pool, to assign peptides to each pool
        for(int pool=0; pool < numberOfPools; pool++){
        
            // Find the first peptide to assign to this pool
            for(nextPep=incrementPep(lastAssignedPeptide,totalPeptides); nextPep!=lastAssignedPeptide;
                   nextPep=incrementPep(nextPep,totalPeptides)){
               if(!pepAssigned[nextPep]) break;
            }

            // Start a new Coverage set of pools
            if(nextPep==lastAssignedPeptide){
                for(nextPep=0; nextPep < totalPeptides; nextPep++){
                    pepAssigned[nextPep] = false;
                }
                nextPep=0;
            }

            lastAssignedPeptide = nextPep;
            pepAssigned[nextPep] = true;
            poolMembership[pool][nextPep] = true;
            poolPeptides[0] = nextPep;


            // Assign the rest of the pool based on concept of least-Sharing
            for(int xPep = 1; xPep < poolSize; xPep++){
                lowestSharePeptide = -1;
                lowestShareCount = (totalPeptides*totalPeptides+1);
                lowestShareMax = lowestShareCount;
                doneSearching = false;

                for(int kPep = incrementPep(nextPep,totalPeptides); kPep != nextPep && !doneSearching;
                    kPep=incrementPep(kPep,totalPeptides)){
                    if(!pepAssigned[kPep]){
                        curShareCount = 0;
                        curShareMax = 0;
                        for(int jPep=0; jPep < xPep; jPep++){
                            curShareCount += pepSharing[poolPeptides[jPep]][kPep];
                            curShareMax = Math.max(curShareMax, pepSharing[poolPeptides[jPep]][kPep]);
                        }
                        if((curShareMax < lowestShareMax) ||
                            (curShareMax == lowestShareMax && curShareCount < lowestShareCount)){
                            lowestSharePeptide = kPep;
                            lowestShareCount = curShareCount;
                            lowestShareMax = curShareMax;
                            doneSearching = (curShareCount == 0);
                        }
                    }
                }

                pepAssigned[lowestSharePeptide] = true;
                poolMembership[pool][lowestSharePeptide] = true;
                poolPeptides[xPep] = lowestSharePeptide;
                for(int kPep=0; kPep < xPep; kPep++){
                    pepSharing[poolPeptides[kPep]][lowestSharePeptide]++;
                    pepSharing[lowestSharePeptide][poolPeptides[kPep]]++;
                }
                lastAssignedPeptide = Math.max(lowestSharePeptide, lastAssignedPeptide);

            } // end least-Sharing loop

        } // end pool loop

        // Print pool membership
        for(int i=0; i < numberOfPools; i++){
            System.out.print("Pool " + (i+1) + ":");
            for(int j=0; j < totalPeptides; j++){
                if(poolMembership[i][j]){
                    System.out.print(" " + (j+1));
                }
            }
            System.out.println();
        }

    } 


    // ------------------------------------
    // incrementPep -
    // ------------------------------------

    int incrementPep(int lastAssignedPeptide, int totalPeptides){
        return ((lastAssignedPeptide+1) % totalPeptides);
    }



} // end Class PoolCreator

