#!/usr/bin/perl
use CGI qw(:standard);
use DBI;
use Ogg::Vorbis::Header;
use Time::Local;


require "/usr/local/tunequeue/setup.pl";
require "cs_subs.pl";

my $dbh = DBI->connect($config{'DB_STRING'},$config{'DB_USER'},$config{'DB_PASS'});

$CGI::DISABLE_UPLOADS = 1;
$CGI::POST_MAX        = 102_400; # 100 KB

my $q = new CGI;

print $q->header( "text/html" );


# get cgi vars

unless ($mode = $q->param( 'mode' )) { $mode = $config{'DEFAULT_MODE'}; }
unless ($chanid = $q->param( 'chan' )) { $chanid = $config{'DEFAULT_CHANNELID'}; }
unless ($displaymode = $q->param( 'display' )) { $displaymode = $config{'DEFAULT_DISPLAYMODE'}; }
unless ($targetid = $q->param( 'targetid' )) { $targetid = 0; }

$config{'LISTENER_IP'} = $ENV{'REMOTE_ADDR'};
$config{'LISTENER_SERVER'} = $ENV{'SERVER_NAME'};


## ACTIONS

if ($action = $q->param( 'action' ))
{
 #### we need to do something before generating page...

 ### things that require a target song id

 if ($targetid)
 {

  ##### process bumping
  if ($action eq "bump")
  {

   
# must rewrite bumpin!
#   $qry = "UPDATE schedule SET added = ? WHERE (TuneID = ?) AND (channelid = ?)";
#   $out = $dbh->prepare($qry);
#   $out->execute($bumpto,$bumpid,$chanid);

  }
  elsif ($action eq "trade")
  {

   ########## trade ins

   my $qry = "SELECT artist FROM tunes WHERE ID = ?";
   my $out = $dbh->prepare($qry);
   $out->execute($targetid); 

   if (my($tartist)=$out->fetchrow_array)
   {
    $qry = "SELECT ID FROM tunes WHERE artist = ?";
    $out = $dbh->prepare($qry);
    $out->execute($tartist);

    @ttids = ();

    while (my($ttid)=$out->fetchrow_array)
    {
      push(@ttids,$ttid); 
    }

    if (@ttids > 1)
    {
     $ntid = $tradeid;
     while ($ntid eq $tradeid) 
     { 
      $ntid = $ttids[rand @ttids]; 
     }

     $qry = "UPDATE schedule SET TuneID = ? WHERE TuneID = ? and channelid = ?";
     $out = $dbh->prepare($qry);
     $out->execute($ntid,$targetid,$chanid)
    }
   }
  } 
  elsif ($action eq "trash")
  {

   ### delete tunes from coming up

   # pretend we played it..
   $qry = "UPDATE channeltunes SET lastplayed = NOW(),cancels = cancels + 1 WHERE tuneid = ? AND channelid = ?"; 
   $out = $dbh->prepare($qry);
   $out->execute($targetid,$chanid); 

   # remove from schedule..
   $qry = "DELETE FROM schedule WHERE TuneID = ? AND channelid = ?";
   $out = $dbh->prepare($qry);
   $out->execute($targetid,$chanid);   

   # call scheduletunes to replace it.. should not be hard coded path!
   `$config{'SCRIPT_DIR'}/scheduletunes.pl`;
  }
  elsif ($action eq "rate")
  {

   #### Tune voting
   if ($rating = $q->param('rating')) 
   {

    if (($rating < 6)  && ($rating > 0))
    {
     $qry = "INSERT INTO tuneratings (tuneid,voteip,rating,time) VALUES (?,?,?,NOW())";
     $out = $dbh->prepare($qry);
     $out->execute($targetid,$config{'LISTENER_IP'},$rating);
    }
   } 
  }
 }
}


# load %vars with data we'll probably need...
%vars = &preloadvars($chanid,$mode,$displaymode);

# read in template
my $tmplfn = $config{'TEMPLATE_DIR'} . "/" . $mode . ".html";
my @tmpl = ();

open(TMPL,"< $tmplfn") or die "Cannot open template file: $!";

while (<TMPL>)
{
 push(@tmpl,$_);
}

close(TMPL);

# preprocess
@tmpl = &preproc(\%vars,@tmpl);

# substitute vars
for (my $x = 1;$x < @tmpl;$x++)
{
 (@tmpl[$x],%vars) = subvars(@tmpl[$x], \%vars);
}

#display

foreach $line (@tmpl)
{
 print "$line";
}

##### the end


sub subvars
{
 my ($line,$vars) = @_;
 
 # match vars
 while ($line =~ m/\$([A-Z0-9_]+)\$/g)
 {
  my $v = $1;
  if (exists($vars{$v}))
  {
   $line =~ s/\$$v\$/$vars{$v}/;
  }
  elsif (exists($config{$v}))      
  {
   $line =~ s/\$$v\$/$config{$v}/;
  }
  else 
  {
   #try to load vars with new value, for things we only calc when we have to..
  
   %vars = &addvar($v,%vars);
   unless (exists($vars{$v}))
   {
    warn "unknown variable: $v";
   }
   else
   {
    $line =~ s/\$$v\$/$vars{$v}/;
   }
  }
 }

 return ($line,%vars);
}


sub preproc
{
 my ($vars,@tmpl) = @_;
 my @newtmpl = ();

 foreach $line (@tmpl)
 {
  while ($line =~ m/\$SUB\_([A-Z0-9_]+)\$/g)
  {
   #check for sub exists? not really sure how
   my $func = "sub_" . $1;
   my $v = &$func(\%vars,\%config);
   $line =~ s/\$SUB\_$1\$/$v/;
  }
  push(@newtmpl,$line);
 }

 return @newtmpl;
}


sub addvar
{
 my ($var,%vars) = @_;

 #load coming up songs if asked
 if ($var =~ m/COMINGUP(\d)\_.*/)
 {
  %vars = loadcomingup($1,%vars);
 }
 elsif ($var =~ m/JUSTPLAYED(\d)\_.*/)
 {
  %vars = loadjustplayed($1,%vars);
 }
 
 return %vars;
}


sub loadcomingup
{
 my ($num,%vars) = @_;

 my $qry = "SELECT TuneID FROM schedule WHERE channelid = ? ORDER BY added LIMIT ?";
 my $out = $dbh->prepare($qry);
 $out->execute($vars{'CHANNEL_ID'},$num);

 my $x = 0;

 while (my($crap)=$out->fetchrow_array)
 {
  $x++;
  $tuneid = $crap;
 }

 if ($x == $num)
 {
  %vars = loadsonginfo($tuneid,"COMINGUP$num",%vars);
 }
 else
 {
  warn "Asked for coming up #$num but can't find it in schedule";
 }

 return %vars;
}



sub loadjustplayed
{
 my ($num,%vars) = @_;

 #because currently playing song is already in tunelogging..

 my $qry = "SELECT tuneid FROM tunelogging WHERE channelid = ? ORDER BY datetime DESC LIMIT ?";
 my $out = $dbh->prepare($qry);
 $out->execute($vars{'CHANNEL_ID'},$num+1);

 my $x = 0;

 while (my($crap)=$out->fetchrow_array)
 {
  $x++;
  $tuneid = $crap;
 }

 if ($x == ($num+1))
 {
  %vars = loadsonginfo($tuneid,"JUSTPLAYED$num",%vars);
 }
 else
 {
  warn "Asked for justplayed #$num but can't find it in history";
 }

 return %vars;
}


sub preloadvars
{
 my ($chanid,$mode,$displaymode) = @_;

 my %tmpvars = '';

 ### load channel vars

 $tmpvars{'CHANNEL_ID'} = $chanid;
 
 $qry = "SELECT name,description,url FROM channels WHERE ID = ?";
 $out = $dbh->prepare($qry);
 $out->execute($chanid);

 unless (($tmpvars{'CHANNEL_NAME'},$tmpvars{'CHANNEL_DESC'},$tmpvars{'CHANNEL_URL'}) = $out->fetchrow_array) { warn "Could not load channel data.";}

 ### current song/show info
 $qry = "SELECT status.tune_id,status.req,status.tunes_since_ad,status.started_at,status.seq,status.actshow_id 
         FROM status WHERE status.ID = ?";
 $out = $dbh->prepare($qry);
 $out->execute($chanid);
 
 unless (($tmpvars{'SONG_ID'},$tmpvars{'SONG_REQ'},$tmpvars{'SHOW_TUNESSINCEAD'},$tmpvars{'SONG_STARTEDAT'},$tmpvars{'SHOW_SEQ'},$tmpvars{'SHOW_ID'})=$out->fetchrow_array)
 {
  warn "could not find current song/show info in status table";
 }
 else
 {
  %tmpvars = &loadsonginfo($tmpvars{'SONG_ID'},"SONG",%tmpvars); 
  
  if ($tmpvars{'SHOW_ID'} > 0)
  {
   $qry = "SELECT showname,showdesc,showstart,showend,showdate,logoimg,showalg FROM shows WHERE ID = ?";
   $out = $dbh->prepare($qry);
   $out->execute($tmpvars{'SHOW_ID'});

   unless (($tmpvars{'SHOW_NAME'},$tmpvars{'SHOW_DESC'},$tmpvars{'SHOW_START'},$tmpvars{'SHOW_END'},$tmpvars{'SHOW_DATE'},$tmpvars{'SHOW_LOGOIMG'},$tmpvars{'SHOW_ALG'}) = $out->fetchrow_array) 
   {
    warn "could not load show info for show ID $tmpvars{'SHOW_ID'}";
   }
  }
 }

 ### load CGI vars
 
 $tmpvars{'CGI_ME'} = "cs.pl";  # should be a setting or something automatic?
 $tmpvars{'CGI_MODE'} = $mode;
 $tmpvars{'CGI_DISPLAY'} = $displaymode;

 $tmpvars{'CGI'} = $tmpvars{'CGI_ME'} . "?chan=" . $tmpvars{'CHANNEL_ID'} . "&mode=" . $tmpvars{'CGI_MODE'} . "&display=" . $tmpvars{'CGI_DISPLAY'};
 
 ### refresh calc
 my ($startedat_secs);

 if ($tmpvars{'SONG_STARTEDAT'} =~ m/^(\d\d\d\d)-(\d\d)-(\d\d)\ (\d\d):(\d\d):(\d\d).*/)
 {
  $startedat_secs = timelocal($6,$5,$4,$3,$2-1,$1);
 }

 # icecast stream/buffer delay is hard to figure.. so guess + 10?
 my $r = int($tmpvars{'SONG_LENGTH'} - (time() - $startedat_secs))+10;

 #minumum refresh of 10 seconds
 if ($r < 10) { $r = 10; }

 $tmpvars{'CGI_SONGREFRESH'} = $r;

 
 # preload upcoming and justplayed tune infos

 my $qry = "SELECT TuneID,added,request,seq,showid FROM schedule WHERE channelid = ? ORDER BY added LIMIT ?";           
 my $out = $dbh->prepare($qry);
 $out->execute($tmpvars{'CHANNEL_ID'},$config{'PRELOAD_COMINGUP'});

 my $x = 1;

 while (($tmpvars{'COMINGUP' . $x . '_ID'},$tmpvars{'COMINGUP' . $x . '_SCHEDULED'},
           $tmpvars{'COMINGUP' . $x . '_REQ'},$tmpvars{'COMINGUP' . $x . '_SEQ'},
           $tmpvars{'COMINGUP' . $x . '_SHOWID'})=$out->fetchrow_array)
 {
  %tmpvars = loadsonginfo($tmpvars{'COMINGUP' . $x . '_ID'},"COMINGUP$x",%tmpvars);  
  $x++;
 }

 my $qry = "SELECT tuneid,datetime FROM tunelogging WHERE channelid = ? ORDER BY datetime DESC LIMIT ?";
 my $out = $dbh->prepare($qry);
 $out->execute($tmpvars{'CHANNEL_ID'},$config{'PRELOAD_JUSTPLAYED'}+1); 

 my $x = 0;

 while (($tmpvars{'JUSTPLAYED' . $x . '_ID'},$tmpvars{'JUSTPLAYED' . $x . '_PLAYED'})=$out->fetchrow_array) 
 {
  #skip one because currently playing song is already in history
  if ($x) {  %tmpvars = loadsonginfo($tmpvars{'JUSTPLAYED' . $x . '_ID'},"JUSTPLAYED$x",%tmpvars); }
  $x++;
 }


 return (%tmpvars);
}



sub loadsonginfo
{
 my ($tuneid,$label,%tmpvars) = @_;

 ### load current song info

 $tmpvars{$label . '_ID'} = $tuneid;

 $qry = "SELECT tunes.artist,tunes.album,tunes.title,tunes.filename,tunes.time,tunes.added,
                channeltunes.lastplayed,channeltunes.added,channeltunes.totalplays,channeltunes.requests,
		channeltunes.cancels
         FROM tunes, channeltunes WHERE (tunes.ID = channeltunes.tuneid) AND (channeltunes.channelid = ?) AND (tunes.ID = ?)";
 $out = $dbh->prepare($qry);
 $out->execute($tmpvars{'CHANNEL_ID'},$tuneid);

 unless (($tmpvars{$label . '_ARTIST'},$tmpvars{$label . '_ALBUM'},$tmpvars{$label . '_TITLE'},
          $tmpvars{$label . '_FILENAME'},$tmpvars{$label . '_LENGTH'},$tmpvars{$label . '_ADDED'},
          $tmpvars{$label . '_LASTPLAYED'},$tmpvars{$label . '_CHANNELADDED'},$tmpvars{$label . '_TOTALPLAYS'},
          $tmpvars{$label . '_REQUESTS'},$tmpvars{$label . '_CANCELS'})=$out->fetchrow_array)
 {
  # oh no.. can't get song info?
  
  warn "Could not get song info for tune id $tuneid"; 

  $tmpvars{$label . '_ARTIST'} = $tmpvars{'CHANNEL_NAME'};
  $tmpvars{$label . '_TITLE'} = $tmpvars{'CHANNEL_DESC'};
  $tmpvars{$label . '_ALBUM'} = $tmpvars{'CHANNEL_URL'};
  $tmpvars{$label . '_FILENAME'} = "";
  $tmpvars{$label . '_ID'} = -1;
  $tmpvars{$label . '_LENGTH'} = -1;
  # could load dummy data for other vars but do we need too?
 }

 ### coverart

 my $artfn = "unknown$tmpvars{'CHANNEL_ID'}.jpg";

 if (-e "$config{'COVERART_DIR'}$tmpvars{$label . '_ARTIST'} - $tmpvars{$label . '_ALBUM'}.jpg")
 {
  $artfn = "$tmpvars{$label . '_ARTIST'} - $tmpvars{$label . '_ALBUM'}.jpg";
 }
 elsif (-e "$config{'COVERART_DIR'}$tmpvars{$label . '_ALBUM'}.jpg")
 {
  $artfn = "$tmpvars{$label . '_ALBUM'}.jpg";
 }
 
 $tmpvars{$label . '_ART'} = $config{'COVERART_BASE'} . $artfn;
 $tmpvars{$label . '_SMALLART'} = $config{'COVERART_BASE'} . "s_" . $artfn;

 
 ### ratings

 $qry = "SELECT * FROM tuneratings WHERE tuneid = ?";
 $out = $dbh->prepare($qry);
 $out->execute($tuneid);

 my $votes = 0;
 my $totrating = 0;

 while (my($voteid,$tuneid,$voteip,$rating,$time)=$out->fetchrow_array)
 {
  if (($rating < 6) && ($rating > 0))
  {
   $totrating = $totrating + $rating;
   $votes++;
  }
 }

 my $prating = "Unrated";
 if ($votes)
 {
  $prating = sprintf "%.2f",($totrating / $votes);
 }
 else
 {
  $votes = "No";
 }
 $tmpvars{$label . '_RATING'} = $prating;
 $tmpvars{$label . '_VOTES'} = $votes; 


 return (%tmpvars);
}
