#include <ncbi.h>
#include <gishlib.h>
#include "blastapp.h"
/* hsp_cmp_default -- default routine for determining the best HSP */
int
hsp_cmp_default(h1, h2)
    HSPPtr  PNTR h1, PNTR h2;
{
    register Score_t    deltascore;
    register Coord_t    deltalen;
	int	i, f1, f2;

	/* Sort by frame */
	f1 = (*h1)->frame;
	f2 = (*h2)->frame;
	if (f1 != f2) {
		f1 = SIGN(f1);
		f2 = SIGN(f2);
		if (f1 != f2) {
			if (f1 > f2)
				return -1;
			return 1;
		}
	}

    /* Sort by score... */
    deltascore = (*h2)->score - (*h1)->score;
    if (deltascore != 0) {
		if (deltascore < 0)
			return -1;
		return 1;
	}

    /* then sort by length */
    deltalen = (Coord_t)(*h1)->len - (Coord_t)(*h2)->len;
    return SIGN(deltalen);
}

void
sort_HSPs(hlp)
	HitListPtr	hlp;
{
	if (hlp == NULL)
		return; /* Nothing to sort */
	LinkSort((VoidPtr PNTR)&hlp->hp, offsetof(HSP,next), (int (*)())hsp_cmp);
}

/* cmp_by_pval -- comparison function used to sort HSPs by probability, score */
int
cmp_by_pval(hli, hlj)
	HitList	**hli, **hlj;
{
	register HSPPtr	hi = (*hli)->signifhsp, hj = (*hlj)->signifhsp;

	if (hi->P_val < hj->P_val)
		return -1;
	if (hi->P_val > hj->P_val)
		return 1;

	hi = (*hli)->hp;
	hj = (*hlj)->hp;

	if (hi->score > hj->score)
		return -1;
	if (hi->score < hj->score)
		return 1;

	if (hi->len < hj->len)
		return -1;
	if (hi->len > hj->len)
		return 1;

	if ((*hli)->seq_nbr < (*hlj)->seq_nbr)
		return -1;
	if ((*hli)->seq_nbr > (*hlj)->seq_nbr)
		return 1;

	return 0;
}

int
cmp_by_count(hli, hlj)
	HitList	**hli, **hlj;
{
	int		i, j;

	i = (*hli)->hspcnt;
	j = (*hlj)->hspcnt;
	if (i != j)
		return j - i;
	if ((*hli)->seq_nbr < (*hlj)->seq_nbr)
		return -1;
	if ((*hli)->seq_nbr > (*hlj)->seq_nbr)
		return 1;
	return 0;
}


int
cmp_by_highscore(hli, hlj)
	HitList	**hli, **hlj;
{
	Score_t	si, sj, sdiff;

	si = (*hli)->highscore;
	sj = (*hlj)->highscore;
	sdiff = sj - si;
	if (sdiff != 0)
		return SIGN(sj - si);
	if ((*hli)->seq_nbr < (*hlj)->seq_nbr)
		return -1;
	if ((*hli)->seq_nbr > (*hlj)->seq_nbr)
		return 1;
	return 0;
}


int
cmp_by_totalscore(hli, hlj)
	HitList	**hli, **hlj;
{
	Score_t	si, sj;

	si = (*hli)->totalscore;
	sj = (*hlj)->totalscore;
	if (si != sj)
		return SIGN(sj - si);
	if ((*hli)->seq_nbr < (*hlj)->seq_nbr)
		return -1;
	if ((*hli)->seq_nbr > (*hlj)->seq_nbr)
		return 1;
	return 0;
}


void
sort_hitlists(hlpp, cmp)
	HitListPtr PNTR	hlpp;
	int	(*cmp)();
{
	LinkSort((VoidPtr PNTR)hlpp, offsetof(HitList,next), cmp);
}

/*
Used to ensure that hitlists are sorted by their order of appearance
in the database.  This permits faster retrieval of header lines
when the header file is kept on disk.
*/
int
cmp_hitlists_by_seqid(hli, hlj)
	HitListPtr	*hli, *hlj;
{
	register Seqid_t	hi = (*hli)->seq_nbr, hj = (*hlj)->seq_nbr;

	if (hi > hj)
		return 1;
	if (hi < hj)
		return -1;
	return 0;
}

void
sort_hitlists_by_seqid()
{
	LinkSort((VoidPtr PNTR)&firsthl, offsetof(HitList,next), (int (*)())cmp_hitlists_by_seqid);
}
