######################################################################
# Cajun display manager/audio player
# Copyright (c) 1999  Paul Bournival Jr. under the GNU Public License
#
# CajunSGX120L.pm    11 Jan 00  hm         Rev 3.0 origination
######################################################################

package CajunSGX120L;
require Exporter;
use POSIX qw(:termios_h);
use IPC::Open2;
use Symbol;

@ISA=qw(Exporter);
@EXPORT=qw();
@EXPORT_OK=qw();

$esc=sprintf("%c",0xfe);
$spaces=" " x 80;

sub new {
  my $self={};
  bless $self,"CajunSGX120L";
  my($junk);

  ($junk,$cajun)=@_;  # param not used
  $self->{cajun}=$cajun;   # for later reference..
  $self->{width}=20;
  $self->{height}=4;
  $self->{line1}=$self->{line2}=$self->{line3}=$self->{line4}="";
  $self->{readh}=Symbol::gensym();
  $self->{writeh}=Symbol::gensym();
  open($self->{writeh},"+>$cajun->{config}{dispport}") 
	or die "failed to open serial port";
  $self->{readh}=$self->{writeh};

  $fd_disp=fileno($self->{writeh});
  $termios = POSIX::Termios->new();
  $termios->getattr($fd_disp);
  $termios->setispeed(B9600); $termios->setospeed(B9600);
  $c_cflag = $termios->getcflag(); $c_lflag = $termios->getlflag();
  $c_oflag = $termios->getoflag(); $c_iflag = $termios->getiflag();

  # set raw
  #######################################################################
  $c_iflag &= ~(BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF);
  $c_iflag &= ~(IUCLC|IXANY|IMAXBEL);
  $c_iflag |= IGNBRK;
  $c_oflag &= ~(OPOST|OLCUC|OCRNL|ONLCR|ONOCR|ONLRET|OFILL|OFDEL);
  $c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN|ECHOE|ECHOK|NOFLSH|XCASE);
  $c_lflag &= ~(TOSTOP|ECHOPRT|ECHOCTL|ECHOKE);
  $c_cflag &= ~(CSIZE|PARENB|PARODD|HUPCL|CSTOPB|CRTSCTS);
  $c_cflag |= CS8|CLOCAL|IXON|IXANY|CREAD;
  #######################################################################

  $termios->setcflag($c_cflag); $termios->setlflag($c_lflag);
  $termios->setoflag($c_oflag); $termios->setiflag($c_iflag);
  $termios->setattr($fd_disp,TCSANOW);

  binmode $self->{writeh}; select($self->{writeh}); $|=1; select(STDOUT);

  my($writeh)=$self->{writeh};
  print $writeh sprintf( "%c", 12 );				# clear & home cursor
  # print $writeh sprintf( "%c", 4 );					# hide cursor
  # print $writeh sprintf( "%c", 14 );					# backlight ON

  $self->backlight_on;

  $self;
}


sub backlight_on {
  my($self)=@_;

  my($writeh)=($self->{writeh});
  print $writeh sprintf("%c", 14 );
}

# The SGX120L does not handle automatic backlight off. We need to
# provide this. We should start a background process which select()s
# stdin (started w/ fork(), inherits $self->{writeh}), write ON on
# refresh, restarts counter, timeout backlight off.


sub backlight_off {
  my($self)=@_;

  my($writeh)=($self->{writeh});
  print $writeh sprintf("%c", 15 );
}

sub display_scroll {
  my($self,@lines)=@_;

  $self->line(1,$lines[0]);
  $self->line(2,$lines[1]);
  $self->line(3,$lines[2]);
  $self->line(4,$lines[3]);
  $self->refresh;
}

sub display_welcome {
  my($self)=@_;
  my($writeh)=$self->{writeh};

  if ( 1 == 0 ) {
    # create custom characters for spelling big "CAJUN" on welcome screen.
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 128
						0x00,0x00,0x00,0x03,0x07,0x07,0x0e,0x0e,0x0e);
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 129
						0x01,0x00,0x00,0x1f,0x1f,0x1f,0x00,0x00);
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 130
						0x02,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e);
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 131
						0x03,0x0e,0x0e,0x07,0x07,0x03,0x00,0x00);
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 132
						0x04,0x0e,0x0e,0x1c,0x1c,0x18,0x00,0x00);
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 133
						0x05,0x00,0x00,0x18,0x1c,0x1c,0x0e,0x0e,0x0e);
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 134
						0x06,0x0e,0x0e,0x0e,0x0e,0x0e,0x00,0x00,0x00);
    print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",  # 135
						0x07,0x00,0x00,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e);

    $self->line(1, sprintf( "%c%c%c %c%c%c   %c %c %c %c%c%c",
        128, 129, 133, 128, 129, 133, 135, 135, 135, 128, 133, 135 ));
    $self->line(2, sprintf( "%c   %c%c%c   %c %c %c %c%c%c",
        130, 130, 129, 130, 130, 130, 130, 130, 130, 130 ));
    $self->line(3, sprintf( "%c%c%c %c %c %c%c%c %c%c%c %c%c%c",
        131, 129, 132, 134, 134, 131, 129, 132, 131, 129, 132, 134, 131, 132 ));
    $self->line(4,"Car Audio Jukebox v3.0");
    $self->refresh;
  } else {
    $self->line(1,$self->center("Cajun v3.0"));
    $self->line(2,$self->center("Car Audio Jukebox"));
    $self->line(3,$self->center("(c) 1999"));
    $self->refresh;
  }
}

sub display_shuffle {
  my($self,$shoutcast)=@_;

  my($shoutcaststr)=($shoutcast ? "7) URL" : "        ");
  $self->line(1,"1) All       5) Jazz");
  $self->line(2,"2) Playlist  6) Slow");
  $self->line(3,"3) Rock      $shoutcaststr");
  $self->line(4,"4) Pop");
  $self->refresh;
}

sub display_play {
  my($self,$cajun)=@_;

  if ($cajun->{audiodev}->{state}==1) {    # stopped... yuk!
    $self->line(1,$self->center("--Stopped--"));
    map {
      $self->line($_," " x $self->{width});
    } (2..4);
    $self->refresh;
  } else {
    my($art,$title,$song,$off,$clock,$percent,$triple,$cur,$ttl);

    # ML: If the song name contains a newline, it must be a stream.
    if ($cajun->{playlist}[$cajun->{playsong}] =~ /\n/) {
      ($ip,$description,$bitrate,$listeners,$avlisten,$uptime) = split("\n",$cajun->{playlist}[$cajun->{playsong}]);
      $file="http://" . $ip;
      $art=$ip;
      $title=$description;
      $song=" Bitrate:" . $bitrate . " Listeners:" . $listeners . " Av. listen time:" . $avlisten . " Uptime:" . $uptime;
    } else {
      ($file,$triple)=split("\0",$cajun->{playlist}[$cajun->{playsong}]);
      ($art,$title,$song)=split("/",$triple);
      $art=Cajun::file2song($art);  # remove leading numbers
      $title=Cajun::file2song($title);  # remove leading numbers
      $song=Cajun::file2song($song);  # remove leading numbers
    }
    $cur=$cajun->{playsong}+1;
    $ttl=scalar(@{ $cajun->{playlist} });
    
    if ($cajun->{state_clock} eq "00:00:00") {    
       $song_scroll = sprintf("%s        ", $song);
    }
    # increment the counters if necessary.
    if ($cajun->{config}{scrollinterval}) {
      $cajun->{scrollcounter1}++; 
      $cajun->{scrollcounter1}=0 if $cajun->{scrollcounter1}>length($art)-$self->{width};
      $cajun->{scrollcounter2}++; 
      $cajun->{scrollcounter2}=0 if $cajun->{scrollcounter2}>length($title)-$self->{width};
#      $cajun->{scrollcounter3}++; 
#      $cajun->{scrollcounter3}=0 if $cajun->{scrollcounter3}>length($song_scroll)-$self->{width};

      $art=substr($art,$cajun->{scrollcounter1});
      $title=substr($title,$cajun->{scrollcounter2});
      $song_scroll=sprintf("%s%s", substr($song_scroll, 1,length($song_scroll)), substr($song_scroll, 0, 1));
#      substr($song_scroll,$cajun->{scrollcounter3});
    }
    $clock=$cajun->{state_clock} ne "" ? $cajun->{state_clock} : "00:00:00";
    $clock=substr($clock,3);  # chop the hours from the display
    if ($cajun->{state_range}>0) {
      $percent=int($cajun->{state_offset}/$cajun->{state_range}*100);
    } else {
      $percent=0;
    }
    $self->line(1,$self->center(sprintf("$clock %02d%% %d/%d",$percent,
          $cur,$ttl)));
    $self->line(2,$self->center($art));
    $self->line(3,$self->center($title));
    $self->line(4,$self->center($song_scroll));
    $self->refresh;
  }
}

sub display_menu {
  my($self,$fmcard,$cdplayer)=@_;

  my($fmstr)=($fmcard ? "8) Radio" : "     ");
  my($cdstr)=($cdplayer ? "5) CDAudio" : "     ");
  $self->line(1,"1) Play    $cdstr");
  $self->line(2,"2) Utils   6) Playlst");
  $self->line(3,"3) Shuffle *) SongUtl");
  $self->line(4,"4) HotList $fmstr");
  $self->refresh;
}

sub display_util {
  my($self)=@_;

  $self->line(1,"1) Stats   5) EQ    ");
  $self->line(2,"2) Mount Media      ");
  $self->line(3,"3) Password         ");
  $self->line(4,"4) Contrast         ");
  $self->refresh;
}

sub display_contrast {
  my($self)=@_;

  $self->line(1,$self->center("Use 1/3 to change"));
  $self->line(2,$self->center("Current setting:"));
  $self->line(3,$self->center($self->{cajun}->{config}{contrast}));
  $self->line(4,"");
  $self->refresh;
}

sub display_password {
  my($self)=@_;
}

sub display_cdaudio {
  my($self,$msg)=@_;

  my ($s1,$s2)=$self->{cajun}->{cdplayer}->status();

  $self->line(1,"");
  $self->line(2,$self->center($s1));
  $self->line(3,$self->center($s2));
  $self->line(4,"");
  $self->refresh;
}

sub display_eq {
  my($self,$b,$v,$t)=@_;
  my($writeh)=($self->{writeh});

  if ( $self->{cajun}->{config}{mixer} eq "braindead" ) {
    $self->line(1," Volume:");
    $self->line(2," ");
    $self->line(3," ");
    $self->line(4," ");
    $self->refresh;

    print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 0, 60, 9, 19, $v/2, 0 );
  } else {
    $self->line(1," Treble:");
    $self->line(2," Volume: ");
    $self->line(3," Bass:");
    $self->line(4,"                    ");
    $self->refresh;

    print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 0, 60, 9, 19, $t/2, 0 );
    print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 1, 60, 9, 19, $v/2, 1 );
    print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 2, 60, 9, 19, $b/2, 2 );
  }
}

sub display_mount {
  my($self,@mounts)=@_;

  my(@list);
  for $mount (@mounts) {
    ($part,$name,$stat)=split(":",$mount);
    push(@list,"$stat $name");
  }
  $self->line(1,"1) Statistics       ");
  $self->line(2,"2) Removable Media  ");
  $self->line(3,"                    ");
  $self->line(4,"                    ");
  $self->refresh;
}

sub display_shutdown {
  my($self)=@_;
  $self->line(1,$self->center("Press '#' to shutdown,"));
  $self->line(2,$self->center("Any other to return"));
  $self->line(3,$self->center("to the main menu"));
  $self->line(4,"");
  $self->refresh;
}

# ML: I will also work on displaying CD's/Tracks per partition
sub display_statistics {
  my($self,$partition_data)=@_;
  ($partition,$name)=split(":",$partition_data);
  open(DF,"df -h $partition|");
  @lines=<DF>;
  close(DF);
  $stats=($lines[1]);
  ($df_filesystem,$df_size,$df_used,$df_available,$df_capacity,$df_mountpoint)=split(/\s+/,$stats);
  $self->line(1,"$name");
  $self->line(2,"Size:$df_size Used:$df_used");
  $self->line(3,"Free:$df_available $df_capacity full");
  $self->line(4,"Press '0' to continue...");
  $self->refresh;
}

sub display_stream {
  my ($self)=@_;
  $self->line(1,"1) Choose genre");
  $self->line(2,"2) Choose station");
  $self->line(3,"");
  $self->line(4,"");
  $self->refresh;
}

sub display_radio {
  my($self,$msg)=@_;
  my($writeh)=$self->{writeh};
#  print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c",
#		                      0x00,0x01,0x02,0x04,0x02,
#			              0x14,0x18,0x1c);
  my ($freq)=$self->{cajun}->{radiodev}->currfreq;
  my ($station)=$self->{cajun}->{radiodev}->getstation;
  my ($scanmode)=$self->{cajun}->{radiodev}->readmode;
  my ($seek_flag)=$self->{cajun}->{radiodev}->seekflag;
  if ($seek_flag eq "SK") {
     $seek_flag = "\0";
  }
  $self->line(1,"FM         $seek_flag");
  $self->line(2,"Freq: $freq Mhz  M-$station");
  $self->line(3,"Mode: $scanmode");
  $self->line(4,"");

  $self->refresh;
}

sub display_radioda {
  my($self,$msg)=@_;
    
  my ($freq)=$self->{cajun}->{radiodev}->{dafreq};
  my ($scanmode)=$self->{cajun}->{radiodev}->readmode;
  my ($seek_flag)=$self->{cajun}->{radiodev}->seekflag;
  $self->line(1,"FM         $seek_flag");
  $self->line(2,"Freq: $freq Mhz  M-$station");
  $self->line(3,"Mode: $scanmode");
  $self->line(4,$self->center("Enter Frequency"));

  $self->refresh;
}

#
# message: if sleeptime==0, the previous screen won't be restored.
#
sub message {
  my($self,$message,$sleeptime)=@_;
  my($word,@words,$cc,$cl);

  my(@sv)=($self->{line1},$self->{line2},$self->{line3},$self->{line4});
  ($self->{line1},$self->{line2},$self->{line3},$self->{line4})=("","","","");
  $cc=0;
  $cl=1;
  for $word (split(" ",$message)) {
    if ($cc+length($word) > $self->{width}) {
      $cc=0;
      $cl++;
    }
    $self->{"line$cl"} .= $word . " ";
    $cc+=length($word)+1;
  }
  $self->refresh;
  sleep($sleeptime);

  # if time to sleep is 0, assume user wants to leave msg on screen.
  if ($sleeptime>0) {
    ($self->{line1},$self->{line2},$self->{line3},$self->{line4})=@sv;
    $self->refresh;
  }
}
sub line {
  my($self,$lineno,$msg)=@_;
  $msg=substr($msg . (" " x ($self->{width}+1)),0,$self->{width});
  $self->{"line$lineno"}="$msg";
}

sub refresh {
  my($self)=@_;
  my($str);
  my($writeh)=$self->{writeh};

  print $writeh sprintf( "%c", 0x01 );   # home cursor
  for $row (1..4) {
    if ($self->{"line$row"} ne $self->{"cline$row"}) {
      $self->{"cline$row"}=$self->{"line$row"};

      # Ctrl-P, pos, SPC, Text
      print $writeh sprintf( "%c%s ", 0x10, ($row - 1) * $self->{width}) .
            substr( $self->{"cline$row"} . $spaces,0,$self->{width} );
    }
  }
}

sub center {
  my($self,$str)=@_;
  $str =~ s/ *$//;
  $str =~ s/^ *//;
  my($left)=($self->{width}-length($str));
  my($extra)=" " x (int($left/2));
  substr($extra . $str . $extra . "     ",0,$self->{width});
}

sub DESTROY {
  close($self->{writeh});
}

1;

