/*        blk2mot.c
   Reads a file of sequences (fasta format) & a file of blocks made
   from those sequences, and makes a .mot file readable by motomat:

      blk2mot <seq_file> <blk_file> <mot_file>
		<seq_file> is just used to count #of sequences

   Use to make a .mot file from Gibbs blocks, etc.
------------------------------------------------------------------------
10/20/95  J. Henikoff
11/14/95  Get MOTIFJ=[] info. off the Title line if there is one in <blk_file>
          There is no Title line in <blk_file> if it came from Gibbs
11/15/95  Treat hybrid as if from motif.
 1/ 3/96  Fix bug with significance level (could be > # seqs!)
 6/20/99  Sequence names can be 18 long instead of 10.
12/23/06  Sequence names can be 20 long instead of 18.
========================================================================*/

#define BLK2MOT_C_
#define EXTERN
#define MAXNAME 80	/* Maximum file name length */
#define MAXWIDTH 60     /* Max block width */

/*  Motomat significance level from Blocks 6.2: x = #sequences   */
#define signif(x) (int) ((double) 0.5 * x + 3.09)

#include <blocksprogs.h>

struct motif_info {
   int Version, RunType, Signif, Dups, Distance, NumSeqs, Total_Motifs, Gibbs;
   int Motif;
   char Title[MAXLINE];
};

int getseqs();
void getblks();
void parse_BL();
void write_motifs();

/*-------------Global variables------------------------------------------*/
int Len[MAXSEQS];		/*  sequence lengths */
char *Seq[MAXSEQS];		/* sequences */
char Seqname[MAXSEQS][SNAMELEN];

/*=======================================================================*/
void main(argc, argv)
     int argc;
     char *argv[];
{
   FILE *fmot, *fblk, *fseq;
   Block *block;
   struct motif_struct *motif;
   struct motif_info *info;
   char *ptr, seqfile[FNAMELEN], blkfile[FNAMELEN],  motfile[FNAMELEN];
   char line[MAXLINE];

   if (argc <= 3)
   {
      printf("BLK2MOT: Copyright 1995 by Fred Hutchinson Cancer");
      printf(" Research Center\n");
      printf("USAGE:  blk2mot <pros_file> <blk_file> <mot_file>\n");
      printf("        <pros_file> = input file of protein sequences\n");
      printf("        <blk_file> = input file of blocks from sequences\n");
      printf("        <mot_file> = output file for motomat\n");
   }
   info = (struct motif_info *) malloc(sizeof(struct motif_info));
   info->Version = VERSION;
/*----------------1st arg = sequence file --------------------------*/
   if (argc > 1)
      strcpy(seqfile, argv[1]);
   else
   {
      printf("\nEnter name of file containing sequences: ");
      gets(seqfile);
   }
   if ( (fseq=fopen(seqfile, "r")) == NULL)
   {
      printf("\nCannot open file %s\n", seqfile);
      exit(-1);
   }
   info->NumSeqs = getseqs(fseq);
   fclose(fseq);
   if (info->NumSeqs < 1 )
   {
      printf("\nNo sequences found in file %s\n", seqfile);
      exit(-1);
   }

/* ------------2nd arg = blocks database ---------------------*/
   if (argc > 2)
      strcpy(blkfile, argv[2]);
   else
   {
      printf("\nEnter name of blocks file: ");
      gets(blkfile);
   }
   if ( (fblk=fopen(blkfile, "r")) == NULL)
   {
      printf("\nCannot open file %s\n", blkfile);
      exit(-1);
   }
   /*  Quickly figure out how many blocks are in it & allocate space */
   /*  Pick up any title, too  */
   info->Total_Motifs = 0; info->Title[0] = '\0';
   while (!feof(fblk) && fgets(line, MAXLINE, fblk) != NULL)
   {
      if (line[0] == '>') strcpy(info->Title, line);
      if (strncmp(line, "BL   ", 5) == 0) info->Total_Motifs++;
   }
   rewind(fblk);
/*   info->Title[100] = '\0';
*/
   if (info->Total_Motifs < 1)
   {
      printf("\nNo blocks found in file %s\n", blkfile);
      exit(-1);
   }
   motif = (struct motif_struct *)
     malloc(info->Total_Motifs * sizeof(struct motif_struct));
   getblks(fblk, info, motif);
   fclose(fblk);

/* ------------3rd arg = new .mot file ---------------------*/
   if (argc > 3)
      strcpy(motfile, argv[3]);
   else
   {
      printf("\nEnter name of new motomat file: ");
      gets(motfile);
   }
   if ( (fmot=fopen(motfile, "wb")) == NULL)
   {
      printf("\nCannot open file %s\n", motfile);
      exit(-1);
   }
   write_motifs(fmot, info, motif);
   fclose(fmot);
   exit(0);
}   /* end of main */

/*======================================================================
       Read all sequences in file, fasta format assumed
	Updates global variables NumSeqs, Seqname[], Seq[], Len[]
========================================================================*/
int getseqs(fp)
FILE *fp;
{
   int ns, itemp, i, j;
   char line[MAXLINE], *ptr;

   ns = -1;
   
   while(!feof(fp) && fgets(line, MAXLINE, fp) != NULL)
   {
	if (line[0] == '>')
	{
	   ns++;
	   ptr = strtok(line+1, " \t\r\n");
	   if ((int) strlen(ptr) > SNAMELEN - 1) ptr[SNAMELEN - 1] = '\0';
	   strcpy(Seqname[ns], ptr);
	   Seq[ns] = (char *) malloc(MAX_LENGTH * sizeof(char));
	   if (Seq[ns] == NULL)
	   {
		printf("Couldn't allocate Seq[%d]\n", ns);
		exit(-1);
	   }
	   Len[ns] = j = 0; Seq[ns][0] = '\0';
        }
        else if (Seq[ns] != NULL && Len[ns] < MAX_LENGTH + (int) strlen(line) )
        {
	   for (i=0; i < (int) strlen(line); i++)
           {
              if (isalpha(line[i]))   /*  assuming all is okay here !! */
              {
  	  	   Seq[ns][j++] = line[i];
		   Len[ns] += 1;
              }
           }
           Seq[ns][j] = '\0';
	}
   }

   return(ns + 1);
}  /*  end of getseqs */
/*========================================================================
             Read the blocks & make motifs
==========================================================================*/
void getblks(fblk, info, motif)
FILE *fblk;
struct motif_info *info;
struct motif_struct *motif;
{
   Block *block;
   int nmot, sb, ss, i;
   char *ptr, *bltemp, ctemp[MAXLINE];

   /*---Take Signif, Dups & Distance parameters off the Title, or
        off first block that has them, or else
        use defaults after all the blocks are read in ---------*/
   info->Signif = info->Dups = info->Distance = -1;
   info->RunType = 3;
   info->Gibbs = info->Motif = NO;
   bltemp = strstr(info->Title, "MOTIFJ=[");
   if (bltemp != NULL)
   {
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "[");
      ptr = strtok(NULL, ",");
      info->RunType = atoi(ptr);
      ptr = strtok(NULL, ",");
      info->Signif = atoi(ptr);
      ptr = strtok(NULL, ",");
      info->Dups = atoi(ptr);
      ptr = strtok(NULL, "]");
      info->Distance = atoi(ptr);
   }
   nmot = 0;
   while ((block = read_a_block(fblk)) != NULL &&
           nmot < info->Total_Motifs)
   {
      motif[nmot].domain = block->width;  		/* width= */
      motif[nmot].freq = block->num_sequences;		/* seqs= */
      parse_BL(block, info, &motif[nmot]);
      for (sb=0; sb < block->num_sequences; sb++)
      {
         /*      Match names to determine sequence number    */
         ss = 0;
	 while (ss < info->NumSeqs && 
            strcmp(Seqname[ss], block->sequences[sb].name) != 0)
                ss++;
         motif[nmot].seq_no[sb] = ss;
         motif[nmot].pos[sb] = block->sequences[sb].position;
      }
      nmot++;
      free_block(block);
   }
   /*-------Use defaults if didn't find any of this stuff on the blocks */
   if (info->Signif < 0 || (info->Gibbs && !info->Motif))
       info->Signif = signif(info->NumSeqs);
   if (info->Signif > info->NumSeqs) info->Signif = info->NumSeqs;
   if (info->Dups < 0) info->Dups = 0;
   if (info->Distance < 0 || (info->Gibbs && !info->Motif)) info->Distance = 0;

}   /* end of getmots */
/*========================================================================
       Get info. off the BL line:
	Some is there for most blocks (width=, seqs=) &
	some is only added by mot2blk (dups=, score=, etc.)
BL   *** gibbs=[7,0,0] width=5 seqs=9 dups=0 freq=9 mots=1 score=0 d1=0 d2=4
BL   LNC motif=[47,0,17] width=14 seqs=92 dups=0 freq=74 mots=2 score=1062 d1=12 d2=1
==========================================================================*/
void parse_BL(block, info, motif)
Block *block;
struct motif_info *info;
struct motif_struct *motif;
{
   char *ptr, *bltemp, ctemp[MAXLINE];

   /*  protomat aa numbers are one less than blimps numbers */
   /*   block->motif is empty for Gibbs blocks */
   if (strlen(block->motif) == 3)
   {
      motif->aa1 = (unsigned char) aa_atob[ block->motif[0] ] - 1;
      if (motif->aa1 > 20) motif->aa1 = 20;
      motif->aa2 = (unsigned char) aa_atob[ block->motif[1] ] - 1;
      if (motif->aa2 > 20) motif->aa2 = 20;
      motif->aa3 = (unsigned char) aa_atob[ block->motif[2] ] - 1;
      if (motif->aa3 > 20) motif->aa3 = 20;
   }
   else motif->aa1 = motif->aa2 = motif->aa3 = (unsigned char) 20;

   bltemp = strstr(block->bl, "motif=[");
   if (bltemp != NULL)
   {
      info->Motif = YES;
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "[");
      ptr = strtok(NULL, ",");
      info->Signif = atoi(ptr);
      ptr = strtok(NULL, ",");
      info->Dups = atoi(ptr);
      ptr = strtok(NULL, "]");
      info->Distance = atoi(ptr);
   }

   bltemp = strstr(block->bl, "gibbs");
   if (bltemp != NULL)
   {
      info->Gibbs = YES; 
      if (!info->Motif) info->RunType = 8;	/* tell motomat it's Gibbs */
   }

   bltemp = strstr(block->bl, "freq=");
   if (bltemp != NULL)
   {
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "="); ptr = strtok(NULL, " \t\r\n");
      motif->freq = atoi(ptr);
   }
   else motif->freq = 0;

   bltemp = strstr(block->bl, "dups=");
   if (bltemp != NULL)
   {
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "="); ptr = strtok(NULL, " \t\r\n");
      motif->dups = atoi(ptr);
   }
   else motif->dups = 0;

   bltemp = strstr(block->bl, "mots=");
   if (bltemp != NULL)
   {
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "="); ptr = strtok(NULL, " \t\r\n");
      motif->mots = atoi(ptr);
   }
   else motif->mots = 1;

   bltemp = strstr(block->bl, "score=");
   if (bltemp != NULL)
   {
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "="); ptr = strtok(NULL, " \t\r\n");
      motif->score = atoi(ptr);
   }
   else motif->score = 0;

   bltemp = strstr(block->bl, "d1=");
   if (bltemp != NULL)
   {
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "="); ptr = strtok(NULL, " \t\r\n");
      motif->distance1 = atoi(ptr);
   }
   else motif->distance1 = 0;

   bltemp = strstr(block->bl, "d2=");
   if (bltemp != NULL)
   {
      strcpy(ctemp, bltemp);
      ptr = strtok(ctemp, "="); ptr = strtok(NULL, " \t\r\n");
      motif->distance2 = atoi(ptr);
   }
   else motif->distance2 = motif->domain - 1;

}  /*  end of parse_BL  */
/*========================================================================
       Write an output file for motomat
==========================================================================*/
void write_motifs(mot, info, motif)
FILE *mot;
struct motif_info *info;
struct motif_struct *motif;
{
  int i, j;

  fwrite(&info->Version, sizeof(int), 1, mot);
  fwrite(&info->RunType, sizeof(int), 1, mot);
  fwrite(&info->Signif, sizeof(int), 1, mot);
  fwrite(&info->Dups, sizeof(int), 1, mot);
  fwrite(&info->Distance, sizeof(int), 1, mot);
  fwrite(&info->NumSeqs, sizeof(int), 1, mot);
  fwrite(&info->Total_Motifs, sizeof(int), 1, mot);
  fwrite(Len, sizeof(int), info->NumSeqs, mot);
  fwrite(Seqname, SNAMELEN*sizeof(char), info->NumSeqs, mot);
  for (i=0; i<info->NumSeqs; i++)
     for (j=0; j<Len[i]; j++)
     {
	fwrite(&Seq[i][j], sizeof(char), 1, mot);
     }
  fwrite(motif, sizeof(struct motif_struct), info->Total_Motifs, mot);
  fwrite(&info->Title, strlen(info->Title)*sizeof(char), 1, mot);

}   /* end of write_motifs  */
