package CCDB::Part;

use strict;
use CCDB::DBIError;
use CCDB::Log;
use Date::Parse;

sub debug_println {
    print STDERR localtime() . " " . join(//, @_) . "\n";
}

our @ISA = qw(CCDB);

sub new
{
    my ($class, $purchase, $row, $dbh) = @_;

    $row->{dbh} = $dbh;
    $row->{name} = $row->{part};
    $row->{purchase} = $purchase->get_purchase;

    bless $row, $class;
}

sub update_quantity
{
    my ($this, $quantity) = @_;
    
    &begin;
    $this->_run_query("UPDATE_PART", { purchase => $this->get_purchase,
				       old_part => $this->get_name,
				       quantity => $quantity });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}	

sub update_cost
{
    my ($this, $cost) = @_;
    
    &begin;
    $this->_run_query("UPDATE_PART", { purchase => $this->get_purchase,
				       old_part => $this->get_name,
				       cost => $cost });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}	

sub update_name
{
    my ($this, $name) = @_;
    
    &begin;
    $this->_run_query("UPDATE_PART", { purchase => $this->get_purchase,
				       old_part => $this->get_name,
				       part => $name });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}	

sub update_comments
{
    my ($this, $comments) = @_;
    
    &begin;
    $this->_run_query("UPDATE_PART", { purchase => $this->get_purchase,
				       old_part => $this->get_name,
				       comments => $comments });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}				       

sub inventory
{
    my ($this, $quantity) = @_;

    # Validate data
    return 0 if $quantity <= 0;

    # Make sure that many are left
    my $inventoried;
    foreach ($this->get_log)
    {
	if ($_->get_action eq "inventoried")
	{
	    $inventoried += $_->get_quantity;
	}
	elsif ($_->get_action eq "uninventoried")
	{
	    $inventoried -= $_->get_quantity;
	}
	elsif ($_->get_action eq "noninventoried")
	{
	    $inventoried = undef;
	}
    }

    return 0 unless $inventoried + $quantity <= $this->get_quantity;

    # Mark
    &begin;
    $this->_run_query("INVENTORY_PARTS", { part => $this->get_part,
					   purchase => $this->get_purchase,
					   quantity => $quantity });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}				       

sub uninventory
{
    my ($this, $quantity) = @_;

    # Validate data
    return 0 if $quantity <= 0;

    # Make sure that many are inventoried
    my $inventoried;
    foreach ($this->get_log)
    {
	if ($_->get_action eq "inventoried")
	{
	    $inventoried += $_->get_quantity;
	}
	elsif ($_->get_action eq "uninventoried")
	{
	    $inventoried -= $_->get_quantity;
	}
	elsif ($_->get_action eq "noninventoried")
	{
	    $inventoried = undef;
	}
    }

    return 0 unless $quantity <= $inventoried;

    # Mark
    &begin;
    $this->_run_query("UNINVENTORY_PARTS", { part => $this->get_part,
					     purchase => $this->get_purchase,
					     quantity => $quantity });

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

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

    # Mark
    &begin;
    $this->_run_query("NONINVENTORY_PARTS", { part => $this->get_part,
					      purchase => $this->get_purchase });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}					       

sub arrive
{
    my ($this, $quantity) = @_;

    # Validate data
    return 0 if $quantity <= 0;

    # Make sure that many are left
    my $arrived;
    foreach ($this->get_log)
    {
	if ($_->get_action eq "arrived")
	{
	    $arrived += $_->get_quantity;
	}
	elsif ($_->get_action eq "unarrived")
	{
	    $arrived -= $_->get_quantity;
	}
    }

    return 0 unless $arrived + $quantity <= $this->get_quantity;

    # Mark
    &begin;
    $this->_run_query("ARRIVE_PARTS", { part => $this->get_part,
					purchase => $this->get_purchase,
					quantity => $quantity });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}				       

sub unarrive
{
    my ($this, $quantity) = @_;

    # Validate data
    return 0 if $quantity <= 0;

    # Make sure that many are arrived
    my $arrived;
    foreach ($this->get_log)
    {
	if ($_->get_action eq "arrived")
	{
	    $arrived += $_->get_quantity;
	}
	elsif ($_->get_action eq "unarrived")
	{
	    $arrived -= $_->get_quantity;
	}
    }

    return 0 unless $quantity <= $arrived;

    # Mark
    &begin;
    $this->_run_query("UNARRIVE_PARTS", { part => $this->get_part,
					  purchase => $this->get_purchase,
					  quantity => $quantity });
    
    if (&commit)
    {
	return 1;
    }
    else
    {
	return 0;
    }
}	

sub _load_log
{
    my ($this) = @_;
    my (@entries, @sorted_entries);
    
    my $query = $this->_run_query("GET_LOG", { part => $this->get_part,
					       purchase => $this->get_purchase });

    $this->{log} = [];
    $this->{arrived} = 0;
    $this->{inventoried} = 0;

    # fetch all rows into array and sort by timestamp (newest last)
    # see [CSL #283504]
    while (my $ent = $query->fetchrow_hashref) {
        push @entries, $ent;
    }

    # this is probably bloody inefficient
    @sorted_entries = sort { str2time($a->{timestamp}) <=> str2time($b->{timestamp}); } @entries;

    foreach my $row (@sorted_entries)
    {
	my $log = new CCDB::Log $row;
	push @{$this->{log}}, $log;

	if ($log->get_action eq "arrived")
	{
	    $this->{arrived} += $log->get_quantity;
	}
	elsif ($log->get_action eq "unarrived")
	{
	    $this->{arrived} -= $log->get_quantity;
	}
	elsif ($log->get_action eq "inventoried")
	{
	    $this->{inventoried} += $log->get_quantity;
	}
	elsif ($log->get_action eq "uninventoried")
	{
	    $this->{inventoried} -= $log->get_quantity;
	}
	elsif ($log->get_action eq "noninventoried")
	{
	    $this->{inventoried} = undef;
	}
    }
}   

our $AUTOLOAD;
sub AUTOLOAD
{
    my ($this) = @_;

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

    $this->_load_log
	if !$this->{$data} && ($data eq "log" || $data eq
			       "inventoried" || $data eq "arrived");

    die "No such method: $AUTOLOAD" 
	unless defined $this->{$data} || $data eq "inventoried";
    
    ref($this->{$data}) eq "ARRAY" ? @{$this->{$data}} : $this->{$data};
}

1;
