#!/usr/bin/perl
# evigene/scripts/fagffmask.pl

use strict;
use warnings;
use Getopt::Long ;

my($nmask, $nbases)=(0,0);
my($mhard, $margin, $fasta, $gff, $oname, $skiptypes, $debug) = (0) x 9;

my $optok= &GetOptions (
  "gff=s"=>\$gff,  
  "fasta=s"=>\$fasta,
  "output=s"=>\$oname,
  "masktypes=s"=>\$skiptypes,
  "margin=s"=>\$margin,
  "hardmask!"=>\$mhard,
  "debug!"=>\$debug, 
  );

$fasta= shift @ARGV unless($fasta);
$gff  = shift @ARGV unless($gff);
die "USAGE: $0 -fasta my.fasta[.gz] -gff stdin|my.gff[.gz] > my.fasta.masked\n"
  unless($optok and $fasta and $gff);

my ($ok,$gfh);
if($gff =~ /\.gz/){ $ok= open(GF,"gunzip -c $gff |"); $gfh=*GF; }
elsif($gff =~ /stdin|-/){ $ok= 1; $gfh=*STDIN; }
else { $ok= open(GF,$gff); $gfh=*GF; }
die $gff unless $ok;

my (%maskat);
while(<$gfh>){
  next if(/^\W/);
  my @gff=split"\t"; 
  my($chr,$gsrc,$gty,$cb,$ce,$cv,$co)=@gff;
  my $gtype="$gsrc,$gty";
  my $mok= (not $skiptypes)? 1 : ($gtype =~ m/\t($skiptypes)\t/) ? 1 : 0;
  if($mok) { if(my $oce= $maskat{$chr}{$cb}){ $ce=$oce if($oce>$ce); } $maskat{$chr}{$cb}=$ce; }
}

if($fasta =~ /\.gz/){ $ok= open(FA,"gunzip -c $fasta |"); }
else { $ok= open(FA,$fasta); }
die $fasta unless $ok;

unless($oname){ $oname=$fasta; $oname=~s/.gz//; $oname.=".masked"; }
rename($oname,"$oname.old") if(-s $oname);
open(OFA,">$oname");
my($id,$fa,$hdr)= ("") x 3;

sub putmfa{ my($id,$hdr,$fa)=@_; 
  $fa=uc($fa); my $imask=0;
  if(exists $maskat{$id}){ 
    my @cb= sort { $a <=> $b } keys %{$maskat{$id}}; 
    for my $cb (@cb){ 
     my $ce=$maskat{$id}{$cb}; my $cw=1 + $ce - $cb; next if($cw < 1);

     if($margin > 0 and $cw > 99) {
       my $m=$margin;
       if($margin > 0.80 * $cw){ $m=10; }
       elsif($margin > 0.30 * $cw) { $m= int($cw * 0.10); }
       $cb += $margin; $ce -= $margin; $cw=1 + $ce - $cb; 
     }
     
     my $fs= substr($fa,$cb-1,$cw); next unless(length($fs) == $cw);
     if($mhard){ $fs= ("n") x $cw; } else { $fs=lc($fs); } 
     substr($fa,$cb-1,$cw)= $fs;  #no,overlaps: $nmask+=$cw; $imask+=$cw;
   }
   ($imask)= ($mhard) ? $fa =~ tr/n/n/ : $fa =~ tr/acgt/acgt/;
   $hdr=~s/$/; nmask=$imask;/; $nmask += $imask;
  }
  $nbases += length($fa); 
  $fa=~s/(.{100})/$1\n/g; chomp($fa);
  print OFA "$hdr\n$fa\n";
}

while(<FA>){ chomp; 
  if(/^>(\S+)/) { my $d=$1; putmfa($id,$hdr,$fa) if($id and $fa); $id=$d; $hdr=$_; $fa=""; } else { $fa.=$_; } 
}
putmfa($id,$hdr,$fa) if($id and $fa);
close(FA); close(OFA);
warn "# masked n=$nmask/$nbases to $oname\n"; 

