package SeqSel;

import dtype.Item;

import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;

/**
 * Java class specifying an interface to alignment coloring object and its associated functionality. <br>
 * The underlying data object is called 'SelItem.java', and this object is used to store, write and load coloring selections. <br>
 * <br>
 * The SelItem object, consists of 3 fields: <br>
 * <br>
 * int seqa<br>
 * int seqb<br>
 * int posa<br>
 * int posb<br>
 * <p/>
 * int R of RGB color<br>
 * int G of RGB color<br>
 * int B of RGB color<br>
 * <br>
 * note: color, is java.awt.Color, and is specified by (int red, int blue, int green), where each of the integer values ranges from 0-255.<br>
 * Alternately, one can use the 16 predefined colors in java.awt.Color. <br>
 * <br>
 * The last  optional field, can be used to store user-specific data/info.<br>
 *
 *
 * @author marcin joachimiak
 * @vwrsion 1.1 - added # comment tolerance in input/output (stores alignment length and number of sequences)
 * @version 1.0, 6/19/01
 */

public class SCF {
//the maximum length of the multiple alignment
    public int alimaxlen;

//the total number of sequences in the alignment
    public int totalseqs;
    public int totalcols;

    public ArrayList sels;
    public long alichecksum;

    /**
     *
     */
    public SCF() {
        sels = new ArrayList();
    }

    /**
     *
     * @param a
     * @param b
     */
    public SCF(int a, int b) {
        sels = new ArrayList();
        alimaxlen = a;
        totalseqs = b;
    }

    /**
     *
     * @param scf
     */
    public SCF(SCF scf) {
        sels = new ArrayList();
        for (int i = 0; i < scf.sels.size(); i++) {
            sels.add(new SelItem((SelItem) scf.sels.get(i)));
        }
        alimaxlen = scf.alimaxlen;
        totalseqs = scf.totalseqs;
    }

    /**
     *
     */
    /**
     * Function to set the extents of the alignment and number of sequences.
     * @param a
     * @param b
     */
    public void setExtents(int a, int b) {
        
        //sels = new ArrayList();
        alimaxlen = a;
        totalseqs = b;
    }

    /**
     * function which checks the state of the global selection vector
     */
    public boolean isEmpty() {
        boolean ret = false;
        if (sels == null) {
            sels = new ArrayList();
            ret = true;
        }
        if (sels.size() == 0)
            ret = true;
        return ret;
    }

    /**
     * function which clears  the global selection vector, deleting all stored selections
     */
    public void clear() {
        sels = new ArrayList();
    }

    /**
     * Determines the checksum for this vector object containing String objects of the sequences.
     * In the reference string, amino acids are indexed as PRIME numbers to preserve uniqueness.
     */
    public boolean checksum(ArrayList ali) {
        String b = "  AC D E   F G   H I   K     L M     N   P Q   R     S     T V     W   Y ~     .";
        long checksum = 0;
        boolean go = true;
        int len = 0;
        for (int i = 0; i < ali.size(); i++) {
            String cur = (String) ali.get(i);
            int curlen = cur.length();
            if (len == 0)
                len = curlen;
            else if (len != curlen) {
                go = false;
                break;
            }
        }
        if (go)
            for (int j = 0; j < alimaxlen; j++) {
                long locsum = 0;
                for (int i = 0; i < ali.size(); i++) {
                    String cur = (String) ali.get(i);
                    char n = cur.charAt(j);
                    int k = b.indexOf(n);
                    locsum = +(long) ((double) k * (double) (i + 1));
                }
                checksum = +(long) ((double) locsum * (double) (j + 1));
            }
        alichecksum = checksum;
        ali = null;

        return go;
    }

    /**
     * Returns an array encoding which positions match the query color.
     */
    public int[] retIfColor(Color c, int max, SCF other) {
        int[] ret = new int[max];
        for (int i = 0; i < other.sels.size(); i++) {
            SelItem si = (SelItem) other.sels.get(i);
//System.out.println("si "+si.col.toString());
//System.out.println("c "+c.toString());

            if (si.col.equals(c)) {
                for (int k = si.posa; k < si.posb + 1; k++)
                    ret[k] = 100;
            }
        }
        return ret;
    }

    /**
     * Increments the position of the selection by posadd.
     */
    public void reNumberSel(SelItem pass, int posadd) {
        for (int u = 0; u < sels.size(); u++) {
            SelItem cur = (SelItem) sels.get(u);
            if (cur.posa == pass.posa && cur.posb == pass.seqb && cur.seqa == pass.seqa && cur.seqb == pass.seqb) {

                cur.posa += posadd;
                cur.posb += posadd;
                sels.set(u, cur);
            }

        }
    }

    /**
     * compares only int pos to SelItem.posa during the search
     */
    public int retIndexIfPosSelected(int pos) {
        int ret = -1;
        for (int u = 0; u < sels.size(); u++) {
            SelItem cur = (SelItem) sels.get(u);
            if (cur.posa == pos) {
                ret = u;
                break;
            }
        }
        return ret;
    }

    /**
     * compares only int pos to SelItem.posa (if sequence =0)
     * during the search
     */
    public int retIndexIfColSelected(int col) {
        int ret = -1;
        for (int u = 0; u < sels.size(); u++) {
            SelItem cur = (SelItem) sels.get(u);
            if (cur.posa == col && cur.seqa == 0) {
                ret = u;
                break;
            }
        }
        return ret;
    }

    /**
     * compares  int pos to SelItem.posa
     * during the search
     */
    public int retIndexIfSeqAndColSelected(int seq, int pos) {
        int ret = -1;
        for (int u = 0; u < sels.size(); u++) {
            SelItem cur = (SelItem) sels.get(u);
            if (cur.posa == pos && cur.seqa == seq) {
                ret = u;
                break;
            }
        }
        return ret;
    }

    /**
     * returns the index of the specified SelItem object, in the global selection vector
     */
    public int retIndexOfSelection(SelItem sltm) {
        int ret = -1;
        for (int u = 0; u < sels.size(); u++) {
            SelItem cur = (SelItem) sels.get(u);
            if (cur.equals(sltm)) {
                ret = u;
                break;
            }
        }
        return ret;
    }

    /**
     * Returns all currently stored selections as a vector of SelItem objects.
     *
     * @return
     */
    public ArrayList retSelections() {
        ArrayList ret = new ArrayList();
        if (!isEmpty()) {
            for (int j = 0; j < sels.size(); j++) {
                SelItem comp = (SelItem) sels.get(j);
                if (comp != null) {
                    ret.add(new SelItem(comp));
                } else {
                    //System.out.println("retSelections removing " + j);
                    sels.remove(j);
                    j--;
                }
            }
        }
        return ret;
    }

    /**
     * Finds rank of current color in the global color scale.
     *
     * @param x
     * @return
     */
    private final static int findInjevtraceColorScale(Color x) {
        int ret = -1;
        if (x.equals(Color.gray))
            ret = 0;
        else if (x.equals(Color.blue))
            ret = 1;
        else if (x.equals(Color.cyan))
            ret = 2;
        else if (x.equals(Color.yellow))
            ret = 3;
        else if (x.equals(Color.orange))
            ret = 4;
        else if (x.equals(Color.pink))
            ret = 5;
        else if (x.equals(Color.magenta))
            ret = 6;
        else if (x.equals(Color.red))
            ret = 7;
        return ret;
    }

    /**
     * @param x
     * @return
     */
    private final static int findInjevtraceScoreColorScale(Color x) {
        int ret = -1;
        if (x.equals(Color.red))
            ret = 0;
        if (x.equals(Color.gray))
            ret = 1;
        else if (x.equals(Color.blue))
            ret = 2;
        else if (x.equals(Color.cyan))
            ret = 3;
        else if (x.equals(Color.yellow))
            ret = 4;
        else if (x.equals(Color.orange))
            ret = 5;
        else if (x.equals(Color.pink))
            ret = 6;
        else if (x.equals(Color.magenta))
            ret = 7;

        return ret;
    }

    /**
     * Returns an array encoding the lowest ranking color based on the reference Color array.
     *
     * @return
     */
    public int[] lowestjevtraceRank() {

        removeSequenceSeqa(-1);

        //System.out.println("SCF lowestjevtraceRank w/o scoring " + sels.size());

        int[] maxpercol = new int[alimaxlen];

        for (int j = 0; j < alimaxlen; j++) {
            maxpercol[j] = 100;
        }

        for (int i = 0; i < sels.size(); i++) {
            SelItem compa = (SelItem) sels.get(i);
            int acol = findInjevtraceColorScale(compa.col);//ScoreColorScale(compa.col);

            if (maxpercol[compa.posa] > acol)
                maxpercol[compa.posa] = acol;

        }

        return maxpercol;
    }


    /**
     * Finds the maximum selected range of sequences for each group and removes all others.
     */
    public void trimLayersByLowerRank() {
        for (int i = 0; i < sels.size(); i++) {
            SelItem compa = (SelItem) sels.get(i);
            int acol = findInjevtraceColorScale(compa.col);
            for (int j = i + 1; j < sels.size(); j++) {
                SelItem compb = (SelItem) sels.get(j);
                int bcol = findInjevtraceColorScale(compb.col);
                //if(compa.posa < compb.posa && compa.posb < compb.posb)
                //{
                if (compa.posa <= compb.posa && compa.posb >= compb.posb && acol < bcol) {
                    sels.remove(j);
                    j--;
                    if (compa.seqa > compb.seqa)
                        compa.seqa = compb.seqa;
                    if (compa.seqb < compb.seqb)
                        compa.seqb = compb.seqb;

                    sels.set(i, compa);
                    compa = (SelItem) sels.get(i);
                }
                //}
            }
        }
    }


    /**
     * Adds all SelItem objects from SCF now with Color c.
     */
    public void addColorFrom(SCF now, Color c) {
        for (int j = 0; j < now.sels.size(); j++) {
            SelItem comp = (SelItem) now.sels.get(j);
            if (comp.col.equals(c)) {
                sels.add(comp);
            }
        }
    }

    /**
     * Function to remove all SelItem objects with Color c.
     */
    public void removeColor(Color c) {

        for (int j = 0; j < sels.size(); j++) {
            SelItem comp = (SelItem) sels.get(j);
            if (comp.col.equals(c)) {
                //System.out.println("removing "+comp.toString());
                sels.remove(j);
                j--;
            }
        }
    }

    /**
     * Function to add this specific SelItem objects from the global
     * selection vector stored in the SCF class.
     */
    public void removeSelection(SelItem d) {

        for (int j = 0; j < sels.size(); j++) {
            SelItem comp = (SelItem) sels.get(j);
            if (comp.equals(d)) {
                //System.out.println("removing "+comp.toString());
                sels.remove(j);
                break;
            }
        }
    }

    /**
     * function to add this specific SelItem objects from the global
     * selection vector stored in the SCF class
     */
    public void removeSelectionAt(int a) {

        if (a > -1 && a < sels.size()) {
            //System.out.println((SelItem)(SelItem)sels.get(a));
            sels.remove(a);
        }
    }

    /**
     * converts all selections
     * to column selections
     */
    public void converttoColumns() {
        for (int i = 0; i < sels.size(); i++) {
            SelItem sq = (SelItem) sels.get(i);
            int seqa = sq.seqa;
            int seqb = sq.seqb;
            if (seqa != 0) {
                SelItem add = new SelItem(0, sq.posa, sq.col);
                sels.add(add);
                sels.remove(i);
                i--;
            }
        }
    }

    /**
     * converts the scoring selections (@seq = -1)
     * to column selections
     */
    public void convertScoretoColumns() {

        for (int i = 0; i < sels.size(); i++) {
            SelItem sq = (SelItem) sels.get(i);
            int seqa = sq.seqa;
            int seqb = sq.seqb;
            if (seqa == -1) {
                SelItem add = new SelItem(0, sq.posa, sq.col);
                sels.add(add);
                sels.remove(i);
                i--;
            }
        }
    }

    /**
     * function to translate current set of selections
     * given indexing array
     */
    public void transSels(int[] inds) {

        for (int i = 0; i < sels.size(); i++) {

            SelItem sq = (SelItem) sels.get(i);

            sq.posa = inds[sq.posa];
            sq.posb = inds[sq.posb];
            if (sq.posa == -1 && sq.posb == -1)
                sels.remove(i);
            else {

                if (sq.posa == -1 && sq.posb != -1)
                    sq.posa = sq.posb;
                else if (sq.posa != -1 && sq.posb == -1)
                    sq.posa = sq.posb;

                sels.set(i, sq);
            }

        }
    }

    /**
     * returns the old single seq format
     */
    public ArrayList retOldSels() {
        ArrayList ret = new ArrayList();
        for (int i = 0; i < sels.size(); i++) {
            SelItem now = (SelItem) sels.get(i);
            Item add = new Item(now.seqa, now.posa, now.col);
            ret.add((Item) add);
        }
        return ret;
    }

    /**
     * Function to add aSelitem objects to the global
     * selection vector stored in the SCF class.
     */
    public void addSelection(SelItem d) {
        if (d != null) {
            sels.add((SelItem) d);
        }
    }

    /**
     * function to add a vector of SelItem objects to the global
     * selection vector stored in the SCF class
     */
    public void addSelections(ArrayList d) {
        //	System.out.println("adding selections !");
        if (sels == null)
            sels = new ArrayList();
//System.out.println("selection size "+d.size());
        for (int i = 0; i < d.size(); i++) {
            SelItem sit = new SelItem((SelItem) d.get(i));
            sels.add((SelItem) sit);
            //System.out.println(i+"\t"+sit.toString());
        }
        //System.out.println("AFTER  sels.adds() "+sels.size()+" new Selitems!");
        orderSels();
        //System.out.println("AFTER  orderSels() " + sels.size() + " new Selitems!");
        makeNonredundant();
        //System.out.println("AFTER  makeNonredundant() " + sels.size() + " new Selitems!");
        sortSelections();
        //System.out.println("AFTER  sortSelections() " + sels.size() + " new Selitems!");
    }

    /**
     * function to remove a position of selections
     */
    public void removeAlignmentPosition(int p) {
        for (int j = 0; j < sels.size(); j++) {
            SelItem comp = (SelItem) sels.get(j);
            if (comp != null) {
                if (comp.posa == p) {
                    sels.remove(j);
                    j--;
                } else if (comp.posb == p) {
                    sels.remove(j);
                    j--;
                } else if (comp.posa <= p && comp.posb >= p) {
                    sels.remove(j);
                    j--;
                }
            } else if (comp == null) {
                sels.remove(j);
                j--;
            }
        }
    }

    /**
     * function to remove an array of positions
     */
    public void removeAlignmentPositions(int[] paa) {
        if (paa.length == alimaxlen)
            for (int i = 0; i < paa.length; i++) {
                if (paa[i] > 0)
                    removeAlignmentPosition(i);
            }
        else
            System.out.println("Problem with alignment indexing: observed length " + paa.length + " while max real maximum is " + alimaxlen + ".");
    }

    /**
     * function to remove all SelItem objects from the current SCF object
     * where the sequence = s or s is contained in the range (seqa, sebq)..
     */
    public void removeAlignmentSequence(int s) {

        //System.out.println("SCF removeAlignmentSequence "+s);
        for (int j = 0; j < sels.size(); j++) {
            SelItem comp = (SelItem) sels.get(j);
            if (comp.seqa == s || (comp.seqa <= s && comp.seqb >= s)) {
                sels.remove(j);
                j--;
            }
        }
    }

    /**
     * function to remove all SelItem objects from the current SCF object
     * where the sequence = s.
     */
    public void removeSequenceSeqa(int s) {

        for (int j = 0; j < sels.size(); j++) {

            SelItem comp = (SelItem) sels.get(j);

            if (comp.seqa == s || comp.seqb == s) {

                //System.out.println("SCF removeSequenceSeqa "+s+"\t"+comp);
                sels.remove(j);
                j--;
            }
        }
    }

    /**
     * function to add all SelItem objects from another SCF object
     * with sequence number (x1) =s.
     */
    public void addAlignmentSequence(int s, SCF nowscf) {
        for (int j = 0; j < nowscf.sels.size(); j++) {
            SelItem comp = (SelItem) nowscf.sels.get(j);
            if (comp.seqa == s) {
                sels.add((SelItem) comp);
            }
        }
    }

    /**
     * function to remove a vector of SelItem objects from the global
     * selection vector stored in the SCF class
     */
    public void removeSelections(ArrayList d) {
        for (int i = 0; i < d.size(); i++) {
            SelItem remthis = (SelItem) d.get(i);
            for (int j = 0; j < sels.size(); j++) {
                SelItem comp = (SelItem) sels.get(j);
                if (comp.equals(remthis)) {
                    //System.out.println("removing SelItem "+comp.toString());
                    sels.remove(j);
                    j--;
                }
            }
        }
    }


    /**
     * function to replace the current global selection vector, with this one
     */
    public void replaceSelections(ArrayList d) {
        sels = new ArrayList();
        for (int i = 0; i < d.size(); i++) {
            SelItem remthis = (SelItem) d.get(i);
            sels.add(remthis);
        }
    }

    /**
     * Function which reads a selection from a file, and loads it into a vector object
     *
     * @param readdir
     */
    public void read(String readdir) {

        ArrayList thesesels = new ArrayList();

        try {

            BufferedReader in = new BufferedReader(new FileReader(readdir));
            String data = null;
            StringTokenizer tokens = null;
            int count = 0;
            boolean end = false;
            int linecount = 0;
            try {

                while (end == false) {

                    data = in.readLine();
//System.out.println("SCF read: "+data);
                    if (data == null) {
                        end = true;
                        break;
                    }

                    while(data.indexOf("#")==0)
                        data = in.readLine();

                    String label = "//null comment";
                    int comment = -1;
                    comment = data.indexOf("//");
                    if (comment != -1) {

                        label = data.substring(comment);
                        data = data.substring(0, comment);
                    }
                    if (data == null) {
                        end = true;
                        break;
                    }

                    linecount++;

                    tokens = new StringTokenizer(data);//, "\t");

                    if (tokens == null) {
                        end = true;
                        break;
                    }

                    int all = tokens.countTokens();
//System.out.println("SCF all tokens: "+all);
                    int countok = 0;
                    int seqa = -1;
                    int seqb = -1;
                    int posa = -1;
                    int posb = -1;

                    int r = -1;
                    int g = -1;
                    int b = -1;

                    if (all == 0) {
                        end = true;
                        break;
                    }

                    if (all > 1)
                        while (countok < all) {
                            //System.out.println("SCF: "+count+"\t"+tokens+"\t"+all);
                            if (countok == 0) {
                                posa = (int) (Float.valueOf(tokens.nextToken())).floatValue();
                                countok++;
                            }
                            if (countok == 1 && all > 6) {
                                posb = (int) (Float.valueOf(tokens.nextToken())).floatValue();
                                countok++;
                            }
                            if ((countok == 2 && all > 6) || (countok == 1 && all < 6)) {
                                seqa = (int) (Float.valueOf(tokens.nextToken())).floatValue();
                                countok++;
                            }
                            if (countok == 3 && all > 6) {
                                seqb = (int) (Float.valueOf(tokens.nextToken())).floatValue();
                                countok++;
                            }
                            if (countok == 4 && all > 6 || (countok == 2 && all < 6)) {
                                r = (int) (Float.valueOf(tokens.nextToken())).floatValue();
                                countok++;
                            }
                            if (countok == 5 && all > 6 || (countok == 3 && all < 6)) {
                                g = (int) (Float.valueOf(tokens.nextToken())).floatValue();
                                countok++;
                            }
                            if (countok == 6 && all > 6 || (countok == 4 && all < 6)) {
                                b = (int) (Float.valueOf(tokens.nextToken())).floatValue();
                                Color addnow = new Color(r, g, b);

                                if (seqb == -1)
                                    seqb = seqa;
                                if (posb == -1)
                                    posb = posa;

                                SelItem hej = new SelItem(seqa, seqb, posa, posb, addnow, label);

                                thesesels.add((SelItem) hej);
//System.out.println("SCF adding:  "+hej.toString()+"   "+thesesels.size());
                                countok = all;
                            }
                        }
                }
            } catch (IOException e) {
                System.out.println("Error with file.");
            }
        } catch (Exception e) {
            //System.out.println("No such file.");
        }

        if (thesesels != null) {
            //System.out.println("SCF READ  " + thesesels.size() + " new Selitems! " + readdir);
            addSelections(thesesels);
            //System.out.println("SCF added  " + sels.size() + " new Selitems! " + readdir);
        }

    }

    /**
     * Counts the number of colors per column.
     */
    public int[] countColorPerCol() {

        int[] ret = new int[alimaxlen];
        ArrayList[] colors = new ArrayList[alimaxlen];

        for (int i = 0; i < sels.size(); i++) {
            SelItem hej = new SelItem((SelItem) sels.get(i));

            if (colors[hej.posa] == null) {

                colors[hej.posa] = new ArrayList();
                colors[hej.posa].add((Color) hej.col);
            }

        }
        for (int i = 0; i < alimaxlen; i++) {

            if (colors[i] != null)
                ret[i] = colors[i].size();
            else
                ret[i] = 0;
        }

        return ret;
    }

    private void removeNull() {

        for (int i = 0; i < sels.size(); i++) {

            SelItem hej = (SelItem) sels.get(i);

            if (hej == null || hej.col == null) {

                //System.out.println("removing selection "+i);
                sels.remove(i);
                i--;
            }

        }

    }

    /**
     * Removes redundancy in selection vector.
     */
    private void makeNonredundant() {

        //System.out.println("makeNonredundant start  "+sels.size()+"  selections.");
        removeNull();

        //part1 exact redundanct
        String test = " ";
        removePureRedundant();

        //System.out.println("makeNonredundant remove pure  "+sels.size()+"  selections.");

        //part2 compaction step
        for (int i = 0; i < sels.size(); i++) {

            SelItem hej = (SelItem) sels.get(i);
            if (hej.seqa > 0 && hej.seqb > 0) {
//System.out.println("starting  "+i+"  "+hej.posa+"  "+hej.seqa+"   "+hej.seqb);
                for (int j = i + 1; j < sels.size(); j++) {

                    if (i != j) {

                        SelItem heja = (SelItem) sels.get(j);
                        if ((heja.posa > 0 && heja.posb > 0)) {

                            if (hej.col.equals(heja.col))
                                if (hej.posa == heja.posa) {
//System.out.println("comparing  "+j+"  "+heja.posa+"  "+heja.seqa+"   "+heja.seqb);
                                    boolean d = false;

                                    //compact single sels

                                    if (hej.seqa <= heja.seqa && hej.seqb >= heja.seqb) {
                                        d = true;
                                    }
                                    if (hej.seqa > heja.seqa && hej.seqa <= heja.seqb && hej.seqb >= heja.seqb) {
                                        hej.seqa = heja.seqa;
                                        d = true;
                                    }
                                    if (hej.seqa <= heja.seqa && hej.seqb < heja.seqb && hej.seqb >= heja.seqa) {
                                        hej.seqb = heja.seqb;
                                        d = true;
                                    }
                                    if (d) {
                                        if (i < sels.size())
                                            sels.set(i, (SelItem) hej);
                                        else
                                            sels.add((SelItem) hej);
//System.out.println("updating  "+i+"  "+hej.posa+"  "+hej.seqa+"   "+hej.seqb);
                                        sels.remove(j);
                                        //System.out.println("removing  " + j + "  " + heja.posa + "  " + heja.seqa + "   " + heja.seqb);
//System.out.println(sels.size());
                                        j--;
                                    }
                                }
                        }
                    }
                }
            }
        }
        //System.out.println("makeNonredundant final  "+sels.size()+"  selections.");
    }

    /**
     * Removes identical selections.
     */
    private void removePureRedundant() {
        for (int i = 0; i < sels.size(); i++) {

            SelItem hej = (SelItem) sels.get(i);
            for (int j = 0; j < sels.size(); j++) {

                if (i != j) {

                    SelItem heja = (SelItem) sels.get(j);
                    if (heja.equals(hej)) {
                        //System.out.println("removing in nonred "+heja.toString());
                        sels.remove(j);
                        j--;
                    }
                }
            }
        }
    }

    /**
     * Orders the selections by sequence and position.
     */
    private void orderSels() {
        for (int i = 0; i < sels.size(); i++) {
            SelItem hej = (SelItem) sels.get(i);
            if (hej != null) {
                if (hej.seqa > hej.seqb) {
                    int k = hej.seqb;
                    hej.seqb = hej.seqa;
                    hej.seqa = k;
                    sels.set(i, hej);
                }
                if (hej.posa > hej.posb) {
                    int k = hej.posb;
                    hej.posb = hej.posa;
                    hej.posa = k;
                    sels.set(i, hej);
                }
            } else if (hej == null) {
                sels.remove(i);
                i--;
            }
        }
    }

    /**
     * Sorts the selections by .posa and .seqa.
     */
    private void sortSelections() {

        if (sels != null && sels.size() > 1) {
            ArrayList real = new ArrayList();

            int count = 0;
            for (int i = 0; i < sels.size(); i++) {

                SelItem add = new SelItem((SelItem) sels.get(i));
                if (add.seqa == -1) {
                    real.add((SelItem) add);
                    removeSelectionAt(i);
                    i--;
                }
            }

            int j = findMinPosa();
            int k = findMinSeqaGivenPosa(j);

            int round = 0;
            //System.out.println("sorting " + j + "\t" + k + "\tround: "+round);

            while (k > -1 && k < sels.size()) {

                SelItem add = new SelItem((SelItem) sels.get(k));
                real.add((SelItem) add);
                removeSelectionAt(k);

                //System.out.println("copy of sel " + real.size());
                //System.out.println("cur size of sel " + sels.size());

                j = findMinPosa();
                k = findMinSeqaGivenPosa(j);

                round++;
                //System.out.println("sorting " + j + "\t" + k + "\tround: " + round);
            }

            //System.out.println("copy of sel " + real.size());

            clear();

            for (int ia = 0; ia < real.size(); ia++) {
                SelItem now = (SelItem) (real.get(ia));
                sels.add((SelItem) now);
                //System.out.println("loading sel "+sels.size());
            }
        }
    }

    /**
     * Finds the minimum .posa value from the SelItem ArrayList.
     */
    private int findMinPosa() {
        int ret = alimaxlen + 1000;
        for (int j = 0; j < sels.size(); j++) {
            SelItem now = (SelItem) sels.get(j);
            if (now.posa < ret) {
                ret = now.posa;
                //System.out.println("Found "+j+"\tfor MIN .posa "+ret);
            }
        }

        if (ret == alimaxlen + 1000)
            ret = -1;

        return ret;
    }

    /**
     * Finds the SelItem object with minimum .seqa.
     */
    private int findMinSeqa() {
        int ret = totalseqs;
        for (int j = 0; j < sels.size(); j++) {
            SelItem now = (SelItem) sels.get(j);
            if (now.seqa < ret)
                ret = now.seqa;
        }
        return ret;
    }

    /**
     * Finds the SelItem object with minimum .seqa given a .posa.
     */
    private int findMinSeqaGivenPosa(int p) {

        int ret = totalseqs + 1;

        //System.out.println("totalseqs+1 "+totalseqs+1);
        int min = -1;

        for (int j = 0; j < sels.size(); j++) {

            SelItem now = (SelItem) sels.get(j);
            //if(j == 0)
            //System.out.println("TESTING "+j+"\t"+now.toString());

            //System.out.println("findMinSeqaGivenPosa "+j+"\tret: "+ret+"\t"+now.seqa+"\tp: "+p+"\t"+now.posa);//now.toString());
            if (now.posa == p && now.seqa < ret) {

                //System.out.println("Found "+j+"\tfor .posa "+p+"\t"+now);
                ret = now.seqa;
                min = j;
            }
        }

        ret = min;
        return ret;
    }

    /**
     * returns the current (compact) selections as
     * individual amino acid
     * or
     * column (0) selections
     */
    public ArrayList retSingleSels() {
        ArrayList ret = new ArrayList();
        for (int i = 0; i < sels.size(); i++) {
            SelItem now = (SelItem) sels.get(i);
            if (now != null) {
                int pa = now.posa;
                int pb = now.posb;
                int sa = now.seqa;
                int sb = now.seqb;
//System.out.println("pos: "+pa+"  "+pb+"\t\t seq:"+sa+" "+sb);
                if (sa > 0) {
                    while (pa < pb + 1) {
                        while (sa < sb + 1) {
                            SelItem add = new SelItem(sa, pa, now.col);
                            ret.add(add);
                            sa++;
                        }
                        pa++;
                    }
                } else if (sa == 0) {

                    SelItem addnow = new SelItem(sa, pa, now.col);
                    ret.add(addnow);
                    /*
                    for(int j=0;j < totalseqs;j++) {

                        SelItem addnow = new SelItem(j, pa, now.col);
                        ret.add(addnow);
                    }
                    */

                } else if (sa == -1) {
                    SelItem add = new SelItem(sa, pa, now.col);
                    ret.add(add);
                }

            } else if (now == null) {
                sels.remove(i);
                i--;
            }
        }
        return ret;
    }


    /**
     * Returns an aray indicating which columns have been assigned a score, i.e. seq coordinate = -1. Returns [i]=1 for scored columns.
     *
     * @return
     */
    public int[] retScorePosArray(int max) {


        int[] scored = new int[max];
        for (int i = 0; i < sels.size(); i++) {

            SelItem cur = (SelItem) sels.get(i);
            if (cur.seqa == -1) {

                scored[cur.posa] = 1;
            }

        }
        return scored;
    }

    /**
     * Function for writing selections to a file.
     */
    public void write(String writedir, int seqs, int cols) {

        if (writedir.indexOf(".seqsel") == -1 && writedir.indexOf(".SEQSEL") == -1)
            writedir = writedir + ".seqsel";

//System.out.println("String for SCF file name "+writedir);

        if (sels != null && sels.size() > 0) {
            orderSels();
            //System.out.println("Selection vector size:   "+sels.size()+" .");
            // makeNonredundant();
            //System.out.println("Selection vector size after nonred routine:   "+sels.size()+" .");
            sortSelections();
            //System.out.println("Selection vector size after sorting:   "+sels.size()+" .");

            int[] zeropos = new int[alimaxlen];
            try {

                PrintWriter pif = new PrintWriter(new FileWriter(writedir));

                if(seqs!=-1 && cols!=-1)
                    pif.println("#Seqs: "+seqs+"\tColumns: "+cols);

                for (int i = 0; i < sels.size(); i++) {
                    SelItem now = (SelItem) sels.get(i);
                    int[] colval = new int[3];
                    colval[0] = now.col.getRed();
                    colval[1] = now.col.getGreen();
                    colval[2] = now.col.getBlue();

                    pif.print(now.posa + "    " + now.posb + "    " + now.seqa + "     " + now.seqb + "    " + colval[0] + "   " + colval[1] + "   " + colval[2] + "      " + now.extra + "\n");

                }
                pif.close();
            } catch (IOException e) {
                System.out.println("Could not write to file ...   " + writedir);
            }

        }
        //else
        //  System.out.println("No sequence selections have been made.");
    }




}
