#!/usr/bin/env perl

use strict;
use warnings;
use Test::More 'no_plan';
use Data::Dumper;
use Maasha::AlignTwoSeq;

test_new_space();
test_new_space_left();
test_new_space_right();

test_matches_select();

test_word_size_calc();
test_seq_index();
test_seq_scan();
test_matches_find();

test_match_expand_forward_end_space();
test_match_expand_forward_end_match();
test_match_expand_backward_end_space();
test_match_expand_backward_end_match();
test_match_expand_end_space();
test_match_expand_end_match();

test_match_redundant_add();
test_match_redundant();

test_matches_filter();

test_match_score_narrow();
test_match_score_diag();
test_match_score_len();
test_match_score();

test_align_two_seq();

test_insert_indels();


sub test_new_space
{
    my $space = { Q_SEQ => \"ATCG", S_SEQ => \"atcg" };
    
    Maasha::AlignTwoSeq::new_space( $space );

    is( ${ $space->{ 'Q_SEQ' } }, "ATCG" );
    is( ${ $space->{ 'S_SEQ' } }, "atcg" );
    ok( $space->{ 'Q_MIN' } == 0 );
    ok( $space->{ 'S_MIN' } == 0 );
    ok( $space->{ 'Q_MAX' } == 3 );
    ok( $space->{ 'S_MAX' } == 3 );
}


sub test_new_space_left
{
    my ( $best_match, $space, $new_space );

    $best_match = {
        Q_BEG => 2,
        Q_END => 3,
        S_BEG => 2,
        S_END => 3,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 3,
        S_MAX => 3,
    };

    $new_space = Maasha::AlignTwoSeq::new_space_left( $best_match, $space );

    ok( defined $new_space );
    is( ${ $new_space->{ 'Q_SEQ' } }, "ATCG" );
    is( ${ $new_space->{ 'S_SEQ' } }, "atcg" );
    ok( $new_space->{ 'Q_MIN' } == 0 );
    ok( $new_space->{ 'S_MIN' } == 0 );
    ok( $new_space->{ 'Q_MAX' } == 1 );
    ok( $new_space->{ 'S_MAX' } == 1 );
}


sub test_new_space_right
{
    my ( $best_match, $space, $new_space );

    $best_match = {
        Q_BEG => 0,
        Q_END => 1,
        S_BEG => 0,
        S_END => 1,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 3,
        S_MAX => 3,
    };

    $new_space = Maasha::AlignTwoSeq::new_space_right( $best_match, $space );

    ok( defined $new_space );
    is( ${ $new_space->{ 'Q_SEQ' } }, "ATCG" );
    is( ${ $new_space->{ 'S_SEQ' } }, "atcg" );
    ok( $new_space->{ 'Q_MIN' } == 2 );
    ok( $new_space->{ 'S_MIN' } == 2 );
    ok( $new_space->{ 'Q_MAX' } == 3 );
    ok( $new_space->{ 'S_MAX' } == 3 );
}


sub test_matches_select
{
    my ( $matches, $space );

    $matches = [
        { Q_BEG => 9,  S_BEG =>  9, Q_END => 10, S_END => 10 },
        { Q_BEG => 10, S_BEG => 10, Q_END => 20, S_END => 20 },
        { Q_BEG => 20, S_BEG => 20, Q_END => 21, S_END => 21 },
    ];

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 10,
        S_MIN => 10,
        Q_MAX => 20,
        S_MAX => 20,
    };

    Maasha::AlignTwoSeq::matches_select( $matches, $space );

    ok( scalar @{ $matches } == 1 );
}


sub test_word_size_calc
{
    ok( Maasha::AlignTwoSeq::word_size_calc( { Q_MIN => 0, S_MIN => 0, Q_MAX => 1, S_MAX => 1 } ) == 1 );
    ok( Maasha::AlignTwoSeq::word_size_calc( { Q_MIN => 0, S_MIN => 0, Q_MAX => 200, S_MAX => 200 } ) == 10 + 1 );
}


sub test_seq_index
{
    my ( $space, $word_size, $index );

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 3,
        S_MAX => 3,
    };

    $word_size = 2;
    
    $index = Maasha::AlignTwoSeq::seq_index( $space, $word_size );

    ok( scalar keys %{ $index } == 3 );
    ok( exists $index->{ 'AT' } );
    ok( exists $index->{ 'TC' } );
    ok( exists $index->{ 'CG' } );
    ok( $index->{ 'AT' }->[ 0 ] == 0 );
    ok( $index->{ 'TC' }->[ 0 ] == 1 );
    ok( $index->{ 'CG' }->[ 0 ] == 2 );
}


sub test_seq_scan
{
    my ( $space, $word_size, $index, $matches );

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 3,
        S_MAX => 3,
    };

    $word_size = 2;
    
    $index   = Maasha::AlignTwoSeq::seq_index( $space, $word_size );
    $matches = Maasha::AlignTwoSeq::seq_scan( $index, $space, $word_size );

    ok( scalar @{ $matches } == 1 );
    ok( $matches->[ 0 ]->{ 'Q_BEG' } == 0 );
    ok( $matches->[ 0 ]->{ 'S_BEG' } == 0 );
    ok( $matches->[ 0 ]->{ 'Q_END' } == 3 );
    ok( $matches->[ 0 ]->{ 'S_END' } == 3 );
    ok( $matches->[ 0 ]->{ 'LEN' }   == 4 );
    ok( $matches->[ 0 ]->{ 'SCORE' } == 0 );
}


sub test_matches_find
{
    my ( $space, $matches );

    $space = { Q_SEQ => \"ATCG", S_SEQ => \"ATCG", Q_MIN => 0, S_MIN => 0, Q_MAX => 3, S_MAX => 3 };

    $matches = Maasha::AlignTwoSeq::matches_find( $space );

    ok( scalar @{ $matches } == 1 );
    ok( $matches->[ 0 ]->{ 'Q_BEG' } == 0 );
    ok( $matches->[ 0 ]->{ 'S_BEG' } == 0 );
    ok( $matches->[ 0 ]->{ 'Q_END' } == 3 );
    ok( $matches->[ 0 ]->{ 'S_END' } == 3 );
    ok( $matches->[ 0 ]->{ 'LEN' }   == 4 );

    $space = { Q_SEQ => \"ATXXGAT", S_SEQ => \"ATCGAT", Q_MIN => 0, S_MIN => 0, Q_MAX => 6, S_MAX => 5 };

    $matches = Maasha::AlignTwoSeq::matches_find( $space );

    ok( scalar @{ $matches } == 4 );
    ok( $matches->[ 0 ]->{ 'Q_BEG' } == 0 );
    ok( $matches->[ 0 ]->{ 'S_BEG' } == 0 );
    ok( $matches->[ 0 ]->{ 'Q_END' } == 1 );
    ok( $matches->[ 0 ]->{ 'S_END' } == 1 );
    ok( $matches->[ 0 ]->{ 'LEN' }   == 2 );
    ok( $matches->[ 1 ]->{ 'Q_BEG' } == 5 );
    ok( $matches->[ 1 ]->{ 'S_BEG' } == 0 );
    ok( $matches->[ 1 ]->{ 'Q_END' } == 6 );
    ok( $matches->[ 1 ]->{ 'S_END' } == 1 );
    ok( $matches->[ 1 ]->{ 'LEN' }   == 2 );
    ok( $matches->[ 2 ]->{ 'Q_BEG' } == 4 );
    ok( $matches->[ 2 ]->{ 'S_BEG' } == 3 );
    ok( $matches->[ 2 ]->{ 'Q_END' } == 6 );
    ok( $matches->[ 2 ]->{ 'S_END' } == 5 );
    ok( $matches->[ 2 ]->{ 'LEN' }   == 3 );
    ok( $matches->[ 3 ]->{ 'Q_BEG' } == 0 );
    ok( $matches->[ 3 ]->{ 'S_BEG' } == 4 );
    ok( $matches->[ 3 ]->{ 'Q_END' } == 1 );
    ok( $matches->[ 3 ]->{ 'S_END' } == 5 );
    ok( $matches->[ 3 ]->{ 'LEN' }   == 2 );
}

sub test_match_expand_forward_end_space
{
    my ( $match, $space );

    $match = {
        Q_BEG => 1,
        Q_END => 2,
        S_BEG => 1,
        S_END => 2,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 3,
        S_MAX => 3,
    };

    Maasha::AlignTwoSeq::match_expand_forward( $match, $space );

    ok( $match->{ 'Q_BEG' } == 1 );
    ok( $match->{ 'S_BEG' } == 1 );
    ok( $match->{ 'Q_END' } == 3 );
    ok( $match->{ 'S_END' } == 3 );
    ok( $match->{ 'LEN' }   == 3 );
}


sub test_match_expand_forward_end_match
{
    my ( $match, $space );

    $match = {
        Q_BEG => 1,
        Q_END => 2,
        S_BEG => 1,
        S_END => 2,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"ATCGXX",
        S_SEQ => \"atcgnn",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 6,
        S_MAX => 6,
    };

    Maasha::AlignTwoSeq::match_expand_forward( $match, $space );

    ok( $match->{ 'Q_BEG' } == 1 );
    ok( $match->{ 'S_BEG' } == 1 );
    ok( $match->{ 'Q_END' } == 3 );
    ok( $match->{ 'S_END' } == 3 );
    ok( $match->{ 'LEN' }   == 3 );
}


sub test_match_expand_backward_end_space
{
    my ( $match, $space );

    $match = {
        Q_BEG => 1,
        Q_END => 2,
        S_BEG => 1,
        S_END => 2,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 3,
        S_MAX => 3,
    };

    Maasha::AlignTwoSeq::match_expand_backward( $match, $space );

    ok( $match->{ 'Q_BEG' } == 0 );
    ok( $match->{ 'S_BEG' } == 0 );
    ok( $match->{ 'Q_END' } == 2 );
    ok( $match->{ 'S_END' } == 2 );
    ok( $match->{ 'LEN' }   == 3 );
}


sub test_match_expand_backward_end_match
{
    my ( $match, $space );

    $match = {
        Q_BEG => 2,
        Q_END => 3,
        S_BEG => 2,
        S_END => 3,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"XATCG",
        S_SEQ => \"natcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 4,
        S_MAX => 4,
    };

    Maasha::AlignTwoSeq::match_expand_backward( $match, $space );

    ok( $match->{ 'Q_BEG' } == 1 );
    ok( $match->{ 'S_BEG' } == 1 );
    ok( $match->{ 'Q_END' } == 3 );
    ok( $match->{ 'S_END' } == 3 );
    ok( $match->{ 'LEN' }   == 3 );
}


sub test_match_expand_end_space
{
    my ( $match, $space );

    $match = {
        Q_BEG => 1,
        Q_END => 2,
        S_BEG => 1,
        S_END => 2,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"ATCG",
        S_SEQ => \"atcg",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 3,
        S_MAX => 3,
    };

    Maasha::AlignTwoSeq::match_expand( $match, $space );

    ok( $match->{ 'Q_BEG' } == 0 );
    ok( $match->{ 'S_BEG' } == 0 );
    ok( $match->{ 'Q_END' } == 3 );
    ok( $match->{ 'S_END' } == 3 );
    ok( $match->{ 'LEN' }   == 4 );
}


sub test_match_expand_end_match
{
    my ( $match, $space );

    $match = {
        Q_BEG => 2,
        Q_END => 3,
        S_BEG => 2,
        S_END => 3,
        SCORE => 0,
        LEN   => 2,
    };

    $space = {
        Q_SEQ => \"XATCGX",
        S_SEQ => \"natcgn",
        Q_MIN => 0,
        S_MIN => 0,
        Q_MAX => 6,
        S_MAX => 6,
    };

    Maasha::AlignTwoSeq::match_expand( $match, $space );

    ok( $match->{ 'Q_BEG' } == 1 );
    ok( $match->{ 'S_BEG' } == 1 );
    ok( $match->{ 'Q_END' } == 4 );
    ok( $match->{ 'S_END' } == 4 );
    ok( $match->{ 'LEN' }   == 4 );
}


sub test_match_redundant_add
{
    my ( $redundant );

    $redundant = {};

    Maasha::AlignTwoSeq::match_redundant_add( { Q_BEG => 10, Q_END => 20, S_BEG => 110, S_END => 120 }, $redundant );
    Maasha::AlignTwoSeq::match_redundant_add( { Q_BEG => 15, Q_END => 25, S_BEG => 210, S_END => 220 }, $redundant );

    ok( scalar keys %{ $redundant } == 16 );
}


sub test_match_redundant
{
    my ( $redundant );

    $redundant = {};

    Maasha::AlignTwoSeq::match_redundant_add( { Q_BEG => 10, Q_END => 20, S_BEG => 110, S_END => 120 }, $redundant );
    Maasha::AlignTwoSeq::match_redundant_add( { Q_BEG => 15, Q_END => 25, S_BEG => 210, S_END => 220 }, $redundant );

    ok( Maasha::AlignTwoSeq::match_redundant( { Q_BEG => 10, Q_END => 20, S_BEG => 110, S_END => 120 }, $redundant ) );
    ok( not Maasha::AlignTwoSeq::match_redundant( { Q_BEG => 1, Q_END => 2, S_BEG => 110, S_END => 120 }, $redundant ) );
}


sub test_matches_filter
{
    ok( 0 );
}


sub test_match_score_narrow
{
    ok( 0 );
}


sub test_match_score_diag
{
    ok( 0 );
}


sub test_match_score_len
{
    ok( 0 );
}


sub test_match_score
{
    ok( 0 );
}


sub test_align_two_seq
{
    my ( $space, $matches );

    $space = {
        Q_SEQ => \"ATXCG",
        S_SEQ => \"ATCG",
    };

    $matches = Maasha::AlignTwoSeq::align_two_seq( $space, [] );

#    print Dumper( $matches );

    ok( 0 );
}


sub test_insert_indels
{
    my ( $matches, $q_seq, $s_seq );

    $matches = [
        { Q_BEG => 1, S_BEG => 1, Q_END => 4, S_END => 4 }
    ];

    $q_seq = "XATCG";
    $s_seq = "PATCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "XATCG" );
    is( $s_seq, "PATCG" );

    $matches = [
        { Q_BEG => 0, S_BEG => 1, Q_END => 3, S_END => 4 }
    ];

    $q_seq = "ATCG";
    $s_seq = "PATCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "-ATCG" );
    is( $s_seq, "PATCG" );

    $matches = [
        { Q_BEG => 1, S_BEG => 0, Q_END => 4, S_END => 3 }
    ];

    $q_seq = "XATCG";
    $s_seq = "ATCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "XATCG" );
    is( $s_seq, "-ATCG" );

    $matches = [
        { Q_BEG => 0, S_BEG => 0, Q_END => 3, S_END => 3 },
        { Q_BEG => 6, S_BEG => 6, Q_END => 9, S_END => 9 },
    ];

    $q_seq = "ATCGXXATCG";
    $s_seq = "ATCGNNATCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "ATCGXXATCG" );
    is( $s_seq, "ATCGNNATCG" );

    $matches = [
        { Q_BEG => 0, S_BEG => 0, Q_END => 3, S_END => 3 },
        { Q_BEG => 6, S_BEG => 4, Q_END => 9, S_END => 7 },
    ];

    $q_seq = "ATCGXXATCG";
    $s_seq = "ATCGATCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "ATCGXXATCG" );
    is( $s_seq, "ATCG--ATCG" );

    $matches = [
        { Q_BEG => 0, S_BEG => 1, Q_END => 2, S_END => 3 },
        { Q_BEG => 5, S_BEG => 4, Q_END => 8, S_END => 7 },
    ];

    $q_seq = "TCGXXATCG";
    $s_seq = "ATCGATCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "-TCGXXATCG" );
    is( $s_seq, "ATCG--ATCG" );

    $matches = [
        { Q_BEG => 1, S_BEG => 0, Q_END => 3, S_END => 2 },
        { Q_BEG => 6, S_BEG => 3, Q_END => 9, S_END => 6 },
    ];

    $q_seq = "ATCGXXATCG";
    $s_seq = "TCGATCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "ATCGXXATCG" );
    is( $s_seq, "-TCG--ATCG" );

    $matches = [
        { Q_BEG => 1, Q_END =>  3, S_BEG => 0, S_END => 2 },
        { Q_BEG => 6, Q_END =>  7, S_BEG => 3, S_END => 4 },
        { Q_BEG => 9, Q_END => 10, S_BEG => 7, S_END => 8 },
    ];

    $q_seq = "ATCGXXATACG";
    $s_seq = "TCGATNTCG";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "ATCGXXAT-ACG" );
    #             |||  ||  ||
    is( $s_seq, "-TCG--ATNTCG" );

    $matches = [
        { Q_BEG => 1, Q_END =>  3, S_BEG => 0, S_END => 2 },
        { Q_BEG => 6, Q_END =>  7, S_BEG => 3, S_END => 4 },
        { Q_BEG => 9, Q_END => 10, S_BEG => 7, S_END => 8 },
    ];

    $q_seq = "ATCGXXATACG";
    $s_seq = "TCGATNTCGXX";

    Maasha::AlignTwoSeq::insert_indels( $matches, \$q_seq, \$s_seq );

    is( $q_seq, "ATCGXXAT-ACG--" );
    #             |||  ||  ||
    is( $s_seq, "-TCG--ATNTCGXX" );
}
