#!/usr/bin/perl -w


# Copyright (c) 1998 "Lathi" <alcornd@earthlink.net>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

###################
# Purpose
#
# The purpose of this script is to take the current AfterStep
# configuration and strip out a minimal set of data so that it can
# later be applied to the ~/G/L/A directory tree to implement a
# "theme" for AfterStep.  This script works on the assumption of
# version 1.5 or greater.

###################
# Scope
#
# Here are the individual components that I think make up a theme.
# Obviously, the individual look file in its entirety.  Also the Wharf
# TextureType, Pixmap, TextureColor, and BgColor.  The Pager Font,
# SmallFont, Fore, Back, Hilight, DesktopImage, Image, Align,
# BalloonFore, BalloonBack, BalloonFont, BalloonBorderWidth, and
# BalloonBorderColor. Finally, the WinListFont, WinListFore,
# WinListBack, and WinListJustify.  As an added bonus, a scheme will
# be included to allow icons for both Wharf and the database to be
# replaced.

# Setting these options to TRUE is somewhat misleading.  Later on I am
# just going to do a check to see if the option exist in the hash.  It
# is a fast way to find things.  So, setting them to FALSE will not
# disable the option from the list.  It must be undefined.
my %WHARF_OPTIONS = (
		     "BgColor" => "TRUE",
		     "Pixmap" => "TRUE",
		     "TextureColor" => "TRUE",
		     "TextureType" => "TRUE",
		     );
my %PAGER_OPTIONS = (
		     "Align" => "TRUE",
		     "Back" => "TRUE",
		     "BalloonBack" => "TRUE",
		     "BalloonBorderColor" => "TRUE",
		     "BalloonBorderWidth" => "TRUE",
		     "BalloonFore" => "TRUE",
		     "DesktopImage" => "TRUE",
		     "Font" => "TRUE",
		     "Fore" => "TRUE",
		     "Hilight" => "TRUE",
		     "Image" => "TRUE",
		     "SmallFont" => "TRUE",
		    );
my %WINLIST_OPTIONS = (
		       "Font" => "TRUE",
		       "Fore" => "TRUE",
		       "Back" => "TRUE",
		       "Justify" => "TRUE",
		       "Pixmap" => "TRUE",
		      );
my %LOOK_IMAGE_OPTIONS = (
			  "TitleButton" => "TRUE",
			  "ButtonPixmap" => "TRUE",
			  "MenuPinOn" => "TRUE",
			  "MenuPinOff" => "TRUE",
			  "BackPixmap" => "TRUE",
			 );
###################
# Assumptions
#
# * Uniqueue themes for each desk will not be supported at this time.
# * Modules that support multiple instances must be formed like this:
#   <new_prefix>Pager versus Wharf<bad_suffix>.  Examples might be
#   MyPager, GoodPager, MyWharf not Wharf2, WharfBad, PagerBad


################### 
# Strategy 
# 
# A new themes directory will be placed in the ~/G/L/A/desktop
# directory.  Each new theme will have its own subdirectory under
# that. Each theme's subdirectory will duplicate the ~/G/L/A/desktop
# subdirectores plus put its own "patches" to the module configuration
# files there.  For example, let's say I had a theme called 'foo'. I
# would then have a directory ~/G/L/A/desktop/themes/foo.  Under that
# I would have the 16bpp, 8bpp, common subdirs and possibly 24bpp and
# other bit depths.  Also in the ~/G/L/A/desktop/themes/foo directory
# would be wharf.foo, pager.foo, and winlist.foo.  OK, that sets up
# how the theme data is stored.
#
# Now on the startmenu, in the Decorations submenu would be a new menu
# called "Themes".  When the startmenu is built, it will scan the
# ~/G/L/A/desktop/themes directory to determine what themes are
# "installed".  When the user then selects a theme from the startmenu,
# this theme installer script will then be executed to modify the
# appropriate files in the non-configurable directory.  
#

###################
# Defines
my $AFTERSTEP_DIR="$ENV{'HOME'}/GNUstep/Library/AfterStep";
my $NONCONFIG_DIR="${AFTERSTEP_DIR}/non-configurable";
my $THEME_DIR="${AFTERSTEP_DIR}/desktop/themes";
my $WHARF_FILE="${AFTERSTEP_DIR}/wharf";
my $PAGER_FILE="${AFTERSTEP_DIR}/pager";
my $WINLIST_FILE="${AFTERSTEP_DIR}/winlist";
my $BACKGROUND_FILE="${NONCONFIG_DIR}/0_background";
my $BIT_DEPTH="8bpp";		# This value is later read in from the
                                # sytem 
my $THEME_NAME="$ENV{'USER'}";	# Default theme name is the user name

if ($THEME_NAME eq "") {
  print_usage();
  die "No theme name defined\n";
}


###################
# Flags
my $GET_WHARF="TRUE";
my $GET_PAGER="TRUE";
my $GET_WINLIST="TRUE";
my $GET_BACKGROUND = "TRUE";

##################
# Command Line Syntax Checking

sub print_usage {
  warn "Usage: $0 [--theme <theme_name>] [--no_wharf] [--no_pager] [--no_winlist] [--no_background]\n";
}

if ((scalar(@ARGV) > 7)) {
  warn "Incorrect number of arguments, $ARGV\n";
  print_usage();
  die;
}

while (scalar(@ARGV) >= 1) {
  my $argument = shift;
  if (($argument eq "--theme") and (scalar(@ARGV) >=1)) {
    $THEME_NAME = shift;
    if ($THEME_NAME =~ /^--no_((wharf)|(pager)|(winlist)|(background))/) {
      print_usage();
      die;
    }
  } elsif ($argument eq "--no_wharf") {
    $GET_WHARF = "";
  } elsif ($argument eq "--no_pager") {
    $GET_PAGER = "";
  } elsif ($argument eq "--no_winlist") {
    $GET_WINLIST = "";
  } elsif ($argument eq "--no_background") {
    $GET_BACKGROUND = "";
  } else {
    print_usage();
    die;
  }
}


###################
# Configuration Checking

if ( ! -d $AFTERSTEP_DIR ) {
  warn "Could not find the $AFTERSTEP_DIR directory.\n";
  die "Are you sure you are running AfterStep verion >= 1.5?\n";
}

if ( ! -d $NONCONFIG_DIR ) {
  warn "Could not find $NONCONFIG_DIR directory.\n";
  die "Are you sure you are running AfterStep verion >=1.5?\n";
}

if ( ! -d $THEME_DIR ) {
  mkdir "${THEME_DIR}", 0777 or
    die "Could not find $THEME_DIR directory.\n";
}

if ( ! -d "${THEME_DIR}/${THEME_NAME}" ) {
  mkdir "${THEME_DIR}/${THEME_NAME}", 0777 or
    die "Could not find or make theme ${THEME_NAME} in the ${THEME_DIR} directory, $!\n";
}
$THEME_DIR = "${THEME_DIR}/${THEME_NAME}";

if ($GET_WHARF and ( ! -f $WHARF_FILE )) {
  warn "Cannot fine the Wharf config file, $WHARF_FILE\n";
  warn "Will not create Wharf specific info for theme.\n";
  $GET_WHARF = "";
}

if ($GET_PAGER and ( ! -f $PAGER_FILE )) {
  warn "Cannot find the Pager config file, $PAGER_FILE\n";
  warn "Will not create Pager specific info for theme.\n";
  $GET_PAGER = "";
}

if ($GET_WINLIST and ( ! -f $WINLIST_FILE )) {
  warn "Cannot find the WinList config file, $WINLIST_FILE\n";
  warn "Will not create WinList specific info for theme.\n";
  $GET_WINLIST = "";
}

if ($GET_BACKGROUND and ( ! -f $BACKGROUND_FILE )) {
  warn "Cannot find the image file, $BACKGROUND_FILE\n";
  warn "Will not apply theme to background image\n";
  $GET_BACKGROUND = "";
}

# Get bit depth via xdpyinfo
open (PROC, "xdpyinfo|") or
  die "Cannot start 'xdpyinfo' process, $!\n";
while (<PROC>) {
  # looking for a line that has the key word "depths" on it, as in:
  # screen #0:
  #  dimensions:    1024x768 pixels (347x260 millimeters)
  #  resolution:    75x75 dots per inch
  #  depths (1):    16
  next unless /depths/;
  # strip out all the stuff except the actual bit depth
  chomp;			# and the pesky newlines
  s/\s*depths \((\d+)\):\s*//;
  my @depths = split /,\s/, $_, $1;
  $BIT_DEPTH = $depths[scalar(@depths) -1];
  last;
}
close PROC;

# Check to make sure we got the bit depth from xdpyinfo
unless ($BIT_DEPTH) {
  die "Couldn't figure out bit depth from xdpyinfo\n";
}

# Now that we know the bit depth, we know which look file to
# modify in the non-config directory
my $LOOK_FILE="${NONCONFIG_DIR}/0_look.${BIT_DEPTH}bpp";
my $BASE_FILE="${AFTERSTEP_DIR}/base.${BIT_DEPTH}bpp";

if ( ! -f $LOOK_FILE ) {  
  warn "Cannot find the non-configurable look file for your bit depth, ${LOOK_FILE}\n";
  die "Are you sure you are using AfterStep >= 1.5?\n";
}

if ( ! -f $BASE_FILE ) {
  warn "Cannot find the base file for your depth, $BASE_FILE\n";
  die "Are you sure you are running AfterStep >=1.5?\n";
}

# OK, everything is kocher; let's do the easy stuff first...
# copy the look file from the non-config dir over to our theme dir
open LOOK_SOURCE, "$LOOK_FILE" or
  die "Cannot read from $LOOK_FILE, $!\n";
@look_source = <LOOK_SOURCE>;
close LOOK_SOURCE;
open LOOK_TARGET, ">${THEME_DIR}/look.${THEME_NAME}" or
  die "Cannot write to theme look file ${THEME_DIR}/look.${THEME_NAME}, $!\n";
print LOOK_TARGET @look_source;
close LOOK_TARGET;


# Let's copy the background over to the theme dir
if ($GET_BACKGROUND) {
  open BACKGROUND_SOURCE, "$BACKGROUND_FILE" or
    die "Cannotread from $BACKGROUND_FILE, $!\n";
  open BACKGROUND_TARGET, ">${THEME_DIR}/background.${THEME_NAME}" or
    die "Cannot write to ${THEME_DIR}/background.${THEME_NAME}, $!\n";
  print BACKGROUND_TARGET <BACKGROUND_SOURCE>;
  close BACKGROUND_TARGET;
  close BACKGROUND_SOURCE;
}

# Before we are done with the look file, we need to scan through and
# find any images that need to be copied over to the theme dir.
foreach $line (@look_source) {
  $line =~ /^\s*(\w+)/;
  if ((defined $1) and (exists $LOOK_IMAGE_OPTIONS{$1})) {
    $option = $1;
    if ( $1 eq "BackPixmap" ) {
      $line =~ s/^\s*\w+\s+(\d+)\s+//;
      if ( $1 != "128" ) {
	next;
      }
    } elsif ( $1 eq "TitleButton" ) {
      $line =~ s/^\s*\w+\s+\d\s+//;
      my ($image1, $image2) = split /\s+/, $line, 2;
      my $image_name = get_image ($image1); # Finds which directory in
                                       # the PixmapPath the image is in
      copy_image ($image_name); # Copies the correct image to the
                                # theme dir
      $line = $image2;
    }else {
      $line =~ s/^\s*\w+\s+//;
    }
    chomp $line;
    my $image_name = get_image ($line);
    $return = copy_image ($image_name);
    if ($return) {
      warn "Could not copy '$image_name' from option $option in $LOOK_FILE\n";
    }
  }
}


# OK, now we are going to scan through the wharf, pager, and winlist
# config files looking for the options we think belong in a theme.
# When we find one, we will strip off the module name and write only
# the option name and the rest of the line to the theme file

if ($GET_WHARF) {
  open WHARF_THEME, ">${THEME_DIR}/wharf.${THEME_NAME}" or
    die "Cannot write to the ${THEME_DIR}/wharf.${THEME_NAME}\n";
  open WHARF_FILE, "$WHARF_FILE" or
    die "Cannot read from $WHARF_FILE, $!";
  while(<WHARF_FILE>) {
    s/^\*(\w*Wharf)(\w+)/$2/;	# the stuff in () is the option to
                                # match on.
    if ((defined $2) and (exists $WHARF_OPTIONS{$2})) {
      my $option = $2;
      print WHARF_THEME;
      if ( $2 eq "Pixmap" ) {
	s/^Pixmap\s+//;
	chomp;
	my $image_name = get_image ($_); # Finds which directory in
                                         # the PixmapPath the image is in
	my $return = copy_image ($image_name); # Copies the correct image to the
                                  # theme dir
	if ($return) {
	  die "Could not copy '$image_name' from option $option in $WHARF_FILE\n"
	}
      }
    }
    /./;			# clears the patter matching variables
  }
  close WHARF_FILE;
  close WHARF_THEME;
}

if ($GET_PAGER) {
  open PAGER_THEME, ">${THEME_DIR}/pager.${THEME_NAME}" or
    die "Cannot write to the ${THEME_DIR}/pager.${THEME_NAME}\n";
  open PAGER_FILE, "$PAGER_FILE" or
    die "Cannot read from $PAGER_FILE, $!";
  while(<PAGER_FILE>) {
    s/^\*(\w*Pager)(\w+)/$2/;	# the stuff in () is the option to
                                # match on.
    if ((defined $2) and (exists $PAGER_OPTIONS{$2})) {
      $option = $2;
      print PAGER_THEME;
      if ($option =~ /Image$/) {
	s/^.*Image\s+(\d+)\s+//;
	chomp;
	if (m!~/GNUstep/Library/AfterStep/non-configurable/\d_background!) {
	  next;
	} else {
	  my $image_name = get_image ($_); # Finds which directory in
                                         # the PixmapPath the image is in
	  my $return = copy_image ($image_name); # Copies the correct image to the
                                  # theme dir
	  if ($return) {
	    warn "Could not copy the '$image_name' from the option $option in $PAGER_FILE\n";
	  }
	}
      }
    }
    /./;			# clears the pattern matching variables
  }
  close PAGER_FILE;
  close PAGER_THEME;
}

if ($GET_WINLIST) {
  open WINLIST_THEME, ">${THEME_DIR}/winlist.${THEME_NAME}" or
    die "Cannot write to the ${THEME_DIR}/winlist.${THEME_NAME}\n";
  open WINLIST_FILE, "$WINLIST_FILE" or
    die "Cannot read from $WINLIST_FILE, $!";
  while(<WINLIST_FILE>) {
    s/^\*(\w*Winlist)(\w+)/$2/;	# the stuff in () is the option to
                                # match on.
    if ((defined $2) and (exists $WINLIST_OPTIONS{$2})) {
      print WINLIST_THEME;
    }
    if ((defined $2) and ($2 eq "Pixmap")) {
	chomp;
	s/^.*Pixmap\s+//;
	my $image_name = get_image ($_); # Finds which directory in
				# the PixmapPath the image is in
	my $return = copy_image ($image_name); # Copies the correct
                                               # image to the theme
                                               # dir
	if ($return) {
	  warn "Could not copy the '$image_name' from the option $option in $PAGER_FILE\n";
	}
      }
    /./;			# clears the patter matching variables
  }
  close WINLIST_FILE;
  close WINLIST_THEME;
}



chdir("${THEME_DIR}/..") or
  die "Can't change to ${THEME_DIR}/.. directory, $!\n";
system("tar cf ${THEME_NAME}.tar ${THEME_NAME}");
system("gzip -f ${THEME_NAME}.tar");

sub get_image {
  my @pixmap_path;
  my $image_name = shift;
  
  $image_name =~ s/^~/$ENV{'HOME'}/; # perl doesn't grok the '~'
  $image_name =~ s/\s*$//;		# gotta remove any trailing white space
  if ( -e $image_name ) {
    return $image_name;
  }
  
  open BASE_FILE, $BASE_FILE or
    die "Cannot read from $BASE_FILE, $!\n";
  
  while(<BASE_FILE>) {
    next unless (/^PixmapPath/);
    chomp;
    s/^PixmapPath\s+//;
    s/~/$ENV{'HOME'}/g;	      # Perl doesn't grok '~'
    @pixmap_path = split /:/; # This stores the directories in the
                              # pixmap path in an array that can be
                              # searched for the necessary image.
    last;
  }
  close BASE_FILE;
  @found_icons = grep { -e ($_ = "$_/$image_name") } @pixmap_path;
  my $match = $found_icons[0];
  if ($match eq "") {
    warn "Could not find $image_name\n";
    return -1;
  } else {
    return $match;	# This returns the first found image
  }
}

sub copy_image {
  my $image_name = shift;
  $image_name =~ m!([^/]*)$!;
  my $base_name = $1;

  
  open IMAGE_SOURCE, $image_name or do {
    warn "Cannot read from $image_name, $!\n";
    return 1;
  };
  open IMAGE_TARGET, ">${THEME_DIR}/${base_name}" or do {
    warn "Cannot write to ${THEME_DIR}/${base_name}, $!\n";
    return 1;
  };

  print IMAGE_TARGET <IMAGE_SOURCE>;
  close IMAGE_SOURCE;
  close IMAGE_TARGET;
  return 0;
}
