package Alexandria::Tracker;


#
# Copyright (C) 2002-2004 Open Source Development Network, Inc. ("OSDN")
# Copyright (C) 2004 OSTG, Inc. ("OSTG")
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the license details found
# below in the section marked "$LICENSE_TEXT".
#
# $Id: Tracker.pm,v 1.2 2005/03/01 11:51:49 moorman Exp $
#
# Written by Jacob Moorman <moorman@sourceforge.net>
###########################################################################

# Use all strictness, list intended global variables
use strict;
use Alexandria::Client;
use HTTP::Request::Common;

use vars qw($THIS); #global self-reference of last docman initialized

$LICENSE_TEXT = '
Copyright (c) 2002-2004 Open Source Development Network, Inc. ("OSDN")
Copyright (c) 2004 OSTG, Inc. ("OSTG")

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

1. The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

2. Neither the names of VA Software Corporation, OSDN, OSTG, SourceForge.net,
the SourceForge.net Site Documentation project, nor the names of its
contributors may be used to endorse or promote products derived from
the Software without specific prior written permission of OSTG. 

3. The name and trademarks of copyright holders may NOT be used in
advertising or publicity pertaining to the Software without specific,
written prior permission. Title to copyright in the Software and
any associated documentation will at all times remain with copyright
holders.

4. If any files are modified, you must cause the modified files to carry
prominent notices stating that you changed the files and the date of
any change.  We recommend that you provide URLs to the location from which
the code is derived.

5. Altered versions of the Software must be plainly marked as such, and
must not be misrepresented as being the original Software.

6. The origin of the Software must not be misrepresented; you must not
claim that you wrote the original Software. If you use the Software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.

7. The data files supplied as input to, or produced as output from,
the programs of the Software do not automatically fall under the
copyright of the Software, but belong to whomever generated them, and may
be sold commercially, and may be aggregated with the Software.

8. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE OR DOCUMENTATION.

This Software consists of contributions made by OSTG and many individuals
on behalf of OSTG.  Specific attributions are listed in the accompanying
credits file.
';

sub BEGIN
{
	use Exporter ();
	use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
	@ISA=qw(Exporter);
	@EXPORT=qw(
		sfnet_tracker_list_cannedresponses
		sfnet_tracker_cannedresponse
		);

}

sub sfnet_tracker_list_cannedresponses { $THIS->list_cannedresponses(@_) }
sub sfnet_tracker_cannedresponse { $THIS->cannedresponse(@_) }

###########################################################################
#
#  Sub new
#
#  creates a new Alexandria Tracker object
#
#  Parameters
#     $CLIENT - the Alexandria::Client object you have sucessfully connected to
#     group_id - the group_id you are initializing a docman object for
#
sub new {
   my ($CLIENT, $group_id, $atid) = @_;
   my $this = {};
   bless $this;

   die "cannot create a tracker object without a valid Alexandria Client and group_id"
      unless $CLIENT and $group_id and $atid;

   $this->{client} = $CLIENT;
   $this->{group_id} = $group_id;
   $this->{atid} = $atid;

   $THIS=$this;  #set the global self-reference
   return $this;
}

# Operation to retrieve a list of Canned Responses in a specific Tracker
sub list_cannedresponses {
	my ($this) = @_;
	util_output("verbose", "Obtaining list of Canned Responses.");

	my $request = HTTP::Request->new(GET =>
			$config{hosturl}. "/tracker/admin/index.php".
			"?group_id=". $config{groupid}.
			"&atid=". $config{atid}.
			"&add_canned=1");
	my $res = request($request);
	my $html = $res->content;
	my %urls = util_extracturls($html);

	# If we are not being called by our parent function (--list),
	# someone is requesting our hash of URL data.
	if (!defined($config{list})) {
		return %urls;
	}
		
	for (keys %urls) {
		if (/update_canned/) {
			(my $value = $_) =~ s/^(.*)(\&id=)([0-9]+)(.*)/$3/;
			if ($config{quiet}) {
				util_output("quiet", $value);
			} else {
				util_output("normal",
					            "$value $urls{$_}");
			}
		}
	}

	util_output("verbose", "Completed listing of DocManager ".
		            "documents.");
}

# Perform an operation to manipulate the Canned Responses
sub cannedresponse {
	my ($this) = @_;    
	util_output("verbose", "Performing a canned response operation.");
	verifylogin("");

	if ($config{cannedresponse} eq "download") {
		$this->cannedresponse_download ("");
	} elsif ($config{cannedresponse} eq "modify") {
		$this->cannedresponse_modify ("");
	} elsif ($config{cannedresponse} eq "create") {
		$this->cannedresponse_createnew ("");
	} else {
		util_output("die", "Invalid --cannedresponse mode ".
				    "specified: $config{cannedresponse}", "4");
	}

	util_output("verbose", "Completed cannedresponse operation.");
}

# Perform a download operation (i.e. retrieve content from the DocManager
# system and output this content to one or more files).
sub cannedresponse_download {
	my ($this) = @_;
	util_output("verbose", "Performing a download operation.");
	util_verifyvariables("groupid", "atid", "crid");
	verifylogin("");

	if (!defined($config{directoryname})) {
		util_output("die", "A directoryname must be specified.", "4");
	}

	if (defined($config{directoryname})) {
		util_mkdir($config{directoryname});
	}

	my %document = $this->cannedresponse_download_retrievedata("");
	my $filename;

	if (defined($config{directoryname}) && (!defined($config{noiddata}))) {
		util_filewriter($config{directoryname}. "/crid",
			                $config{crid});
	}

	$filename = $config{directoryname}. "/title";
	util_filewriter($filename, $document{title});

	$filename = $config{directoryname}. "/body";
	util_filewriter($filename, $document{body});
	util_output("verbose", "Completed download operation.");
}

# Perform data retrieval operations for a document's content and properties
# from the DocManager system
sub cannedresponse_download_retrievedata {
	my ($this) = @_;
	my $request = HTTP::Request->new(GET =>
		        $config{hosturl}. "/tracker/admin/index.php".
			"?group_id=". $config{groupid}. "&atid=".
			$config{atid}. "&update_canned=1".
			"&id=". $config{crid});
	my $res = request($request);
	my $html = $res->content;
	my %document = ();

	# Trim the content to this form, for sake of expediancy
	my $formhtml = util_extractform($html, "updatecanned");

	# Parse the document to obtain a full set of data
        my $parser = HTML::TokeParser->new(\$formhtml);
	my $current_select = "";
	my $current_field = "";
	while (my $token = $parser->get_token()) {
		my $type = $token->[0];
		if ($type eq "S") {
			my $tag = $token->[1];

			if ($tag eq "input") {
				my $name = $token->[2]{name} || "-";
				my $value = $token->[2]{value} || "-";
				if ($name eq "title") {
					$document{title} = $value;
				}
			} elsif ($tag eq "textarea") {
				my $name = $token->[2]{name} || "-";
				if ($name eq "body") {
					my $body = $parser->get_text;
					$document{body} = $body;
				}
			}
		}
	}

	return %document;
}

# Create a new Canned Response
sub cannedresponse_createnew {
	my ($this) = @_;
	util_output("verbose", "Creating a new Canned Response.");

	# Intialize the PRNG, generate a random string to use for
	# identification of new document, since DocManager doesn't tell
	# us the docid of new documents
	srand;
	my $randomstring;
	my $i;
	for ($i = 1; $i < 4; $i++) {
		$randomstring .= rand(32000);
	}

	# Obtain the current time/date stamp
	my $date = util_currenttime("");

	# Build default document
	my %document = ();
	$document{title} = 'atracker-created CR: '. $randomstring;
	$document{body} = 'CR created by adocman '. $VERSION.
			  ' on '. $date. '.';

	# Perform creation of document
	my $res = request
	  (POST
	   $config{hosturl}. "/tracker/admin/index.php",
	   content => [ 'add_canned'	=> 'y',
			'group_id'	=> $config{groupid},
			'atid'		=> $config{atid},
			'title'		=> $document{title},
			'body'		=> $document{body},
			'post_changes'	=> '1'
		      ]
	  );

	# Check to see if we failed to get a result from the server
        if (!$res->is_success) {
		util_output("verbose", "Failed to create Canned Response.");
		util_output("die", "$res->as_string", "1");
        }

	# Check to see if our result contained the success phrase
	my $submitresult = $res->content;
	(my $modifiedhtml = $submitresult) =~ s/Canned Response Inserted//;
	if ($modifiedhtml ne $submitresult) {
		util_output("verbose", "Completed create ".
			            "successfully, per result page.");
	}

	my %urls = $this->list_cannedresponses("");

	my $found_match = 0;
	util_output("verbose", "-- START OF REQUESTED OUTPUT --");
	my $key;
	foreach $key (keys %urls) {
		if ($urls{$key} eq $document{title}) {
			(my $value = $key) =~ s/^(.*)(\&id=)([0-9]+)(.*)/$3/;
			util_output("quiet", $value);
			$found_match = 1;
		}
	}
	util_output("verbose", "--- END OF REQUESTED OUTPUT ---");

	if (!$found_match) {
		util_output("die", "Unable to locate new CR.",
			            "1");
	} else {
		util_output("verbose", "Completed create ".
			            "operation successfully.");
	}

	util_output("verbose", "Completed CR create operation.");
}

# Modify the content for one or more fields pertaining to a CR
sub cannedresponse_modify {
	my ($this) = @_;
	util_output("verbose", "Modifying a Canned Response.");
	util_verifyvariables("groupid", "atid");
	verifylogin("");
	my %document = ();

	# Verify that we have a source for content
	if (!defined($config{directoryname})) {
		util_output("die", "A directoryname must be specified.", "4");
	}

	# Read the required document content from file or directory
	if (defined($config{directoryname})) {
		%document = util_readdownloaddir("");
	}

	util_output("verbose", "Performing modification of Canned Response.");

	# Write the content to Tracker
	my $res = request
	  (POST
	   $config{hosturl}. "/tracker/admin/index.php",
	   content => [ 'update_canned'	=> 'y',
			'group_id'	=> $config{groupid},
			'id'		=> $document{crid},
			'title'		=> $document{title},
			'atid'		=> $config{atid},
			'body'		=> $document{body},
			'post_changes'	=> '1'
		      ]
	  );

	# Check to see if we failed to get a result from the server
        if (!$res->is_success) {
		util_output("verbose", "Failed to modify Canned Response.");
		util_output("die", "$res->as_string", "1");
        }

	# Check to see if our result contained the success phrase
	my $submitresult = $res->content;
	(my $modifiedhtml = $submitresult) =~ s/Canned Response Updated//;
	if ($modifiedhtml ne $submitresult) {
		util_output("verbose", "Completed modify ".
			            "successfully, per result page.");
	} else {
		# FIXME: could probably use some debugging info here
		util_output("die", "Modify operation failed.", "1");
	}

	# FIXME: Do we need to verify that the content has been written
	# properly by doing a manual comparison?
	util_output("verbose", "Completed modification of Canned Response.");
}



#############################################################################
# end of package
#############################################################################

1;
