private static Alignment traceback(Sequence s1, Sequence s2, Matrix m,
            byte[] pointers, Cell cell, short[] sizesOfVerticalGaps,
            short[] sizesOfHorizontalGaps) {

        char[] a1 = s1.toArray();
        char[] a2 = s2.toArray();

        float[][] scores = m.getScores();

        int n = s2.length() + 1;

        Alignment alignment = new Alignment();
        alignment.setScore(cell.getScore());

        int maxlen = s1.length() + s2.length(); // maximum length after the
        // aligned sequences

        char[] reversed1 = new char[maxlen]; // reversed sequence #1
        char[] reversed2 = new char[maxlen]; // reversed sequence #2
        char[] reversed3 = new char[maxlen]; // reversed markup

        int len1 = 0; // length of sequence #1 after alignment
        int len2 = 0; // length of sequence #2 after alignment
        int len3 = 0; // length of the markup line

        int identity = 0; // count of identitcal pairs
        int similarity = 0; // count of similar pairs
        int gaps = 0; // count of gaps

        char c1, c2;

        int i = cell.getRow(); // traceback start row
        int j = cell.getCol(); // traceback start col
        int k = i * n;

        boolean stillGoing = true; // traceback flag: true -> continue & false
        // -> stop

        while (stillGoing) {
            switch (pointers[k + j]) {
                case Directions.UP:
                    for (int l = 0, len = sizesOfVerticalGaps[k + j]; l < len; l++) {
                        reversed1[len1++] = a1[--i];
                        reversed2[len2++] = Alignment.GAP;
                        reversed3[len3++] = Markups.GAP;
                        k -= n;
                        gaps++;
                    }
                    break;
                case Directions.DIAGONAL:
                    c1 = a1[--i];
                    c2 = a2[--j];
                    k -= n;
                    reversed1[len1++] = c1;
                    reversed2[len2++] = c2;
                    if (c1 == c2) {
                        reversed3[len3++] = Markups.IDENTITY;
                        identity++;
                        similarity++;
                    } else if (scores[c1][c2] > 0) {
                        reversed3[len3++] = Markups.SIMILARITY;
                        similarity++;
                    } else {
                        reversed3[len3++] = Markups.MISMATCH;
                    }
                    break;
                case Directions.LEFT:
                    for (int l = 0, len = sizesOfHorizontalGaps[k + j]; l < len; l++) {
                        reversed1[len1++] = Alignment.GAP;
                        reversed2[len2++] = a2[--j];
                        reversed3[len3++] = Markups.GAP;
                        gaps++;
                    }
                    break;
                case Directions.STOP:
                    stillGoing = false;
            }
        }

        alignment.setSequence1(reverse(reversed1, len1));
        alignment.setStart1(i);
        alignment.setSequence2(reverse(reversed2, len2));
        alignment.setStart2(j);
        alignment.setMarkupLine(reverse(reversed3, len3));
        alignment.setIdentity(identity);
        alignment.setGaps(gaps);
        alignment.setSimilarity(similarity);

        return alignment;
    }