package CCDB::Purchase;

use strict;
use lib "/s/req/perl5"; # <- doesn't exist.  Didn't comment it out entirely cause I don't feel like testing it right now.  XXX
use lib "/s/req/lib";
use Req::Request;
use CCDB::Part;
use CCDB::Fund;
use CCDB::Paperwork;
use CCDB::DBIError;

our @ISA = qw(CCDB Req::Request);

sub new
{
    my ($class, $req) = @_;

    # Validate input
    return $req if ref($req) eq "CCDB::Purchase";
    return 0 unless ref($req) eq "Req::Request";
    
    # Copy to preserve blessing on original
    my %req = %$req;
    my %this = %req;
    my $this = bless \%this, $class;
    $this->{purchase} = $this->{request};
    
    my $query = $this->_run_query("GET_PURCHASE_DATA", { purchase =>
							     $this->{purchase} });
    my $row = $query->fetchrow_hashref;
    if( $row ) {
        %$this = (%$this, %$row);
        return $this;
    } else {
        return 0;
    }
    
}

sub cancel
{
    my ($this) = @_;

    &begin;
    $this->_run_query("CANCEL_ORDER", { purchase => $this->{purchase} });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub reopen
{
    my ($this) = @_;

    &begin;
    $this->_run_query("REOPEN_ORDER", { purchase => $this->{purchase} });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub check
{
    my ($this) = @_;

    &begin;
    $this->_run_query("CHECK_ORDER", { purchase => $this->{purchase} });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub uncheck
{
    my ($this) = @_;

    &begin;
    $this->_run_query("UNCHECK_ORDER", { purchase => $this->{purchase} });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub add_part
{
    my ($this, %part) = @_;
    
    # Validate input
    return 0 unless $part{name};

    # Make sure we don't already have that part
    foreach ($this->get_parts)
    {
	return 0 if $part{name} eq $_->get_name;
    }
    
    # Add the part
    &begin;
    $this->_run_query("ADD_PART", { part => $part{name},
				    cost => $part{cost},
				    quantity => $part{quantity},
				    comments => $part{comments},
				    purchase => $this->get_purchase });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub remove_part
{
    my ($this, $part) = @_;

    # Validate input
    return 0 unless ref($part) eq "CCDB::Part";
    
    # Make sure we have this part
    my $have = 0;
    foreach ($this->get_parts)
    {
	next unless $part->get_name eq $_->get_name;
	
	$have = 1;
	last;
    }
    return 0 unless $have;

    # Remove the part
    &begin;
    $this->_run_query("DELETE_PART", { part => $part->get_name,
				       purchase => $this->get_purchase });

    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub add_shipping
{
    my ($this, %shipping) = @_;
    
    # Validate input
    return 0 unless $shipping{name};

    # Make sure we don't already have that shipping
    foreach ($this->get_shipping)
    {
	return 0 if $shipping{name} eq $_->get_name;
    }

    # Add the shipping
    &begin;
    $this->_run_query("ADD_SHIPPING", { shipping => $shipping{name},
					cost => $shipping{cost},
					quantity => $shipping{quantity},
					comments => $shipping{comments},
					purchase => $this->get_purchase });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub remove_shipping
{
    my ($this, $shipping) = @_;

    # Validate input
    return 0 unless ref($shipping) eq "CCDB::Part";
    
    # Make sure we have this shipping
    my $have = 0;
    foreach ($this->get_shipping)
    {
	next unless $shipping->get_name eq $_->get_name;
	
	$have = 1;
	last;
    }
    return 0 unless $have;

    # Remove the shipping
    &begin;
    $this->_run_query("DELETE_PART", { part => $shipping->get_name,
				       purchase => $this->get_purchase });

    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub add_fund
{
    my ($this, %fund) = @_;
    
    # Validate input
    return 0 unless $fund{name};
    
    # Make sure we don't already have that part
    foreach ($this->get_funds)
    {
	return 0 if $fund{name} eq $_->get_name;
    }

    # Add the part
    &begin;
    $this->_run_query("ADD_FUND", { fund => $fund{name},
				    amount => $fund{all} ? 0 : $fund{amount},
				    all => $fund{all} ? 't' : 'f',
				    purchase => $this->{purchase} });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub remove_fund
{
    my ($this, $fund) = @_;

    # Validate input
    return 0 unless ref($fund) eq "CCDB::Fund";
    
    # Make sure we have this fund
    my $have = 0;
    foreach ($this->get_funds)
    {
	next unless $fund->get_name eq $_->get_name;
	
	$have = 1;
	last;
    }
    return 0 unless $have;

    # Remove the part
    &begin;
    $this->_run_query("DELETE_FUND", { fund => $fund->get_name,
				       purchase => $this->get_purchase });

    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}

sub mark_paperwork
{
    my ($this, $message, $type) = @_;

    # Validate input
    return 0 unless ref($message) eq "Req::Message";

    # Check if it's already marked
    foreach ($this->get_paperwork)
    {
	return 0 if $_->get_message_file eq
	    $message->get_message_file;
    }

    &begin;
    $this->_run_query("MARK_PAPERWORK", { type => $type,
					  purchase => $this->get_purchase,
					  message =>
					      $message->get_message_file });

    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }    
}

sub unmark_paperwork
{
    my ($this, $message) = @_;

    # Validate input
    return 0 unless ref($message) eq "Req::Message";
    
    # Make sure it's already marked
    my $have = 0;
    foreach ($this->get_paperwork)
    {
	next unless $_->get_message_file eq
	    $message->get_message_file;
	$have = 1;
	last;
    }
    return 0 unless $have;

    &begin;
    $this->_run_query("UNMARK_PAPERWORK", { purchase => $this->get_purchase,
					    message =>
						$message->get_message_file });

    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }   
}

sub update_vendor
{
    my ($this, $vendor) = @_;

    &begin;
    $this->_run_query("UPDATE_VENDOR", { purchase => $this->get_purchase,
					 vendor => $vendor });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }   
}

sub update_card
{
    my ($this, $card) = @_;

    &begin;
    $this->_run_query("UPDATE_CARD", { purchase => $this->get_purchase,
				       card => $card });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }   
}

sub update_class
{
    my ($this, $class) = @_;

    &begin;
    $this->_run_query("UPDATE_CLASS", { purchase => $this->get_purchase,
				        class => $class });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }   
}

sub update_type {
    my ($self, $type) = @_;

    if( $type ne 'ccard' and $type ne 'requis' and $type ne 'gik' ) {
        # Invalid type
        return 0;
    } else {
        &begin;
        $self->_run_query("UPDATE_TYPE", {
            purchase => $self->get_purchase,
            type => $type });
        return 1 if &commit;
        return 0;
    }
}

sub update_requis_num {
    my ($self, $requis_num) = @_;

    &begin;
    $self->_run_query("UPDATE_REQUIS_NUM", {
        purchase => $self->get_purchase,
        requis_num => $requis_num });
    return 1 if &commit;
    return 0;
}

sub update_pi {
    my ($self, $pi) = @_;

    &begin;
    $self->_run_query("UPDATE_PI", {
        purchase => $self->get_purchase,
        pi => $pi });
    return 1 if &commit;
    return 0;
}

sub _load_parts
{
    my ($this) = @_;

    my $query = $this->_run_query("GET_PARTS", { purchase => $this->get_purchase });
    my @parts;
    while (my $row = $query->fetchrow_hashref)
    {
	push @parts, new CCDB::Part $this, $row, $this->{dbh};
    }

    $this->{parts} = \@parts;
}

sub _load_funds
{
    my ($this) = @_;

    my $query = $this->_run_query("GET_FUNDS", { purchase => $this->get_purchase });
    my @funds;
    while (my $row = $query->fetchrow_hashref)
    {
	push @funds, new CCDB::Fund $this, $row, $this->{dbh};
    }

    $this->{funds} = \@funds;
}

sub _load_paperwork
{
    my ($this) = @_;
    
    my @paperwork;
    foreach my $message ($this->get_messages)
    {
	my $query = $this->_run_query("GET_PAPERWORK", { message =>
							     $message->get_message_file });
	next unless my $row = $query->fetchrow_hashref;

	push @paperwork, new CCDB::Paperwork $message, $row->{type};
    }
    $this->{paperwork} = \@paperwork;
}

sub _load_shipping
{
    my ($this) = @_;

    my $query = $this->_run_query("GET_SHIPPING", { purchase => $this->get_purchase });
    my @shipping;
    while (my $row = $query->fetchrow_hashref)
    {
	push @shipping, new CCDB::Part $this, $row, $this->{dbh};
    }
    
    $this->{shipping} = \@shipping;    
}

our $AUTOLOAD;
sub AUTOLOAD
{
    my ($this) = @_;
    
    $AUTOLOAD =~ /DESTROY$/ && return;
    $AUTOLOAD =~ /::get_(.*)/ || die "No such method: $AUTOLOAD";
    my $data = $1;

    $this->_load_parts 
	if !exists $this->{parts} && $data eq "parts";
    $this->_load_funds
	if !exists $this->{funds} && $data eq "funds";
    $this->_load_paperwork
	if !exists $this->{paperwork} && $data eq "paperwork";
    $this->_load_shipping
	if !exists $this->{shipping} && $data eq "shipping";

    goto &Req::Request::AUTOLOAD unless exists $this->{$data};

    ref($this->{$data}) eq "ARRAY" ? @{$this->{$data}} : $this->{$data};
}

1;
