#!/usr/bin/perl
#------------------------------------------------------------ 
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------ 

use strict;
use Getopt::Std;
use IO::File;
use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::Util qw(trimspaces clean normalize_upc normalize_isrc normalize_date);
use Common::RSDB;
use Common::RSApp;
use Common::Assert;
use Common::TextProgressBar;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Artist;
use RPS::DB::Item::ArtistContractTermReserve;
use RPS::DB::Item::BonusTrack;
use RPS::DB::Item::LicenseReserve;
use RPS::DB::Item::MechanicalStatementItem;
use RPS::DB::Item::Label;
use RPS::DB::Item::Track;
use RPS::DB::Item::Album;
use RPS::DB::Item::Product;
use RPS::DB::Item::ProductTrack;
use RPS::DB::Item::Master;
use RPS::DB::Item::Song;
use RPS::DB::Item::Composer;


use constant kFileFormatXML => 999;
my @gHeaders =
(
	["album-name", "album-artist", "label-name", "catalog-no", "cd-product-id", "cd-upc", "digital-product-id", "digital-upc", "vinyl-product-id", "vinyl-upc", "dvd-product-id", "dvd-upc", "release-date", "album-custom-1", "album-custom-2", "album-custom-3", "track-name", "disc-no", "disc-name", "track-no", "track-minutes", "track-seconds", "track-artist", "isrc", "genre", "track-custom-1", "track-custom-2", "track-custom-3"],
);


# reporting flags and variable
#
use constant kQuiet => 0;
use constant kNormal => 1;
use constant kVerbose => 2;
use constant kDebug => 3;
my $gReportLevel = kVerbose;

use constant kProgressQuanta => 100;


# Parse the command-line.
#
my ($clientID, $catalogFile, $commit) =  parseCommandLine();


# Instantiate the application singleton object.
#
my $appSingleton = Common::RSApp->new(clientID => $clientID);


# Scan the catalog file, and build the data structure of updates.
#
my %updates;
scanCatalogFileForUpdates($catalogFile, \%updates);


#
# --- Subroutines
#


sub parseCommandLine
{
    my %opt;
    getopts('c:f:e', \%opt);

    my $catalogFile = $opt{f};
    my $clientID = $opt{c};
    my $commit   = $opt{e};

    unless ($clientID =~ /^\d+$/ && $clientID > 0)
    {
	    die usage("You must specify a valid client ID");
    }

    unless ($catalogFile)
    {
	    die usage("You must specify a catalog file to import");
    }

    unless (-e $catalogFile)
    {
	    die usage("The specified catalog file does not exist");
    }

    return ($clientID, $catalogFile, $commit);
}


sub usage
{
	my $errstr = shift;
	my $text = ($errstr) ? "ERROR: $errstr\n" : '';
	$text .= "Usage: $0 -c <clientID> -f <catalogFile> [-e]\n       -e executes/commits an update\n";
	return $text;
}


sub scanCatalogFileForUpdates
{
    my ($catalogFilePath, $updates) = @_;
    assert($catalogFilePath);
    assert($updates);


    # Open the catalog file for reading.
    #
    my $catalogFile = IO::File->new($catalogFile) || die "Can't open catalog file '$catalogFile': $!\n";


    # Examine the first line - This should contain the field headers.
    # And will tell us whether we're looking at a tab-seperated file, or XML.
    #
    my $format = determineFileType($catalogFile);

    if (kFileFormatXML == $format)
    {
        readXMLCatalogFile($catalogFile, $updates);
    }
    else
    {
        print "FORMAT = $format\n";
        # !!! Probably want to seed this read method with the field definitions.
        #
        readTabSeperatedCatalogFile($catalogFile, $format);
    }


    # Done with the catalog file, close it.
    #
    $catalogFile->close();
}


sub determineFileType
{
    my ($file) = @_;
    assert($file);

    # Read the first line from the file.
    #
    my $line = <$file>;
    die "ERROR - empty catalog file!\n" unless $line;
    chomp $line;

    my @fields = split("\t", $line);
   	@fields = trimquotes(@fields);
   	@fields = escapequotes(@fields);


    report("Examining file header...");


    # First, see if this file contains XML - should be easy to tell.
    #
    if ($line =~ m/\^<catalog\>/)
    {
        report("  File is XML");
        return kFileFormatXML;
    }


    # Try to match the fields to one of our known header configurations.
    #
    my $match;
    my $formats = scalar @gHeaders;
		
    my $format = 0;
    while ($format < $formats && !$match)
    {
        my $fields = @fields;
    	$match = 1;
        my $i;
		for ($i = 0; $i < $fields; $i++)
		{
			if (! defined $gHeaders[$format]->[$i])
            {
				$match = 0;
				last;
            }
            
            if ($fields[$i] !~ m/$gHeaders[$format]->[$i]/i)
			{
				$match = 0;
				last;
			}
		}
		if (!$match)
		{
			$format++;
		}
	}
	if (!$match)
	{
		die "Unrecognized file format. Header:\n$line\n";
	}

    report("  File is tab-delimited");
    report("  format = $format", kDebug);

    return $format;
}


sub readXMLCatalogFile
{
    my ($file, $updates) = @_;
    assert($file);
    assert($updates);

    die "--- NOT YET IMPLEMENTED---\n";
}


sub readTabSeperatedCatalogFile
{
    my ($file, $format) = @_;
    assert($file);

	exit unless ($format == 0);

    report("Processing catalog file");

    my %inserted_albums;
    my $last_album;
    my (%album_info, %track_info);
    my %err_on_album;

    my $recordCount = 0;
    # Process the file line by line
    while (my $record = <$file>) 
    {
	    my @fields;
        $recordCount++;

        #if (0 == $recordCount % kProgressQuanta)
        #{
            #report("  record $recordCount ... ", kVerbose);
        #}

        # Split the line up into fields.
    	chomp $record;
    	@fields = split("\t", $record);
    	@fields = trimquotes(@fields);
    	@fields = escapequotes(@fields);

        # Parse the fields, based on the expected field order.
		my ($albumName, $albumArtist, $labelName, $catalogID,
            $productIdCD, $upcCD, $productIdDigital, $upcDigital, $productIdVinyl, $upcVinyl, $productIdDVD, $upcDVD,
            $releaseDate, $albumCustom1, $albumCustom2, $albumCustom3,
			$trackName, $discNumber, $discName, $trackNumber, $trackMinutes, $trackSeconds, $trackArtist, $isrc,
            $genre, $trackCustom1, $trackCustom2, $trackCustom3) = undefspaces(@fields);

        unless (defined $catalogID) {
            report("missing catalogID: @fields");
            next;
        }

        ## check if $catalogID already in system
        my $isAlbumInSystem = RPS::DB::Item::Album->Lookup(catalog_number => $catalogID);
        if ($isAlbumInSystem) {
            report("album $catalogID is already in system");
            $err_on_album{$catalogID} = 1;
            next;
        }

        unless (defined $albumName && defined $albumArtist && defined $labelName) {
            report("missing album name, artist, or label on $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }
        unless (defined $trackName && defined $trackArtist) {
            report("missing track name or artist on $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }
        unless ($trackNumber =~ m/^\d+$/ && $discNumber =~ m/^\d+$/) {
            report("missing or invalid track/disc numbers for $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }
        unless ($trackMinutes =~ m/^\d*$/ && $trackSeconds =~ m/^\d*$/) {
            report("invalid min/sec values for $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }

        if ($upcCD && !$productIdCD) {
            report("incomplete CD specs for $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }
        if ($upcDigital && !$productIdDigital) {
            report("incomplete Digital specs for $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }
        if ($upcVinyl && !$productIdVinyl) {
            report("incomplete Vinyl specs for $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }
        if ($upcDVD && !$productIdDVD) {
            report("incomplete DVD specs for $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }

        unless ($productIdCD || $productIdDigital || $productIdVinyl || $productIdDVD) {
            report("no products specified for $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }
        
        if ($upcCD ne "") {
            $upcCD = "0".$upcCD if (length $upcCD == 11);
            if ($upcCD ne normalize_upc($upcCD)) {
                report("bad upc check digit on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif (length $upcCD != 12) {
                report("upc of wrong length on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            }
        }
        if ($upcDigital ne "") {
            $upcDigital = "0".$upcDigital if (length $upcDigital == 11);
            if ($upcDigital ne normalize_upc($upcDigital)) {
                report("bad upc check digit on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif (length $upcDigital != 12) {
                report("upc of wrong length on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            }
        }
        if ($upcVinyl ne "") {
            $upcVinyl = "0".$upcVinyl if (length $upcVinyl == 11);
            if ($upcVinyl ne normalize_upc($upcVinyl)) {
                report("bad upc check digit on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif (length $upcVinyl != 12) {
                report("upc of wrong length on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            }
        }
        if ($upcDVD ne "") {
            $upcDVD = "0".$upcDVD if (length $upcDVD == 11);
            if ($upcDVD ne normalize_upc($upcDVD)) {
                report("bad upc check digit on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif (length $upcDVD != 12) {
                report("upc of wrong length on $catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            }
        }

		my $duration = ($trackMinutes * 60) + $trackSeconds;

        $releaseDate = normalize_date($releaseDate);

        if ($releaseDate ne '' && $releaseDate !~ m/^\d\d\d\d-\d\d-\d\d/) {
            report("badly formatted release date on $catalogID");
            $err_on_album{$catalogID} = 1;
            next;
        }


        if (defined $last_album && $last_album ne $catalogID) {
            if (exists $inserted_albums{$catalogID}) {
                report("skipping duplicated or out-of-order album $catalogID");
                next;
            }

            ## process/insert %album_info and %track_info (for last album)
            if ($err_on_album{$last_album} == 0) {
                if ($commit) {
                    processAlbum($last_album, \%album_info, \%track_info);
                    report ("album $last_album inserted");
                }
            }
            %album_info = ();
            %track_info = ();
            $inserted_albums{$last_album} = 1;

        }
        $last_album = $catalogID;

		if (!exists($inserted_albums{$catalogID})) 
        {
			$album_info{albumName}		  = $albumName;
			$album_info{albumArtist}	  = $albumArtist;
			$album_info{labelName}		  = $labelName;
			$album_info{catalogID}		  = $catalogID;
			$album_info{releaseDate}	  = $releaseDate;
			$album_info{albumCustom1}     = $albumCustom1;
			$album_info{albumCustom2}	  = $albumCustom2;
			$album_info{albumCustom3}	  = $albumCustom3;
            $album_info{productIdCD}      = $productIdCD;
            $album_info{productIdDigital} = $productIdDigital;
            $album_info{productIdVinyl}   = $productIdVinyl;
            $album_info{productIdDVD}     = $productIdDVD;
            $album_info{upcCD}            = $upcCD;
            $album_info{upcDigital}       = $upcDigital;
            $album_info{upcVinyl}         = $upcVinyl;
            $album_info{upcDVD}           = $upcDVD;
		}
		else
		{
			if ($album_info{$catalogID}->{albumName} ne $albumName) {
				report("Album name varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
			} elsif ($album_info{$catalogID}->{albumArtist} ne $albumArtist) {
				report("Artist name varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$catalogID}->{labelName} ne $labelName) {
				report("Label name varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$catalogID}->{releaseDate} ne $releaseDate) {
				report("Release date varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$productIdCD}->{releaseDate} ne $productIdCD) {
				report("CD product ID varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$productIdDigital}->{releaseDate} ne $productIdDigital) {
				report("Digital product ID varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$productIdVinyl}->{releaseDate} ne $productIdVinyl) {
				report("Vinyl product ID varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$productIdDVD}->{releaseDate} ne $productIdDVD) {
				report("DVD product ID varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$upcCD}->{releaseDate} ne $upcCD) {
				report("CD UPC varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$upcDigital}->{releaseDate} ne $upcDigital) {
				report("Digital UPC varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$upcVinyl}->{releaseDate} ne $upcVinyl) {
				report("Vinyl UPC varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            } elsif ($album_info{$upcDVD}->{releaseDate} ne $upcDVD) {
				report("DVD UPC varies: album ID=$catalogID");
                $err_on_album{$catalogID} = 1;
                next;
            }
		}

		if (!exists($track_info{$discNumber}->{$trackNumber}->{trackName}))
		{
			$track_info{$discNumber}->{$trackNumber}->{trackName}	= $trackName;
			$track_info{$discNumber}->{$trackNumber}->{duration}	= $duration;
			$track_info{$discNumber}->{$trackNumber}->{trackArtist}	= $trackArtist;
			$track_info{$discNumber}->{$trackNumber}->{isrc}		= $isrc;
			$track_info{$discNumber}->{$trackNumber}->{genreName}	= $genre;
			$track_info{$discNumber}->{$trackNumber}->{trackCustom1}= $trackCustom1;
			$track_info{$discNumber}->{$trackNumber}->{trackCustom2}= $trackCustom2;
			$track_info{$discNumber}->{$trackNumber}->{trackCustom3}= $trackCustom3;
		}
		else
		{
			report("Duplicate track: album ID=$catalogID, track ${discNumber}.${trackNumber}");
            #print "$catalogID ${discNumber}.${trackNumber} ".($track_info{$discNumber}->{$trackNumber}->{trackName})."\n";
            $err_on_album{$catalogID} = 1;
            next;
		}
	}
    ## process/insert %album_info and %track_info (for last album)
    if ($err_on_album{$last_album} == 0) {
        if ($commit) {
            processAlbum($last_album, \%album_info, \%track_info);
            report ("album $last_album inserted");
        }
    }
    ##
    report("\n\n  $recordCount records processed\n\n");
    foreach my $id (keys %err_on_album) {
        report("album $id skipped due to errors") if ($err_on_album{$id} != 0);
    }

    unless ($commit) {
        report("\ncorrect any problems (if necessary) and re-run with the -e option to commit");
    }
}


sub processAlbum
{
    my ($catalogID, $album, $tracks) = @_;


    my %artistNameIDHash;

    # report("ALBUM DATA $albumID: " . Dumper($albums->{$albumID}));

    # Before we create the album entry, we first have to 
    # - create the label (if necessary)
    # - create the artist (if necessary)
    #

    # Does this label exist already?
    #
    my $labelName = $album->{labelName};
    my $labelDBItem = RPS::DB::Item::Label->Lookup(label_name => $labelName);
    if (! $labelDBItem)
    {
        $labelDBItem= RPS::DB::Item::Label->Create(
            label_name => $labelName,
            label_name_clean => clean($labelName),
        );
        $labelDBItem->save();
    }
    my $labelID = $labelDBItem->label_id;


    # Does this artist exist already?
    #
    my $artistName = $album->{albumArtist};
    my $artistDBItem = RPS::DB::Item::Artist->Lookup(name => $artistName);
    if (! $artistDBItem)
    {
        $artistDBItem = RPS::DB::Item::Artist->Create(
            name => $artistName,
            name_clean => clean($artistName),
        );
        $artistDBItem->save();
    }
    my $artistID = $artistDBItem->artist_id;


    my $newAlbum = RPS::DB::Item::Album->Create(
      catalog_number => $album->{catalogID},
      title => $album->{albumName},
      title_clean => clean($album->{albumName}),
      artist_id => $artistID,
      label_id => $labelID,
      custom_1 => $album->{albumCustom1},
      custom_2 => $album->{albumCustom2},
      custom_3 => $album->{albumCustom3},
      company_id  => $album->{albumCustom1},
      vendor_id   => $album->{albumCustom2},
      location_id => $album->{albumCustom3},
      status => 1, # 1=active
      
    );
    $newAlbum->save();

    my $albumID = $newAlbum->album_id;

    # Now create a corresponding digital product (for the album).

    my ($albumDigitalProductID, $albumCDProductID, $albumVinylProductID, $albumDVDProductID);
    if ($album->{productIdDigital})
    {
        my $newDigProduct = RPS::DB::Item::Product->Create(
         #product_id => $album->{albumProductID},
         asset_id => $albumID,
         upc_ean => $album->{upcDigital},
		 release_date => $album->{releaseDate},
         product_type_id => RPS::DB::Item::Product::kProductTypeDigital,       # 3 == digital
         product_status_id => 1,     # 1 == active
         # product_price_id => 1,     # 1 == full (the default) # don't set this at all -jff-
         product_code => $album->{productIdDigital},
        );
        $newDigProduct->save();
        $albumDigitalProductID = $newDigProduct->product_id;
    }

        
    if ($album->{productIdCD})
    {
        my $newPhysProduct = RPS::DB::Item::Product->Create(
         #product_id => $album->{physicalCDProductID},
         asset_id => $albumID,
         upc_ean => $album->{upcCD},
		 release_date => $album->{releaseDate},
         product_type_id => RPS::DB::Item::Product::kProductTypeCD,       # 2 == cd 
         product_status_id => 1,     # 1 == active
         # product_price_id => 1,     # 1 == full (the default) # don't set this -jff-
         product_code => $album->{productIdCD},
        );
        $newPhysProduct->save();
        $albumCDProductID = $newPhysProduct->product_id;
    }

    if ($album->{productIdVinyl})
    {
        my $newPhysProduct = RPS::DB::Item::Product->Create(
         #product_id => $album->{physicalLPProductID},
         asset_id => $albumID,
         upc_ean => $album->{upcVinyl},
		 release_date => $album->{releaseDate},
         product_type_id => RPS::DB::Item::Product::kProductTypeLP,
         product_status_id => 1,     # 1 == active
         # product_price_id => 1,     # 1 == full (the default) # don't set this -jff-
         product_code => $album->{productIdVinyl},
        );
        $newPhysProduct->save();
        $albumVinylProductID = $newPhysProduct->product_id;
    }

    if ($album->{productIdDVD})
    {
        my $newPhysProduct = RPS::DB::Item::Product->Create(
         #product_id => $album->{physicalDVDProductID},
         asset_id => $albumID,
         upc_ean => $album->{upcDVD},
	     release_date => $album->{releaseDate},
         product_type_id => RPS::DB::Item::Product::kProductTypeDVD,
         product_status_id => 1,     # 1 == active
         # product_price_id => 1,     # 1 == full (the default) # don't set this -jff-
         product_code => $album->{productIdDVD},
        );
        $newPhysProduct->save();
        $albumDVDProductID = $newPhysProduct->product_id;
    }

    # Create/update track entries
    #
    foreach my $disc_no (keys %$tracks) {
        foreach my $track_no (keys %{$$tracks{$disc_no}}) {

            my $trackArtistName = $tracks->{$disc_no}->{$track_no}->{trackArtist};
    
            # Does this artist exist already?
            #
            my $artistDBItem = RPS::DB::Item::Artist->Lookup(name => $trackArtistName);
            if (! $artistDBItem)
            {
                $artistDBItem = RPS::DB::Item::Artist->Create(
                    name => $trackArtistName,
                    name_clean => clean($trackArtistName),
                );
                $artistDBItem->save();
            }
            my $trackArtistID = $artistDBItem->artist_id;
    
            # We need to create a Master for this track, because that's where track length is stored.
            # I guess that means that we want to create a Song for this track, too.
            # We'll just do our best, and see what happens.
            #
    
            my $newSong = RPS::DB::Item::Song->Create(title => $tracks->{$disc_no}->{$track_no}->{trackName});
            $newSong->save();
            my $trackSongID = $newSong->song_id;
    
    
            my $newMaster = RPS::DB::Item::Master->Create(
                song_id => $trackSongID,
                title => $tracks->{$disc_no}->{$track_no}->{trackName},
                artist_id => $trackArtistID,
                isrc => $tracks->{$disc_no}->{$track_no}{isrc},
                duration => $tracks->{$disc_no}->{$track_no}{duration},
            );
            $newMaster->save();
            my $trackMasterID = $newMaster->master_id;
    
    
            my $newTrack = RPS::DB::Item::Track->Create(
                title => $tracks->{$disc_no}->{$track_no}{trackName},
                title_clean => clean($tracks->{$disc_no}->{$track_no}{trackName}),
                album_id => $albumID,
                artist_id => $trackArtistID,
                track_order => $track_no,
                genre_name => $tracks->{$disc_no}->{$track_no}{genreName},
                custom_1 => $tracks->{$disc_no}->{$track_no}{trackCustom1},
                custom_2 => $tracks->{$disc_no}->{$track_no}{trackCustom2},
                custom_3 => $tracks->{$disc_no}->{$track_no}{trackCustom3},
                master_id =>  $trackMasterID,
            );
            $newTrack->save();
    
            my $trackID = $newTrack->track_id;
    
    
            # Now create a corresponding digital product for this track.

            if ($albumDigitalProductID) {
                my $newProduct = RPS::DB::Item::Product->Create(
                    #product_id => $tracks->{$trackID}{trackProductID},
                    asset_id => $trackID,
                    product_type_id => RPS::DB::Item::Product::kProductTypeDigitalTrack,       # 4 == digital track
                    product_status_id => 1,     # 1 == active
                    # product_price_id => 1,     # 1 == full (the default) -jff-
                );
                $newProduct->save();
            }
    
    
    
            if ($albumDigitalProductID) {
                my $digProductTrack = RPS::DB::Item::ProductTrack->Create(
                    product_id => $albumDigitalProductID,
                    track_id => $trackID,
                    disc_number => $disc_no,
                    disc_track => $track_no,
                    );
                    $digProductTrack->save();
            }
    
    
            if ($albumCDProductID)
            {
                my $physProductTrack = RPS::DB::Item::ProductTrack->Create(
                    product_id => $albumCDProductID,
                    track_id => $trackID,
                    disc_number => $disc_no,
                    disc_track => $track_no,
                );
                $physProductTrack->save();
            }
            if ($albumVinylProductID)
            {
                my $physProductTrack = RPS::DB::Item::ProductTrack->Create(
                    product_id => $albumVinylProductID,
                    track_id => $trackID,
                    disc_number => $disc_no,
                    disc_track => $track_no,
                );
                $physProductTrack->save();
            }
            if ($albumDVDProductID)
            {
                my $physProductTrack = RPS::DB::Item::ProductTrack->Create(
                    product_id => $albumDVDProductID,
                    track_id => $trackID,
                    disc_number => $disc_no,
                    disc_track => $track_no,
                );
                $physProductTrack->save();
            }
        }
    }
}






sub escapequotes
{
	my @string = @_;

	for (@string)
	{
		s/\"\"/"/g;
	}

	return wantarray ? @string : $string[0];
}

sub trimquotes
{
	my @string = trimspaces(@_);

	for (@string)
	{
		if (m/^\".*\"$/)
		{
			s/^\"//;
			s/\"$//;
		}
	}

	return wantarray ? @string : $string[0];
}

sub undefspaces
{
	my @string = trimspaces(@_);

	for (@string)
	{
		if ($_ eq '')
		{
			$_ = undef;
		}
	}

	return wantarray ? @string : $string[0];
}

sub report
{
    my ($text, $level) = @_;

    $level = kNormal unless $level;

    if ($level <= $gReportLevel)
    {
        print STDERR $text . "\n";
    }
}
