#!/usr/bin/perl
#
# ag_sane
# This script is part of the YaST2 Scanner installation module
# Copyright SuSE Gmbh - 2001
#
# Author(s): Klaas Freitag <freitag@suse.de>
#            Gabi Strattner <gs@suse.de>
#
# $Id: ag_sane,v 1.33 2004/03/08 16:25:14 gs Exp $
#

BEGIN { unshift @INC, "/usr/lib/YaST2/agents_non_y2/" ;
	unshift @INC, "/usr/lib/YaST2/servers_non_y2/" ; }

use ycp;
use strict;

use scannerDB;

# ##############################################################################
#
# ag_sane offers the following actions, selected by the calling 'path' in ycp,
# which is mapped to the perl var $action in this script.
#
# driver
# ======
#
# Required parameter: bus, vendor, model.
#
# Action driver delivers the correct driver for a scanner identified by the bus
# the scanner is connected to, the model and the vendor.
#
# The return-value is a string containing the driver name or an empty string on
# error.
# Bus 'net' is not supported.
#
#
# modellist
# =========
#
# Required parameter: bus, vendor
#
# modellist returns a sorted list of models of a vendor for a bus. If the vendor
# is an empty string, the 'generic' vendor is assumed and a list of all available
# drivers is returned.
# Bus 'net' is not supported.
#
# vendorlist
# ==========
#
# Required parameters: bus
#
# returns a list of all vendors for which models/drivers on the bus exist.
# Bus 'net' is not supported.
#
# writeconfig
# ===========
#
# Required parameter: driver, vendor, device, bus
#
# adds one backend to the system wide driver list for sane in /etc/sane.d/dll.conf
# and writes the individual config file in /etc/sane.d/{backend}.conf
#
# returns a ycp boolean
#
# scanimage
# =========
#
# Required Parameter: driver, devicefile, host in case of network scanner
#
# Scans a test image and returns the filename where the image is saved.
# The file format of the image is pnm.
#
# netscannerinfo
# ==============
#
# Required Parameter: bus(=net), host
#
# returns a list of maps with scanner descriptions of the remote scanners connected to
# the work station 'host'.
#
# firmware
# ========
# 
# Required Parameter: scanner_driver
#
# Returns either strings none, all or some.
# That says if the scanners served by the driver require a firmware file configured
# in their .conf file.
#
# ##############################################################################



while ( <STDIN> )
{
    ycpDoVerboseLog();

    if( /result/i )
    {
	y2debug("got result -> say goodbye!");
	exit(0);
    }

    my ($action, $path, $argument) = ycp::ParseCommand ($_);
    
    y2debug( " vvv starting ag_sane with action <$action> <$path> vvv" );

    #unless( ycpArgIsMap() )
    #{
    #	y2debug( "Argument seems not to be a Map from ycp" );
    #}

    my %scanner;
    my $vendor;
    my $bus;
    my $model;

    if ( ref ($argument) eq "HASH" )
    {
	%scanner = %{$argument};
	$vendor = findInHash( "vendor", \%scanner );
	$bus    = findInHash( "bus", \%scanner  );
	$model  = findInHash( "device", \%scanner );
	if( ! defined( $vendor ) )
	{
	    $vendor = findInHash( "sub_vendor", \%scanner );
	}
	if( ! defined( $model ) )
	{
	    $model = findInHash( "sub_device", \%scanner );
	}
    }

    #Read command
    if ( $action eq "Read" ) {
      if ( $path =~ /^\s*\.*driver\s*$/i ) {
	#
	# This action queries for the correct driver for one scanner
	# identified by its vendor and the model, both values come as
	# parameters.
	y2debug( "Bus is $bus" );
	y2debug( "Model is $model" );
	y2debug( "Vendor is $vendor" );

	my %models = getModel( $bus, $vendor);

	while ( my ($model, $driver) = each %models ) {
	  y2debug( "Use <$driver> for <$model>" );
	}

	my $use_driver = "";
	$use_driver = findInHash( $model, \%models );

	# If no entry was found regularly, try a version of the model without any
	# whitespaces. That makes for example Perfection1200 from 'Perfection 1200'
	# Seems to be common with Epson, that they skip the whitespaces.
	if ( $use_driver eq "" ) {
	  my $wsfree = $model;
	  $wsfree =~ s/\s//g;
	  y2debug( "Found no driver for <$model>, try whitespace free <$wsfree>" );
	  # And then, try again...
	  $use_driver = findInHash( $wsfree, \%models );
	}
	y2debug( "Returning <$use_driver>" );

	ycp::Return( $use_driver );

	# my $retdriver = $driver;
      } elsif ( $path =~ /firmware\s*$/ ) {
	  my $fw = "none";
	  my $driver = findInHash( "scanner_driver", \%scanner );

	  if( $driver eq "" ) 
	  {
	      y2error("Param driver required for firmware!");
	  }
	  else
	  {
	      $fw = "some" if( $driver =~ /^\s*snapscan\s*$/i );
	      $fw = "all"  if( $driver =~ /^\s*artec_eplus48u\s*/ ||
			       $driver =~ /^\s*gt68xx\s*/ );
	  }
	 
	  ycp::Return( $fw );

      } elsif ( $path =~ /modellist\s*$/ ) {
	# Only the vendor and the bus must be set in the incoming parameter hash -
	# returning a list of available drivers.
	y2debug( "Handling action modellist" );

	if ( !defined $vendor || $vendor =~ /^\s+$/  ) {
	  y2debug("Vendor string is empty -> assume 'generic'" );
	  $vendor = "generic";
	}
	my %models = getModel( $bus, $vendor);

	my @drivers;

	@drivers = sort keys %models;

	ycp::Return( \@drivers );
      } elsif ( $path =~ /vendorlist/ ) {
	y2debug( "Handling action vendorlist" );
	# Only the bus is required. Return a list of vendors for the list.
	my @vlist = getVendorList( findInHash( "bus", \%scanner ));
	ycp::Return( \@vlist );
      } elsif ( $path =~ /netscannerinfo/i ) {
	y2debug( "Handling action netscannerinfo" );
	unless ( $bus =~ /net/i )
	  {
	    y2debug( "bus is not net !" );
	  }
	my $host = findInHash( "host", \%scanner );

	if ( defined ( $host ) ) {
	  my @netscanners_on_host = getNetInfo( $host );
	  my $found_scanners_anz = @netscanners_on_host;

	  y2debug( "Found $found_scanners_anz net scanners" );
	  if ( $found_scanners_anz > 0 ) {
	    enableNetScan( $host );
	  }
	  ycp::Return( \@netscanners_on_host );
	} else {
	  y2debug( "No host defined for netscannerinfo!" );
	  ycp::Return( [] );
	}
      } else {
	y2error( "Unknown action <$path>" );
	ycp::Return ( "false" );
      }
    }  

    # Write command
    elsif ( $action eq "Write" ) {
      if ( $path =~ /writeconfig/ ) {
	y2debug( "Handling action writeconfig" );
	my @cfg_backends = readDllconf( );
	my $ok = 0;

	if ( $bus =~ /net/i ) {
	  my $host = findInHash( "host", \%scanner );
	  y2debug( "Installing a net scanner on host <$host> !" );

	  if ( defined $host ) {
	    $ok = enableNetScan( $host );
	  } else {
	    y2error( "ERROR: Host is not defined or empty!" );
	    $ok = 0;
	  }
	  # ATTENTION: Return here :(
	  $ok?ycp::Return( "true" ):ycp::Return( "false" );
	}


	# Not net !
	my $driver = findInHash( "scanner_driver", \%scanner );
	my $devicefile = findInHash( "dev_name", \%scanner );
	y2milestone( "Installing driver <$driver> for scanner <$vendor/$model> on <$devicefile>" );

	if ( grep( /$driver/, @cfg_backends ) ) {
	  y2debug( "Backend <$driver> is already configured!" );
	  $ok = 1;
	} else {
	  y2debug( "Backend <$driver> is not configured, adding it" );
	  push @cfg_backends, $driver;

	  $ok = writeDllconf( \@cfg_backends );
	}

	# now the scanner conf:
	$ok = $ok && writeIndividualConf( $bus, $driver, $devicefile );

	# valid are:
	# vendor-bus-model

	$ok?ycp::Return( "true" ):ycp::Return( "false" );
      }
      else {
	y2error( "Unknown action <$path>" );
	ycp::Return( "false" );
      }
    }

    # Execute command
    elsif ( $action eq "Execute" ) {
      if ( $path =~ /revertall/ ) {

	y2debug( "Handling action revert all" );
	revertAll();
        ycp::Return( "true" );
      } elsif ( $path =~ /removeDriver/ ) {
	my $ok = 0;
	my $driver = findInHash( "scanner_driver", \%scanner );

	y2debug( "Handling action removeDriver" );

	# If a net scanner is to remove, just delete it from net.conf
	if ( $bus =~ /^\s*net\s*$/i ) {
	  my $host = findInHash( "host", \%scanner );
	  if ( defined $host ) {
	    y2debug( "Going to remove net scanning on <$host>" );
	    $ok = disableNetScan( $host );
	  } else {
	    y2debug( "Property Host not defined in scanner map" );
	  }
	} else {
	  # If not net scanner, remove from dll.conf
	  if ( defined $driver  ) {
	    my @existing  = readDllconf();
	    my $driver_found = 0;

	    my @writeDll = ();
	    foreach my $exist_driver ( @existing )
	      {
		if ( $driver =~ /$exist_driver/i ) {
		  y2debug( "Removing <$driver> from existing list" );
		  $driver_found++;
		  next;		# continue in loop
		}
		push @writeDll,  $exist_driver;
	      }
	    if ( $driver_found > 0 ) {
	      $ok = writeDllconf( \@writeDll );
	    } else {
	      y2debug("Driver to remove was not found in existing list!" );
	      # but return true :)
	      $ok = 1;
	    }
	  } else {
	    y2error( "ERROR: Driver was not given but is a required argument for removeDriver!" );
	  }
	}
	$ok?ycp::Return( "true" ):ycp::Return( "false" );

      } elsif ( $path =~ /scanimage/ ) {
	y2debug( "Handling action scanimage" );
	my $resFile = "";
	my $devicefile = findInHash( "dev_name", \%scanner );
	if ( !defined $devicefile ) 
	{
	    $devicefile = "";
	}
	my $driver = findInHash( "scanner_driver", \%scanner );
	my $tmpdir = findInHash( "tmpdir", \%scanner );
	y2debug( "Scanning to temp-dir: $tmpdir" );
	if ( !defined $driver || $driver eq "" || !defined $devicefile ) {
	  y2error( "Driver or devicefile is not defined - can not scan !" );
	} else {
	  my $devstring = sprintf( "%s:%s", lc $driver, $devicefile );

	  if ( $bus =~ /net/i ) {
	    my $host = findInHash( "host", \%scanner );
	    if (defined $host) {
	      $devstring = "net:" . $host .":". $devstring;
	    } else {
	      y2error( "ERROR: Tried to scan net, but no host given !" );
	      $devstring = undef;
	    }
	  }

	  if ( defined $devstring ) {
	    $resFile = acquireTestImage( $devstring, $tmpdir );

	    y2milestone( "Test image - device <$devstring>, result-file <$resFile>" );
	  }
	}
	ycp::Return( $resFile );

      } else {
	y2error( "Unknown action <$path>" );
	ycp::Return ( "false" );	
      }
    } 
    
    # Dir command
    elsif ( $action eq "Dir" ) {
	my @paths = ("driver","modellist","vendorlist","netscannerinfo","writeconfig","revertall","scanimage");
	ycp::Return( \@paths );
      }
    
    # Result
    elsif ( $action eq "result" ) {
	exit;
    }

    # Unknown
    else {
        y2error ("Unknown instruction ", ycpGetCommand, " or argument: ", ycpGetArgType);
        ycp::Return ( "false" );
    }
}

# EOF
