#!/usr/bin/perl
#
use Statistics::OLS;
use Math::FFT;
use Math::Stat;
use Math::Spline qw(spline linsearch binsearch);
use Math::Derivative qw(Derivative2);
use Math::Approx;
use Astro::FITS::CFITSIO qw( :longnames :constants );
use PDL;
use PDL::Fit::Polynomial; 
use PDL::Filter::Linear;
use PGPLOT;  # Load PGPLOT module
use PDL::Fit::Gaussian;
use PDL::Slatec;
use PDL::Image2D;
#use PDL::Matrix;
#$F3D=$ENV{HIIEXPLORER_PATH};  $F3D=$ENV{HIIEXPLORER_PATH};  require("$F3D/my.pl"); #("$F3D/scripts/my.pl"); # "/work1/ssa/perl/MY/my.pl";

$F3D=$ENV{HIIEXPLORER_PATH}; $F3D=$ENV{HIIEXPLORER_PATH};  $F3D=$ENV{HIIEXPLORER_PATH};  require("$F3D/my.pl"); #("$F3D/scripts/my.pl"); #("$F3D/my.pl");

#$F3D=$ENV{HIIEXPLORER_PATH};  $F3D=$ENV{HIIEXPLORER_PATH};  require("$F3D/my.pl"); #("$F3D/scripts/my.pl"); # "/home/sanchez/sda2/code/R3D/my.pl";


if ($#ARGV<6) {
    print "USE: reg_spec.pl Ha_map.fits FLUX_LIMIT_PEAK MAX_DIST_PEAK FRAC_PEAK MIN_FLUX SEGFILE.fits DIFFUSE_MASK.fits\n";
    exit;
}

$Ha_file=$ARGV[0];
$F_max=$ARGV[1];
$max_dist=$ARGV[2];
$frac=$ARGV[3];
$MIN_FLUX=$ARGV[4];
$segfile=$ARGV[5];
$maskfile=$ARGV[6];

$Ha_map=rfits($Ha_file);
($nx,$ny)=$Ha_map->dims;
$seg_map=zeroes($nx,$ny);
$mask_map=ones($nx,$ny);

$map_now=$Ha_map;
$stop=0;
$NR=1;
while ($stop==0) {
    $k=0;
    $lower_lim=$F_max;
    $upper_lim=1e30;
    $ip=-1;
    $jp=-1;
    for ($i=0;$i<$nx;$i++) {
	for ($j=0;$j<$ny;$j++) {
	    $val=$map_now->at($i,$j);
	    my $is_max=is_max($i,$j);
	    my $is_near=is_near($i,$j);
	    if (($val<$upper_lim)&&($val>$lower_lim)&&($is_max==1)&&($is_near==0)) {
#	    if (($val<$upper_lim)&&($val>$lower_lim)&&($is_near==0)) {
		$lower_lim=$val;
		$ip=$i;
		$jp=$j;
	    }
	}
    }
    $JP[$NR]=$jp;
    $IP[$NR]=$ip;
    $F_PEAK[$NR]=$Ha_map->at($ip,$jp);
    print "ip,jp $ip,$jp $NR\n";
    if (($ip==-1)&&($jp==-1)) {
	$stop=1;
    } else {
	LOOP($ip,$jp);
#,$max_dist,$NR);
	$map_now=$map_now*$mask_map;

#	for ($i=0;$i<$nx;$i++) {
#	    for ($j=0;$j<$ny;$j++) {
#		my $val=$seg_map->at($i,$j);
#		if ($val!=0) {
#		    mask_around($i,$j);
#		}
#	    }
#	}


#	$seg_map->wfits($segfile);
#$mask_map->wfits("mask_seg.fits");
#
#	print "Press Enter"; <stdin>;
	$NR++;
    }
}

for ($i=0;$i<$nx;$i++) {
    for ($j=0;$j<$ny;$j++) {
	my $val=$Ha_map->at($i,$j);
	if ($val>=$MIN_FLUX) {
	    set($mask_map,$i,$j,0);
	}
    }
}

$seg_map->wfits($segfile);
$mask_map->wfits($maskfile);

exit;

# 1 larger than nearby
# 0 equal
# -1 smaller than nearby

sub is_max {
    my $i=$_[0];
    my $j=$_[1];
    my $i1=$i-1;
    my $i2=$i+2;
    my $j1=$j-1;
    my $j2=$j+2;
    if ($i1<0) {
	$i1=0;
	$i2=$i1+3;
    }
    if ($i2>$nx-1) {
	$i2=$nx-1;
	$i1=$i2-3;
    }
    if ($j1<0) {
	$j1=0;
	$j2=$j1+3;
    }
    if ($j2>$ny-1) {
	$j2=$ny-1;
	$j1=$j2-3;
    }
    my @a;
    my $k=0;
    my $is_max=-3;
#    print "LIM = $i,$j $i1,$i2 $j1,$j2\n";
    for ($ii=$i1;$ii<$i2;$ii++) {
	for ($jj=$j1;$jj<$j2;$jj++) {
	    if (($ii!=$i)&&($jj!=$j)) {
		if (($ii>0)&&($ii<$nx)&&($jj>0)&&($jj<$ny)) {
		    $a[$k]=$Ha_map->at($ii,$jj);
		    $k++;
		}
	    }
	}
    }
    my $med_a=median(@a);
    my $sig_a=sigma(@a);
    my ($min,$max)=minmax(@a);
    if (($i>0)&&($i<$nx)&&($j>0)&&($j<$ny)) {
	my $val=$Ha_map->at($i,$j);
	my $F_peak=$Ha_map->at($ip,$jp);
#	print "$val $frac $F_peak\n";
	if ($val>$frac*$F_peak) {
	    my $ncut=2.0;
	    if (($val-$med_a)<0) {
		$is_max=-1;
	    }
#	    if (($val-$med_a)<0) {
#		$is_max=-1;
#	    }
	    if (abs($med_a-$val)<=$ncut*$sig_a) {
		$is_max=0;
	    }
#
#	    if ((($val-$med_a)>$sig_a)&&($val>$max)) {
#	    if ((($val-$med_a)>0.3*$med_a)&&($val>=$max)) {
#	    if ((($val-$med_a)>$sig_a)) {
#	    if ((($val-$med_a)>0.*$sig_a)) {
	    if ($val>$med_a) {
#	    if ($val>$max) {
		$is_max=1;
	    }
	}
    }
    return $is_max;
}


sub is_near {
    my $i=$_[0];
    my $j=$_[1];
    my $i1=$i-1;
    my $i2=$i+2;
    my $j1=$j-1;
    my $j2=$j+2;
    if ($i1<0) {
	$i1=0;
	$i2=$i1+3;
    }
    if ($i2>$nx-1) {
	$i2=$nx-1;
	$i1=$i2-3;
    }
    if ($j1<0) {
	$j1=0;
	$j2=$j1+3;
    }
    if ($j2>$ny-1) {
	$j2=$ny-1;
	$j1=$j2-3;
    }
    my $a=0;
    my $k=0;
    my $is_max=-3;
    for ($ii=$i1;$ii<$i2;$ii++) {
	for ($jj=$j1;$jj<$j2;$jj++) {
	    if (($ii!=$i)&&($jj!=$j)) {
		if (($ii>0)&&($ii<$nx)&&($jj>0)&&($jj<$ny)) {
		    $a=$a+$seg_map->at($ii,$jj);
		    $k++;
		}
	    }
	}
    }
    return $a;
}




sub DO {
    my $i=$_[0];
    my $j=$_[1];
    my $dist=sqrt(($i-$ip)**2+($j-$jp)**2);
    my $is_max=is_max($i,$j);
    my $F_PEAK_NOW=$Ha_map->at($ip,$jp);
    my $frac_dist=log10(1+$F_PEAK[1])/log10(1+$F_PEAK_NOW);
    if ($NR==1) {
	$frac_dist=1;
    }
    $frac_dist=1;
    my $dist_max_now=$max_dist/$frac_dist;
    if ($dist_max_now<1.5) {
	$dist_max_now=1.5;
    }
#    print "$i,$j,$is_max $max_dist $dist_max_now $fract_dist $NR $F_PEAK[1] $F_PEAK_NOW\n";
    my $is_point=0;
    if (($i>0)&&($i<$nx)&&($j>0)&&($j<$ny)) {
	my $val=$Ha_map->at($i,$j);
	my $F_peak=$Ha_map->at($ip,$jp);
#	print "$val $frac $F_peak\n";
#	if ($val>$frac*$F_peak) {
#	if (($dist<$max_dist)&&($is_max!=1)&&($is_max!=-3)&&($val>$F_max)) {
#	if (($dist<$max_dist)&&($is_max!=1)&&($is_max!=-3)) {
#	if (($dist<$max_dist)&&($val>$F_max)&&($val>$frac*$F_peak)) {
#	if (($dist<$max_dist)&&($val>$frac*$F_peak)&&($val>$MIN_FLUX)) {
#	if (($dist<$max_dist)&&($val>$frac*$F_peak)&&($val>$MIN_FLUX)) {
	if (($dist<$max_dist)&&($val>$MIN_FLUX)) {
	    if (($dist<$dist_max_now)&&($val>$frac*$F_peak)) {
		my $nr=$seg_map->at($i,$j);
		if ($nr==0) {
		    set($seg_map,$i,$j,$NR);
		    $is_point=1;
		} else {
		    my $d_now=sqrt(($i-$ip)**2+($j-$jp)**2);
		    my $d_r=sqrt(($i-$IP[$nr])**2+($j-$JP[$nr])**2);
		    if ($d_now<$d_r) {
			set($seg_map,$i,$j,$NR);
			$is_point=1;
		    }
		}
	    }
	    set($mask_map,$i,$j,0);	    
	}
    }
    return $is_point;
}


sub mask_around {
    my $i=$_[0];
    my $j=$_[1];
    my $i1=$i-1;
    my $i2=$i+2;
    my $j1=$j-1;
    my $j2=$j+2;
    if ($i1<0) {
	$i1=0;
	$i2=$i1+3;
    }
    if ($i2>$nx-1) {
	$i2=$nx-1;
	$i1=$i2-3;
    }
    if ($j1<0) {
	$j1=0;
	$j2=$j1+3;
    }
    if ($j2>$ny-1) {
	$j2=$ny-1;
	$j1=$j2-3;
    }
    for ($ii=$i1;$ii<$i2;$ii++) {
	for ($jj=$j1;$jj<$j2;$jj++) {
	    set($mask_map,$ii,$jj,0);	    
	}
    }
}

# LOOP(x,y);
sub LOOP {

    my $is=$_[0];
    my $js=$_[1];
    my $nmax=($nx-1)*($ny-1);
    my $n_now=0;
    my $delta=2;
    my $k=0;
    my $sig=0;
    $i=$is;
    $j=$js;

    set($seg_map,$i,$j,$NR);
    set($mask_map,$i,$j,0);
    $n_now=$now+$s;
    $break=0;
    while ($break==0) {
	if ($sig==0) {
	    for ($j=$js+1;$j<$js+$delta;$j++) {
		$s=DO($i,$j);
		$n_now=$n_now+1;
	    }
	    $j--;
	    for ($i=$is+1;$i<$is+$delta;$i++) {
		$s=DO($i,$j);
		$n_now=$n_now+1;
	    }
	    $sig=1;
	    $i--;
	} else {
	    for ($j=$js-1;$j>$js-$delta;$j--) {
		$s=DO($i,$j);
		$n_now=$n_now+1;
	    }
	    $j++;
	    for ($i=$is-1;$i>$is-$delta;$i--) {
		$s=DO($i,$j);
		$n_now=$n_now+1;
	    }
	    $sig=0;
	    $i++;
	}
	$delta++;
	$js=$j;
	$is=$i;


	my $dist=sqrt(($i-$ip)**2+($j-$jp)**2);
	if ($dist>1.5*$max_dist) {
	    $break=1;
	}
    }
    $done=1;
    return $done;
}
