/* ===========================================================================
*
*                            PUBLIC DOMAIN NOTICE
*               National Center for Biotechnology Information
*
*  This software/database is a "United States Government Work" under the
*  terms of the United States Copyright Act.  It was written as part of
*  the author's official duties as a United States Government employee and
*  thus cannot be copyrighted.  This software/database is freely available
*  to the public for use. The National Library of Medicine and the U.S.
*  Government have not placed any restriction on its use or reproduction.
*
*  Although all reasonable efforts have been taken to ensure the accuracy
*  and reliability of the software and data, the NLM and the U.S.
*  Government do not and cannot warrant the performance or results that
*  may be obtained by using this software or data. The NLM and the U.S.
*  Government disclaim all warranties, express or implied, including
*  warranties of performance, merchantability or fitness for any particular
*  purpose.
*
*  Please cite the author in any work or product based on this material.
*
* ===========================================================================*/
#include <ncbi.h>
#include <blast/blast.h>

static BLAST_Letter _iupacaa_vec[] = {
	'A', 'B', 'C', 'D', 'E',
	'F', 'G', 'H', 'I', 'K',
	'L', 'M', 'N', 'P', 'Q',
	'R', 'S', 'T', 'V', 'W',
	'X', 'Y', 'Z'
	};

static BLAST_Letter _iupacna_vec[] = {
	'A', 'B', 'C', 'D', 'G',
	'H', 'K', 'M', 'N', 'R',
	'S', 'T', 'U', 'V', 'W', 'Y'
	};

static BLAST_Alphabet _oldblastaa = {
		NULL , NULL ,
		BLAST_ALPHATYPE_AMINO_ACID ,
		"OldBLASTaa" ,
		BLAST_ALPHA_OLDBLASTaa ,
		0 ,
		NULL ,
		1 , 24
	};

static BLAST_Alphabet _oldblastna = {
		NULL , NULL ,
		BLAST_ALPHATYPE_NUCLEIC_ACID ,
		"OldBLASTna" ,
		BLAST_ALPHA_OLDBLASTna ,
		0 ,
		NULL ,
		0 , 15
	};

static BLAST_Alphabet _print = {
		NULL , NULL ,
		BLAST_ALPHATYPE_ANY ,
		"Print" ,
		BLAST_ALPHA_PRINT ,
		0 ,
		NULL ,
		0 , UCHAR_MAX
	};

static BLAST_Alphabet _iupacaa = {
		NULL , NULL ,
		BLAST_ALPHATYPE_AMINO_ACID ,
		"IUPACaa" ,
		BLAST_ALPHA_IUPACaa ,
		DIM(_iupacaa_vec) ,
		_iupacaa_vec ,
	};

static BLAST_Alphabet _iupacna = {
		NULL , NULL ,
		BLAST_ALPHATYPE_NUCLEIC_ACID ,
		"IUPACna" ,
		BLAST_ALPHA_IUPACna ,
		DIM(_iupacna_vec) ,
		_iupacna_vec
	};

static BLAST_Alphabet _ncbistdaa = {
		NULL , NULL ,
		BLAST_ALPHATYPE_AMINO_ACID ,
		"NCBIstdaa" ,
		BLAST_ALPHA_NCBIstdaa ,
		0 ,
		NULL ,
		0 , 25
	};

static BLAST_Alphabet _ncbi2na = { /* 2-bit nucleic acid code */
		NULL , NULL ,
		BLAST_ALPHATYPE_NUCLEIC_ACID ,
		"NCBI2na" ,
		BLAST_ALPHA_NCBI2na ,
		0 ,
		NULL ,
		0 , 3
	};

static BLAST_Alphabet _ncbi4na = { /* 4-bit nucleic acid code */
		NULL , NULL ,
		BLAST_ALPHATYPE_NUCLEIC_ACID ,
		"NCBI4na" ,
		BLAST_ALPHA_NCBI4na ,
		0 ,
		NULL ,
		0 , 15
	};


static BLAST_AlphabetPtr	_alphalist[] = {
		&_oldblastaa ,
		&_oldblastna ,
		&_print ,
		&_iupacaa ,
		&_iupacna ,
		&_ncbistdaa ,
		&_ncbi2na ,
		&_ncbi4na
	};

/* master linked list of known alphabets */
static volatile BLAST_AlphabetPtr	master_a;

static BLAST_LetterPair	_iupacaa_to_oldblastaa_vec[] = {
		{ 'A',  1 },
		{ 'R',  2 },
		{ 'N',  3 },
		{ 'D',  4 },
		{ 'C',  5 },
		{ 'Q',  6 },
		{ 'E',  7 },
		{ 'G',  8 },
		{ 'H',  9 },
		{ 'I', 10 },
		{ 'L', 11 },
		{ 'K', 12 },
		{ 'M', 13 },
		{ 'F', 14 },
		{ 'P', 15 },
		{ 'S', 16 },
		{ 'T', 17 },
		{ 'W', 18 },
		{ 'Y', 19 },
		{ 'V', 20 }
	};

static BLAST_LetterPair	_print_to_oldblastaa_vec[] = {
		{ 'A',  1 }, { 'a',  1 },
		{ 'R',  2 }, { 'r',  2 },
		{ 'N',  3 }, { 'n',  3 },
		{ 'D',  4 }, { 'd',  4 },
		{ 'C',  5 }, { 'c',  5 },
		{ 'Q',  6 }, { 'q',  6 },
		{ 'E',  7 }, { 'e',  7 },
		{ 'G',  8 }, { 'g',  8 },
		{ 'H',  9 }, { 'h',  9 },
		{ 'I', 10 }, { 'i', 10 },
		{ 'L', 11 }, { 'l', 11 },
		{ 'K', 12 }, { 'k', 12 },
		{ 'M', 13 }, { 'm', 13 },
		{ 'F', 14 }, { 'f', 14 },
		{ 'P', 15 }, { 'p', 15 },
		{ 'S', 16 }, { 's', 16 },
		{ 'T', 17 }, { 't', 17 },
		{ 'W', 18 }, { 'w', 18 },
		{ 'Y', 19 }, { 'y', 19 },
		{ 'V', 20 }, { 'v', 20 },
		{ 'B', 21 }, { 'b', 21 },
		{ 'Z', 22 }, { 'z', 22 },
		{ 'X', 23 }, { 'x', 23 },
		{ '*', 24 }
	};

static BLAST_LetterPair	_oldblastaa_to_print_vec[] = {
		{  1, 'A' },
		{  2, 'R' },
		{  3, 'N' },
		{  4, 'D' },
		{  5, 'C' },
		{  6, 'Q' },
		{  7, 'E' },
		{  8, 'G' },
		{  9, 'H' },
		{ 10, 'I' },
		{ 11, 'L' },
		{ 12, 'K' },
		{ 13, 'M' },
		{ 14, 'F' },
		{ 15, 'P' },
		{ 16, 'S' },
		{ 17, 'T' },
		{ 18, 'W' },
		{ 19, 'Y' },
		{ 20, 'V' },
		{ 21, 'B' },
		{ 22, 'Z' },
		{ 23, 'X' },
		{ 24, '*' }
	};

static BLAST_LetterPair _iupacna_to_oldblastna_vec[] = {
		{ 'A',  0 },
		{ 'C',  1 },
		{ 'G',  2 },
		{ 'T',  3 },
		{ 'U',  3 },
		{ 'R',  4 },
		{ 'Y',  5 },
		{ 'M',  6 },
		{ 'K',  7 },
		{ 'W',  8 },
		{ 'S',  9 },
		{ 'B', 10 },
		{ 'D', 11 },
		{ 'H', 12 },
		{ 'V', 13 },
		{ 'N', 14 }
	};

static BLAST_LetterPair _print_to_oldblastna_vec[] = {
		{ 'A',  0 }, { 'a',  0 },
		{ 'C',  1 }, { 'c',  1 },
		{ 'G',  2 }, { 'g',  2 },
		{ 'T',  3 }, { 't',  3 },
		{ 'U',  3 }, { 'u',  3 },
		{ 'R',  4 }, { 'r',  4 },
		{ 'Y',  5 }, { 'y',  5 },
		{ 'M',  6 }, { 'm',  6 },
		{ 'K',  7 }, { 'k',  7 },
		{ 'W',  8 }, { 'w',  8 },
		{ 'S',  9 }, { 's',  9 },
		{ 'B', 10 }, { 'b', 10 },
		{ 'D', 11 }, { 'd', 11 },
		{ 'H', 12 }, { 'h', 12 },
		{ 'V', 13 }, { 'v', 13 },
		{ 'N', 14 }, { 'n', 14 },
		{ '-', 15 }
	};

static BLAST_LetterPair _oldblastna_to_print_vec[] = {
		{  0, 'A' },
		{  1, 'C' },
		{  2, 'G' },
		{  3, 'T' },
		{  4, 'R' },
		{  5, 'Y' },
		{  6, 'M' },
		{  7, 'K' },
		{  8, 'W' },
		{  9, 'S' },
		{ 10, 'B' },
		{ 11, 'D' },
		{ 12, 'H' },
		{ 13, 'V' },
		{ 14, 'N' },
		{ 15, '-' }
	};

static BLAST_LetterPair _print_to_ncbistdaa_vec[] = {
		{ '-' ,  0 },
		{ 'A' ,  1 }, { 'a',  1 },
		{ 'B' ,  2 }, { 'b',  2 },
		{ 'C' ,  3 }, { 'c',  3 },
		{ 'D' ,  4 }, { 'd',  4 },
		{ 'E' ,  5 }, { 'e',  5 },
		{ 'F' ,  6 }, { 'f',  6 },
		{ 'G' ,  7 }, { 'g',  7 },
		{ 'H' ,  8 }, { 'h',  8 },
		{ 'I' ,  9 }, { 'i',  9 },
		{ 'K' , 10 }, { 'k', 10 },
		{ 'L' , 11 }, { 'l', 11 },
		{ 'M' , 12 }, { 'm', 12 },
		{ 'N' , 13 }, { 'n', 13 },
		{ 'P' , 14 }, { 'p', 14 },
		{ 'Q' , 15 }, { 'q', 15 },
		{ 'R' , 16 }, { 'r', 16 },
		{ 'S' , 17 }, { 's', 17 },
		{ 'T' , 18 }, { 't', 18 },
		{ 'V' , 19 }, { 'v', 19 },
		{ 'W' , 20 }, { 'w', 20 },
		{ 'X' , 21 }, { 'x', 21 },
		{ 'Y' , 22 }, { 'y', 22 },
		{ 'Z' , 23 }, { 'z', 23 },
		{ 'U' , 24 }, { 'u', 24 },
		{ '*' , 25 }
	};

static BLAST_LetterPair	_ncbistdaa_to_print_vec[] = {
		{  0, '-' },
		{  1, 'A' },
		{  2, 'B' },
		{  3, 'C' },
		{  4, 'D' },
		{  5, 'E' },
		{  6, 'F' },
		{  7, 'G' },
		{  8, 'H' },
		{  9, 'I' },
		{ 10, 'K' },
		{ 11, 'L' },
		{ 12, 'M' },
		{ 13, 'N' },
		{ 14, 'P' },
		{ 15, 'Q' },
		{ 16, 'R' },
		{ 17, 'S' },
		{ 18, 'T' },
		{ 19, 'V' },
		{ 20, 'W' },
		{ 21, 'X' },
		{ 22, 'Y' },
		{ 23, 'Z' },
		{ 24, 'U' },
		{ 25, '*' }
	};
static BLAST_LetterPair	_ncbistdaa_to_iupacaa_vec[] = {
		{  0, 'X' },
		{  1, 'A' },
		{  2, 'B' },
		{  3, 'C' },
		{  4, 'D' },
		{  5, 'E' },
		{  6, 'F' },
		{  7, 'G' },
		{  8, 'H' },
		{  9, 'I' },
		{ 10, 'K' },
		{ 11, 'L' },
		{ 12, 'M' },
		{ 13, 'N' },
		{ 14, 'P' },
		{ 15, 'Q' },
		{ 16, 'R' },
		{ 17, 'S' },
		{ 18, 'T' },
		{ 19, 'V' },
		{ 20, 'W' },
		{ 21, 'X' },
		{ 22, 'Y' },
		{ 23, 'Z' },
		{ 24, 'X' },
		{ 25, 'X' }
	};

static BLAST_LetterPair	_iupacaa_to_ncbistdaa_vec[] = {
		{  'A' ,  1 },
		{  'B' ,  2 },
		{  'C' ,  3 },
		{  'D' ,  4 },
		{  'E' ,  5 },
		{  'F' ,  6 },
		{  'G' ,  7 },
		{  'H' ,  8 },
		{  'I' ,  9 },
		{  'K' , 10 },
		{  'L' , 11 },
		{  'M' , 12 },
		{  'N' , 13 },
		{  'P' , 14 },
		{  'Q' , 15 },
		{  'R' , 16 },
		{  'S' , 17 },
		{  'T' , 18 },
		{  'V' , 19 },
		{  'W' , 20 },
		{  'X' , 21 },
		{  'Y' , 22 },
		{  'Z' , 23 }
	};

static BLAST_LetterPair _iupacna_to_ncbi2na_vec[] = {
		{ 'A' , 0 } ,
		{ 'C' , 1 } ,
		{ 'G' , 2 } ,
		{ 'T' , 3 } ,
		{ 'U' , 3 }
	};

static BLAST_LetterPair _ncbi2na_to_iupacna_vec[] = {
		{  0, 'A' } ,
		{  1, 'C' } ,
		{  2, 'G' } ,
		{  3, 'T' }
	};

static BLAST_LetterPair	_ncbi2na_to_ncbi4na_vec[] = {
		{  0, 1 } ,
		{  1, 2 } ,
		{  2, 4 } ,
		{  3, 8 }
	};

static BLAST_LetterPair	_ncbi4na_to_ncbi2na_vec[] = {
		{  1, 0 } ,
		{  2, 1 } ,
		{  4, 2 } ,
		{  8, 3 }
	};

static BLAST_LetterPair _iupacna_to_ncbi4na_vec[] = {
		{ 'A',  1 },
		{ 'C',  2 },
		{ 'M',  3 },
		{ 'G',  4 },
		{ 'R',  5 },
		{ 'S',  6 },
		{ 'V',  7 },
		{ 'T',  8 },
		{ 'U',  8 },
		{ 'W',  9 },
		{ 'Y', 10 },
		{ 'H', 11 },
		{ 'K', 12 },
		{ 'D', 13 },
		{ 'B', 14 },
		{ 'N', 15 }
	};

static BLAST_LetterPair _ncbi4na_to_iupacna_vec[] = {
		{  1, 'A' },
		{  2, 'C' },
		{  3, 'M' },
		{  4, 'G' },
		{  5, 'R' },
		{  6, 'S' },
		{  7, 'V' },
		{  8, 'T' },
		{  9, 'W' },
		{ 10, 'Y' },
		{ 11, 'H' },
		{ 12, 'K' },
		{ 13, 'D' },
		{ 14, 'B' },
		{ 15, 'N' }
	};

static BLAST_LetterPair _print_to_ncbi4na_vec[] = {
		{ '-',  0 },
		{ 'A',  1 }, { 'a',  1 },
		{ 'C',  2 }, { 'c',  2 },
		{ 'M',  3 }, { 'm',  3 },
		{ 'G',  4 }, { 'g',  4 },
		{ 'R',  5 }, { 'r',  5 },
		{ 'S',  6 }, { 's',  6 },
		{ 'V',  7 }, { 'v',  7 },
		{ 'T',  8 }, { 't',  8 },
		{ 'U',  8 }, { 'u',  8 },
		{ 'W',  9 }, { 'w',  9 },
		{ 'Y', 10 }, { 'y', 10 },
		{ 'H', 11 }, { 'h', 11 },
		{ 'K', 12 }, { 'k', 12 },
		{ 'D', 13 }, { 'd', 13 },
		{ 'B', 14 }, { 'b', 14 },
		{ 'N', 15 }, { 'n', 15 }
	};

static BLAST_LetterPair _ncbi4na_to_print_vec[] = {
		{  0, '-' } ,
		{  1, 'A' } ,
		{  2, 'C' } ,
		{  3, 'M' } ,
		{  4, 'G' } ,
		{  5, 'R' } ,
		{  6, 'S' } ,
		{  7, 'V' } ,
		{  8, 'T' } ,
		{  9, 'W' } ,
		{ 10, 'Y' } ,
		{ 11, 'H' } ,
		{ 12, 'K' } ,
		{ 13, 'D' } ,
		{ 14, 'B' } ,
		{ 15, 'N' }
	};

static BLAST_LetterPair _ncbi2na_to_ncbi2na_vec[] = {
		{ 0, 3 } ,
		{ 1, 2 } ,
		{ 2, 1 } ,
		{ 3, 0 }
	};

static BLAST_LetterPair _ncbi4na_to_ncbi4na_vec[] = {
		{  0,  0 } ,
		{  1,  8 } ,
		{  2,  4 } ,
		{  3, 12 } ,
		{  4,  2 } ,
		{  5, 10 } ,
		{  6,  6 } ,
		{  7, 14 } ,
		{  8,  1 } ,
		{  9,  9 } ,
		{ 10,  5 } ,
		{ 11, 13 } ,
		{ 12,  3 } ,
		{ 13, 11 } ,
		{ 14,  7 } ,
		{ 15, 15 }
	};

static BLAST_LetterPair _oldblastna_to_oldblastna_vec[] = {
		{  0,  3 } ,
		{  1,  2 } ,
		{  2,  1 } ,
		{  3,  0 } ,
		{  4,  5 } ,
		{  5,  4 } ,
		{  6,  7 } ,
		{  7,  6 } ,
		{  8,  8 } ,
		{  9,  9 } ,
		{ 10, 13 } ,
		{ 11, 12 } ,
		{ 12, 11 } ,
		{ 13, 10 } ,
		{ 14, 14 } ,
		{ 15, 15 }
	};

static BLAST_LetterPair _iupacna_to_iupacna_vec[] = {
		{ 'T', 'A' } ,
		{ 'U', 'A' } ,
		{ 'G', 'C' } ,
		{ 'K', 'M' } ,
		{ 'C', 'G' } ,
		{ 'Y', 'R' } ,
		{ 'S', 'S' } ,
		{ 'B', 'V' } ,
		{ 'A', 'T' } ,
		{ 'W', 'W' } ,
		{ 'R', 'Y' } ,
		{ 'D', 'H' } ,
		{ 'M', 'K' } ,
		{ 'H', 'D' } ,
		{ 'V', 'B' } ,
		{ 'N', 'N' }
	};


static BLAST_AlphaMap _print_to_ncbistdaa = {
		NULL , NULL ,
		&_print , &_ncbistdaa ,
		DIM(_print_to_ncbistdaa_vec) ,
		_print_to_ncbistdaa_vec
	};

static BLAST_AlphaMap _ncbistdaa_to_print = {
		NULL , NULL ,
		&_ncbistdaa , &_print ,
		DIM(_ncbistdaa_to_print_vec) ,
		_ncbistdaa_to_print_vec
	};

static BLAST_AlphaMap _ncbistdaa_to_iupacaa = {
		NULL , NULL ,
		&_ncbistdaa , &_iupacaa ,
		DIM(_ncbistdaa_to_iupacaa_vec) ,
		_ncbistdaa_to_iupacaa_vec
	};

static BLAST_AlphaMap _iupacaa_to_ncbistdaa = {
		NULL , NULL ,
		&_iupacaa , &_ncbistdaa  ,
		DIM(_iupacaa_to_ncbistdaa_vec) ,
		_iupacaa_to_ncbistdaa_vec
	};

static BLAST_AlphaMap _ncbi2na_to_ncbi2na = {
		NULL , NULL ,
		&_ncbi2na , &_ncbi2na ,
		DIM(_ncbi2na_to_ncbi2na_vec) ,
		_ncbi2na_to_ncbi2na_vec
	};

static BLAST_AlphaMap _ncbi4na_to_ncbi4na = {
		NULL , NULL ,
		&_ncbi4na , &_ncbi4na ,
		DIM(_ncbi4na_to_ncbi4na_vec) ,
		_ncbi4na_to_ncbi4na_vec
	};

static BLAST_AlphaMap _oldblastna_to_oldblastna = {
		NULL , NULL ,
		&_oldblastna , &_oldblastna ,
		DIM(_oldblastna_to_oldblastna_vec) ,
		_oldblastna_to_oldblastna_vec
	};

static BLAST_AlphaMap _iupacna_to_iupacna = {
		NULL , NULL ,
		&_iupacna , &_iupacna ,
		DIM(_iupacna_to_iupacna_vec) ,
		_iupacna_to_iupacna_vec
	};

static BLAST_AlphaMap _iupacna_to_ncbi2na = {
		NULL , NULL ,
		&_iupacna , &_ncbi2na ,
		DIM(_iupacna_to_ncbi2na_vec) ,
		_iupacna_to_ncbi2na_vec
	};

static BLAST_AlphaMap _ncbi2na_to_ncbi4na = {
		NULL , NULL ,
		&_ncbi2na , &_ncbi4na ,
		DIM(_ncbi2na_to_ncbi4na_vec) ,
		_ncbi2na_to_ncbi4na_vec
	};

static BLAST_AlphaMap _ncbi4na_to_ncbi2na = {
		NULL , NULL ,
		&_ncbi4na , &_ncbi2na ,
		DIM(_ncbi4na_to_ncbi2na_vec) ,
		_ncbi4na_to_ncbi2na_vec
	};

static BLAST_AlphaMap _ncbi2na_to_iupacna = {
		NULL , NULL ,
		&_ncbi2na , &_iupacna ,
		DIM(_ncbi2na_to_iupacna_vec) ,
		_ncbi2na_to_iupacna_vec
	};

static BLAST_AlphaMap _print_to_ncbi2na = {
		NULL , NULL ,
		&_print , &_ncbi2na ,
		DIM(_iupacna_to_ncbi2na_vec) ,
		_iupacna_to_ncbi2na_vec
	};

static BLAST_AlphaMap _ncbi2na_to_print = {
		NULL , NULL ,
		&_ncbi2na , &_print ,
		DIM(_ncbi2na_to_iupacna_vec) ,
		_ncbi2na_to_iupacna_vec
	};

static BLAST_AlphaMap _iupacna_to_ncbi4na = {
		NULL , NULL ,
		&_iupacna , &_ncbi4na ,
		DIM(_iupacna_to_ncbi4na_vec) ,
		_iupacna_to_ncbi4na_vec
	};

static BLAST_AlphaMap _ncbi4na_to_iupacna = {
		NULL , NULL ,
		&_ncbi4na , &_iupacna ,
		DIM(_ncbi4na_to_iupacna_vec) ,
		_ncbi4na_to_iupacna_vec
	};

static BLAST_AlphaMap _print_to_ncbi4na = {
		NULL , NULL ,
		&_print , &_ncbi4na ,
		DIM(_print_to_ncbi4na_vec) ,
		_print_to_ncbi4na_vec
	};

static BLAST_AlphaMap _ncbi4na_to_print = {
		NULL , NULL ,
		&_ncbi4na , &_print ,
		DIM(_ncbi4na_to_print_vec) ,
		_ncbi4na_to_print_vec
	};

static BLAST_AlphaMap _iupacaa_to_oldblastaa = {
		NULL , NULL ,
		&_iupacaa , &_oldblastaa  ,
		DIM(_iupacaa_to_oldblastaa_vec) ,
		_iupacaa_to_oldblastaa_vec
	};

static BLAST_AlphaMap _print_to_oldblastaa = {
		NULL , NULL ,
		&_print , &_oldblastaa  ,
		DIM(_print_to_oldblastaa_vec) ,
		_print_to_oldblastaa_vec
	};

static BLAST_AlphaMap _oldblastaa_to_print = {
		NULL , NULL ,
		&_oldblastaa  , &_print ,
		DIM(_oldblastaa_to_print_vec) ,
		_oldblastaa_to_print_vec
	};

static BLAST_AlphaMap _iupacna_to_oldblastna = {
		NULL , NULL ,
		&_iupacna , &_oldblastna  ,
		DIM(_iupacna_to_oldblastna_vec) ,
		_iupacna_to_oldblastna_vec
	};

static BLAST_AlphaMap _print_to_oldblastna = {
		NULL , NULL ,
		&_print , &_oldblastna  ,
		DIM(_print_to_oldblastna_vec) ,
		_print_to_oldblastna_vec
	};

static BLAST_AlphaMap _oldblastna_to_print = {
		NULL , NULL ,
		&_oldblastna  , &_print ,
		DIM(_oldblastna_to_print_vec) ,
		_oldblastna_to_print_vec
	};

static BLAST_AlphaMapPtr	_alphamaplist[] = {
		&_print_to_ncbistdaa ,
		&_ncbistdaa_to_print ,
		&_ncbistdaa_to_iupacaa ,
		&_iupacaa_to_ncbistdaa ,
		&_iupacna_to_ncbi2na ,
		&_ncbi2na_to_iupacna ,
		&_print_to_ncbi2na ,
		&_ncbi2na_to_print ,
		&_ncbi2na_to_ncbi2na ,
		&_ncbi2na_to_ncbi4na ,
		&_ncbi4na_to_ncbi2na ,
		&_iupacna_to_ncbi4na ,
		&_ncbi4na_to_iupacna ,
		&_print_to_ncbi4na ,
		&_ncbi4na_to_print ,
		&_ncbi4na_to_ncbi4na ,
		&_iupacna_to_iupacna ,
		&_iupacaa_to_oldblastaa ,
		&_print_to_oldblastaa ,
		&_oldblastaa_to_print ,
		&_iupacna_to_oldblastna ,
		&_print_to_oldblastna ,
		&_oldblastna_to_print ,
		&_oldblastna_to_oldblastna
	};

static volatile BLAST_AlphaMapPtr	master_m;

/* _blast_alphabet_init -- top-level init function, 2b called only by InitBLAST() */
BLAST_Error
_blast_alphabet_init()
{
	int		i;

	for (i=0; i < DIM(_alphalist); ++i) {
		if (BlastAlphabetRegister(_alphalist[i]) != BLAST_ERR_NONE)
			return blast_errno;
	}
	for (i=0; i < DIM(_alphamaplist); ++i) {
		if (BlastAlphaMapRegister(_alphamaplist[i]) != BLAST_ERR_NONE)
			return blast_errno;
	}
	return BLAST_ERR_NONE;
}

Nlm_Boolean
BlastAlphabetTst(BLAST_AlphabetPtr ap, BLAST_Letter ch)
{
	if (ch >= ap->letter_min && ch <= ap->letter_max)
		return ap->membertst[ch];
	return FALSE;
}

static int
alpha_letter_cmp(a1p, a2p)
	BLAST_LetterPtr	a1p, a2p;
{
	if (*a1p < *a2p)
		return -1;
	if (*a1p > *a2p)
		return 1;
	return 0;
}


/* BlastAlphabetInit -- initialize a partially instantiated alphabet */
BLAST_Error
BlastAlphabetInit(ap)
	BLAST_AlphabetPtr	ap;
{
	int		i, bits;
	BLAST_Letter	ch;
	size_t	range;

	if (ap->initialized)
		return BLAST_ERR_NONE;

	/* Determine the number of letters in the alphabet */
	if (ap->alphasize == 0 || ap->alist == NULL)
		ap->alphasize = ap->letter_max - ap->letter_min + 1;
	if (ap->alphasize > BLAST_ALPHASIZE_MAX || ap->alphasize <= 1)
		return blast_errno = BLAST_ERR_ALPHASIZE;

	if (ap->alist != NULL) {
		/* sort letters smallest to largest */
		qsort((Nlm_VoidPtr)ap->alist, ap->alphasize, sizeof(BLAST_Letter),
				(int (*)())alpha_letter_cmp);
		/* Find the smallest and largest letter values in the alphabet */
		ap->letter_min = ap->alist[0];
		ap->letter_max = ap->alist[ap->alphasize - 1];
	}
	else {
		ap->alist = (BLAST_LetterPtr) BlastMalloc(ap->alphasize * sizeof(BLAST_Letter));
		if (ap->alist == NULL)
			return blast_errno;
		for (i = 0; i < ap->alphasize; ++i)
			ap->alist[i] = ap->letter_min + i;
	}
	if (ap->letter_max > BLAST_LETTER_MAX)
		return blast_errno = BLAST_ERR_LETTER;

	/*
	Make array for performing fast membership tests of arbitrary letters
	*/
	range = ap->letter_max - ap->letter_min + 1;
	ap->_membertst0 = (Nlm_Boolean PNTR) BlastCalloc(range);
	if (ap->_membertst0 == NULL)
		return blast_errno;

	ap->membertst = ap->_membertst0 - ap->letter_min;
	for (i=0; i<ap->alphasize; ++i)
		ap->membertst[ap->alist[i]] = TRUE;

	/* Identify or pick an appropriate sentinel value */
	if (ap->alphasize >= BLAST_ALPHASIZE_MAX) {
		/* all possible letter values are in use...assign a default sentinel */
		ap->hard_sentinel = FALSE;
		ap->sentinel = BLAST_SOFT_SENTINEL;
		ap->minval = ap->letter_min;
		ap->maxval = ap->letter_max;
	}
	else {
		ap->hard_sentinel = TRUE;
		ap->minval = ap->letter_min;
		ap->maxval = ap->letter_max;
		/* Is the alphabet discontinuous? */
		if (ap->letter_max - ap->letter_min + 1 < ap->alphasize) {
			/* Find a hole in the alphabet to be used as the sentinel value */
			for (ch = ap->letter_min; ch <= ap->letter_max; ++ch)
				if (ap->membertst[ch] == FALSE) {
					ap->sentinel = ch;
					break;
				}
		}
		else
			if (ap->letter_min > BLAST_LETTER_MIN)
				ap->sentinel = --ap->minval;
			else
				ap->sentinel = ++ap->maxval;
	}

	/* Determine the minimum no. of bits necessary to represent the alphabet */
	for (bits = 1; bits <= sizeof(BLAST_Letter)*CHAR_BIT; ++bits)
		if ((1 << bits) > (int)ap->letter_max)
			break;
	ap->bpl = bits;

	/* Set initialized flag here to block recursion */
	ap->initialized = TRUE;

	{
		BLAST_AlphaMapPtr	amp;
		BLAST_AlphabetPtr	asciip;

		asciip = BlastAlphabetFindByID(BLAST_ALPHA_PRINT);
		if (asciip != NULL) {
			amp = BlastAlphaMapFind(asciip, ap);
			if (amp != NULL)
				ap->inmap = amp;
			amp = BlastAlphaMapFind(ap, asciip);
			if (amp != NULL)
				ap->outmap = amp;
		}
	}

	return BLAST_ERR_NONE;
}

/* BlastAlphabetIsRegistered -- return TRUE if alphabet is registered */
Nlm_Boolean
BlastAlphabetIsRegistered(ap)
	BLAST_AlphabetPtr	ap;
{
	BLAST_AlphabetPtr	p;

	for (p = master_a; p != NULL; p = p->next)
		if (p == ap)
			return TRUE;
	return FALSE;
}

/* BlastAlphabetRegister -- register an alphabet in the master_a list */
BLAST_Error
BlastAlphabetRegister(ap)
	BLAST_AlphabetPtr	ap;
{
	mproc_lock();

	if (BlastAlphabetIsRegistered(ap)) {
		mproc_unlock();
		return BLAST_ERR_NONE;
	}

	if (master_a != NULL)
		master_a->previous = ap;
	ap->previous = NULL;
	ap->next = master_a;
	master_a = ap;

	mproc_unlock();
	return BLAST_ERR_NONE;
}

/* BlastAlphabetUnregister -- remove an alphabet from the master_a list */
BLAST_Error
BlastAlphabetUnregister(ap)
	BLAST_AlphabetPtr	ap;
{
	mproc_lock();

	if (BlastAlphabetIsRegistered(ap) == FALSE) {
		mproc_unlock();
		return BLAST_ERR_NONE;
	}

	if (ap->previous != NULL)
		ap->previous->next = ap->next;
	if (ap->next != NULL)
		ap->next->previous = ap->previous;
	if (master_a == ap)
		master_a = ap->next;
	ap->previous = ap->next = NULL;

	mproc_unlock();
	return BLAST_ERR_NONE;
}

BLAST_Error
BlastAlphaMapInit(amp)
	BLAST_AlphaMapPtr	amp;
{
	BLAST_AlphabetPtr	from, to;
	BLAST_LetterPairPtr	pair;
	size_t	u, range;

	from = amp->from;
	to = amp->to;
	if (BlastAlphabetInit(from) != BLAST_ERR_NONE)
		return blast_errno;
	if (BlastAlphabetInit(to) != BLAST_ERR_NONE)
		return blast_errno;

	range = from->letter_max - from->letter_min + 1;
	amp->_map0 = (BLAST_LetterPtr) BlastMalloc(range*sizeof(BLAST_Letter));
	if (amp->_map0 == NULL)
		return blast_errno;
	amp->map =  amp->_map0 - from->letter_min;

	amp->_maptst0 = (Nlm_Boolean PNTR) BlastCalloc(range*sizeof(Nlm_Boolean));
	if (amp->_maptst0 == NULL) {
		BlastFree(amp->_map0);
		Nlm_MemSet((CharPtr)amp, 0, sizeof(*amp));
		return blast_errno;
	}
	amp->maptst =  amp->_maptst0 - from->letter_min;

	pair = amp->pair;
	for (u = 0; u < amp->npairs; ++u) {
		if (!BlastAlphabetTst(from, pair[u].from))
			goto ErrExit;
		if (!BlastAlphabetTst(to, pair[u].to))
			goto ErrExit;
		amp->map[pair[u].from] = pair[u].to;
		amp->maptst[pair[u].from] = TRUE;
	}

	amp->initialized = TRUE;
	return BLAST_ERR_NONE;

ErrExit:
	if (amp->_map0 != NULL)
		BlastFree(amp->_map0);
	if (amp->_maptst0 != NULL)
		BlastFree(amp->_maptst0);
	Nlm_MemSet((CharPtr)amp, 0, sizeof(*amp));
	return blast_errno = BLAST_ERR_ALPHAVAL;
}

BLAST_Letter
BlastAlphaMapChr(BLAST_AlphaMapPtr amp, BLAST_Letter ch1)
{
	return amp->map[ch1];
}

Nlm_Boolean
BlastAlphaMapTst(BLAST_AlphaMapPtr amp, BLAST_Letter ch1)
{
	return amp->maptst[ch1];
}

Nlm_Boolean
BlastAlphaMapIsRegistered(amp)
	BLAST_AlphaMapPtr	amp;
{
	BLAST_AlphaMapPtr	p;

	for (p = master_m; p != NULL; p = p->next) {
		if (p == amp)
			return TRUE;
	}
	return FALSE;
}

BLAST_Error
BlastAlphaMapRegister(amp)
	BLAST_AlphaMapPtr	amp;
{
	mproc_lock();
	if (BlastAlphaMapIsRegistered(amp)) {
		mproc_unlock();
		return BLAST_ERR_NONE;
	}

	if (master_m != NULL)
		master_m->previous = amp;
	amp->previous = NULL;
	amp->next = master_m;
	master_m = amp;

	mproc_unlock();
	return BLAST_ERR_NONE;
}

BLAST_Error
BlastAlphaMapUnregister(amp)
	BLAST_AlphaMapPtr	amp;
{
	mproc_lock();
	if (BlastAlphaMapIsRegistered(amp) == FALSE) {
		mproc_unlock();
		return BLAST_ERR_NONE;
	}

	if (amp->previous != NULL)
		amp->previous->next = amp->next;
	if (amp->next != NULL)
		amp->next->previous = amp->previous;
	if (master_m == amp)
		master_m = amp->next;
	amp->previous = amp->next = NULL;

	mproc_unlock();
	return BLAST_ERR_NONE;
}

/* BlastAlphabetFindByName -- find an alphabet by visible string name */
BLAST_AlphabetPtr
BlastAlphabetFindByName(name)
	CharPtr	name;
{
	BLAST_AlphabetPtr	p;

	for (p = master_a; p != NULL; p = p->next)
		if (Nlm_StrICmp(p->name, name) == 0) {
			if (p->initialized || BlastAlphabetInit(p) == BLAST_ERR_NONE)
				return p;
			return NULL;
		}
	blast_errno = BLAST_ERR_NF;
	return NULL;
}

BLAST_AlphabetPtr
BlastAlphabetFindByID(id)
	BLAST_AlphaID	id;
{
	BLAST_AlphabetPtr	p;

	for (p = master_a; p != NULL; p = p->next)
		if (p->id == id) {
			if (p->initialized || BlastAlphabetInit(p) == BLAST_ERR_NONE)
				return p;
			return NULL;
		}
	blast_errno = BLAST_ERR_NF;
	return NULL;
}

BLAST_AlphaMapPtr
BlastAlphaMapFind(from, to)
	BLAST_AlphabetPtr	from, to;
{
	BLAST_AlphaMapPtr	p;

	for (p = master_m; p != NULL; p = p->next) {
		if (p->from == from && p->to == to) {
			if (p->initialized || BlastAlphaMapInit(p) == BLAST_ERR_NONE)
				return p;
			return NULL;
		}
	}
	blast_errno = BLAST_ERR_NF;
	return NULL;
}

BLAST_AlphaMapPtr
BlastAlphaMapFindCreate(from, to)
	BLAST_AlphabetPtr	from, to;
{
	BLAST_AlphaMapPtr	amp, famp, tamp;
	BLAST_AlphabetPtr	printap;
	BLAST_LetterPairPtr	lpp, relpp;
	register BLAST_Letter	fc, xfc, tc;
	register int	i, npairs;

	if (from == NULL || to == NULL) {
		blast_errno = BLAST_ERR_INVAL;
		return NULL;
	}
	amp = BlastAlphaMapFind(from, to);
	if (amp != NULL)
		return amp;

	printap = BlastAlphabetFindByID(BLAST_ALPHA_PRINT);
	if (printap == NULL)
		return NULL;
	if (printap == from || printap == to) {
		blast_errno = BLAST_ERR_INVAL;
		return NULL;
	}

	famp = BlastAlphaMapFind(from, printap);
	tamp = BlastAlphaMapFind(printap, to);
	if (famp == NULL || tamp == NULL)
		return NULL;

	amp = (BLAST_AlphaMapPtr) BlastCalloc(sizeof(*amp));
	if (amp == NULL)
		return NULL;

	lpp = (BLAST_LetterPairPtr) BlastMalloc(sizeof(*lpp) * from->alphasize);
	if (lpp == NULL) {
		BlastFree(amp);
		return NULL;
	}

	amp->from = from;
	amp->to = to;

	for (i = npairs = 0; i < from->alphasize; ++i) {
		if (BlastAlphaMapTst(famp, fc = from->alist[i]) == FALSE)
			continue;
		xfc = BlastAlphaMapChr(famp, fc);
		if (BlastAlphaMapTst(tamp, xfc) == FALSE)
			continue;
		tc = BlastAlphaMapChr(tamp, xfc);
		lpp[npairs].from = fc;
		lpp[npairs].to = tc;
		++npairs;
	}

	if (npairs < from->alphasize) {
		relpp = (BLAST_LetterPairPtr) BlastRealloc(lpp, sizeof(*lpp) * npairs);
		if (relpp == NULL) {
			BlastFree(amp);
			return NULL;
		}
		lpp = relpp;
	}

	amp->npairs = npairs;
	amp->pair = lpp;

	if (BlastAlphaMapInit(amp) != BLAST_ERR_NONE) {
		BlastFree(lpp);
		BlastFree(amp);
		return NULL;
	}

	BlastAlphaMapRegister(amp);
	amp = BlastAlphaMapFind(from, to);

	return amp;
}
