#!/usr/local/bin/perl -w

use Getopt::Long;
use Astro::Vex;
use Astro::Time;

$Astro::Time::StrSep = ' ';
$Astro::Time::StrZero = 2;

sub addmode ($$$$$$);
sub modesetup ($$$\%);

use strict;

if (@ARGV!=1) {
  die "Usage vex2psn.pl <vexfile>\n";
}

my $vex = new Astro::Vex(shift);
my $exper = $vex->exper->exper_name;

my %modes;
my ($oldfreq1, $oldfreq2, $nfreq);

my  $antid = 'Pa';

print<<EOF;
!
! Parkes frequency-switching file for $exper
! Assumes already set to first frequency using normal lorun command
! run on joffrey as 
!      losched ${exper}.losched
! (assuming this file is called ${exper}.loshed)
!
! Created with vex2freq.pl
!
EOF

my @scans = $vex->ant_sched($antid);

my ($source, $dayno, $year, $ut);

my $first = 1;
my $last_stop;
foreach (@scans) {

  my $start = $_->start;
  my $scanlen = $_->stations('Pa')->datastop;
  my $stop = $start+$scanlen->unit('day')->value;

  my $modename = $_->mode;


  if (! exists $modes{$modename}) {
    modesetup($vex, 'Pa', $modename, %modes);
  }


  my $freq1 = $modes{$modename}->{FREQ1};
  my $freq2 = $modes{$modename}->{FREQ2};
  my $bw = $modes{$modename}->{BANDWIDTH};

  if ($first) {
    $oldfreq1 = $freq1;
    $oldfreq2 = $freq2;
    $nfreq = $modes{$modename}->{NFREQ};

    $freq1 = 'SETME' if ($freq1 == 0);
    $freq2 = 'SETME' if ($freq2 == 0);
    $first = 0;
  } else {
    my $freqchange = 0;

    if ($freq1!=$oldfreq1) {
      $freqchange = 1;
    }
    if ($freq2!=$oldfreq2) {
      $freqchange = 1;
    }

    if ($freqchange) {
      ($dayno, $year, $ut) = mjd2dayno($last_stop);
      print "!\n";
      printf "%4d %03d %s ! $modename\n", $year, $dayno, turn2str($ut,'H',0);
      printf "lo_drv lochain fr1 %d 64 fr2 %d 64\n", $freq1, $freq2;
    }
  }

  $oldfreq1 = $freq1;
  $oldfreq2 = $freq2;
  $last_stop = $_->stop;
}


sub modesetup ($$$\%) {

  my ($vex, $ant, $modename, $modes) = @_;

  my $mode = $vex->mode($modename)->{$ant};

  my @chans = $mode->chan_def;
  my @chan_data;
  foreach (@chans) {
    my %vals = ();
    my $sideband = $_->sideband;
    my $sign;
    if ($sideband eq 'L') {
      $sideband = 'LSB';
      $sign = -1;
    } else {
      $sideband = 'USB';
      $sign = +1;
    }
    
    $vals{SIDEBAND} = $sideband;
    $vals{SIDESIGN} = $sign;

    my $pol = $_->pol;
    if ($pol eq 'R') {
      $pol = 'RCP';
    } elsif ($pol eq 'L') {
      $pol = 'LCP';
    }
    
    $vals{POL} = $pol;
    $vals{BW} = $_->bw->value;

    my $f0  = $_->freq;
    $f0->unit('MHz');

    my $f1 = $f0;
    if ($_->sideband eq 'U') {
      $f1 += $_->bw;
    } else {
      $f0 -= $_->bw;
    }
    $vals{F0} = $f0->value;
    $vals{F1} = $f1->value;

    push @chan_data, \%vals;

  }

  @chan_data = sort {$a->{F0} <=> $b->{F0}} @chan_data;

  my $freq1;
  my $freq2;
  my $nfreq;
  my $bw;
  my $nchan = scalar(@chan_data);
  # Sort out what sort of mode it is

  my $lsb=0;
  foreach (@chan_data) {
    #warn "***  ", $_->{F0}, '--', $_->{F1}, '  ', $_->{BW}, ' ', $_->{POL}, ' ', $_->{SIDEBAND}, "\n";
    if ($_->{SIDEBAND} eq 'LSB') {
      $lsb = 1;
      last;
    }
  }

  if ($nchan==0) {
    die "No frequency channels found for mode $mode\n";
  } elsif ($nchan==1) {
    # Will use a AT16s type DAS profile

    if ($lsb) {
      warn "Does not support LSB in mode $modename\n";
      addmode($modes, $modename, 0, 0, 0, 0);
      return;
    }

    $nfreq = 1;
    $freq1 = $chan_data[0]->{F0}+$chan_data[0]->{BW};
    $freq2 = $freq1;
    $bw = $chan_data[0]->{BW};
  } elsif ($nchan==2) {

    if ($chan_data[0]->{F0}==$chan_data[1]->{F0}) {

      $nfreq = 1;
      $bw = $chan_data[0]->{BW};
      if ($bw==16) {
	if ($lsb) {
	  warn "Does not support LSB in mode $modename\n";
	  addmode($modes, $modename, 0, 0, 0, 0);
	  return;
	}
	# VSOP mode
	$freq1 = $chan_data[0]->{F0}+$chan_data[0]->{BW};
      } else  {
	$freq1 = ($chan_data[0]->{F0}+$chan_data[0]->{F1})/2;
      }
      $freq2 = $freq1;
    } elsif (($chan_data[0]->{F0}==$chan_data[1]->{F1} ||
	      $chan_data[0]->{F1}==$chan_data[1]->{F0})
	    ) {
      die "No not support single pol modes if BW != 16 MHz\n"
	if ($chan_data[0]->{BW}!=16 || $chan_data[1]->{BW}!=16);
      
      # VSOP mode
      $nfreq = 1;
      $freq1 = ($chan_data[0]->{F0}+$chan_data[1]->{F1})/2;
      $freq2 = $freq1;
    } else {
      $nfreq = 2;
      $freq1 = $chan_data[0]->{F0}+$chan_data[0]->{BW}/2;
      $freq2 = $chan_data[1]->{F0}+$chan_data[1]->{BW}/2;
    }
    $bw = $chan_data[0]->{BW};
    
  } elsif ($nchan==4) {
    # Check we understand this mode

    $bw = undef;
    for (my $i=0; $i<4; $i++) {
      if (!defined $bw) {
	$bw = $chan_data[$i]->{BW};
      } else {
	if ($bw != $chan_data[$i]->{BW}) {
	  die "Does not supports mixed bandwidths\n";
	}
      }
    }
    
    # Single pol??
    my $singlepol = 1;
    my $pol = $chan_data[0]->{POL};
    foreach (@chan_data) {
      if ($_->{POL} ne $pol) {
	$singlepol = 0;
	last;
      }
    }

    if ($singlepol) {
      die "Do not support 4 channel 64 MHz (mode $modename)" if ($bw==64);

      for (my $i=0; $i<4; $i+=2) {
	if ($chan_data[$i]->{F0}+$bw!=$chan_data[$i+1]->{F0}) {
	  die "Do not support this mode setup $modename";
	}
      }

      $nfreq = 2;
      $freq1 = ($chan_data[0]->{F0}+$chan_data[1]->{F1})/2;
      $freq2 = ($chan_data[2]->{F0}+$chan_data[3]->{F1})/2;

    } else {

      if ($bw!=16) {
	if ($chan_data[0]->{F0}!=$chan_data[1]->{F0} ||
	    $chan_data[2]->{F0}!=$chan_data[3]->{F0}) {
	  die "Do not support this mode setup $modename";
        }
        $nfreq = 2;
	$freq1 = ($chan_data[0]->{F0}+$chan_data[0]->{F1})/2;
	$freq2 = ($chan_data[2]->{F0}+$chan_data[2]->{F1})/2;
      } elsif ($chan_data[0]->{F0}==$chan_data[1]->{F0} &&
	  $chan_data[2]->{F0}==$chan_data[3]->{F0} &&
	  $chan_data[0]->{F0}+$bw==$chan_data[3]->{F0}) {
	# Standard dual pol
	$nfreq = 1;
	$freq1 = ($chan_data[0]->{F0}+$chan_data[2]->{F1})/2;
	$freq2 = $freq1;
      } elsif ($chan_data[0]->{F0}==$chan_data[1]->{F0} &&
	       $chan_data[2]->{F0}==$chan_data[3]->{F0}) {
	# Use VSOP profile - not sure this works with LSB
	$nfreq = 2;
	$freq1 = $chan_data[0]->{F1};
	$freq2 = $chan_data[2]->{F1};
      } elsif (($chan_data[0]->{F0}+$bw==$chan_data[1]->{F0}) &&
	       ($chan_data[2]->{F0}+$bw==$chan_data[3]->{F0})) {
	$nfreq = 2;
	$freq1 = $chan_data[0]->{F1};
	$freq2 = $chan_data[2]->{F1};
      } else {
	die "Do not support this mode setup $modename";
      }
    }
  } elsif ($nchan==8) {
    my $bw = undef;

    # Check not mixed bandwidth
    foreach (@chan_data) {
      if (!defined $bw) {
	$bw = $_->{BW};
      } else {
	if (($bw != $_->{BW})) {
	  my $bw2 = $_->{BW};
	  warn "Does not support mixed bandwith observations ($bw/$bw2)";
	  addmode($modes, $modename, 0, 0, 0, 0);
	  return;
	}
      }
    }

    # Check pairs of frequencies
    for (my $i=0; $i<4; $i++) {

      if ($chan_data[$i*2]->{F0}!=$chan_data[$i*2+1]->{F0} ||
	  $chan_data[$i*2]->{POL} eq $chan_data[$i*2+1]->{POL}) {
	die "Do not support this mode setup $modename";
      }
    }

    # Check 16 MHz pairs
    foreach my $i (0,4) {
      if ($chan_data[$i]->{F0}+$bw!=$chan_data[$i+2]->{F0}) {
	die "Do not support this mode setup $modename";
      }
    }
    
    $nfreq = 2;
    $freq1 = ($chan_data[0]->{F0}+$chan_data[2]->{F1})/2;
    $freq2 = ($chan_data[4]->{F0}+$chan_data[6]->{F1})/2;
    $bw = '16.0';
    
  } else {
    die "Do not support $nchan channels in mode $modename\n";
  }

  addmode($modes, $modename, $freq1, $freq2, $nfreq, $bw);
}

sub addmode ($$$$$$) {
  my ($modes, $modename, $freq1, $freq2, $nfreq, $bw) = @_;

  $modes->{$modename} = {};
  $modes->{$modename}->{FREQ1} = $freq1;
  $modes->{$modename}->{FREQ2} = $freq2;
  $modes->{$modename}->{NFREQ} = $nfreq;
  $modes->{$modename}->{BANDWIDTH} = $bw;
}
