#!/usr/bin/perl -w
use warnings;
use strict;
$|=1;
use EVE::Db;
my $dbh = EVE::Db::dbh();
die "cant connect to db: ".DBI->errstr unless $dbh;
use EVE::Cache;
my $CC = EVE::Cache::get();
use CGI::Fast qw/ :standard /;
while (my $q = new CGI::Fast) {
&do_bpo($q);
}
exit 0;
die "never here";
sub do_bpo ($) {
use CGI qw/:standard *ul *table *Tr/;
my ($q,) = @_;
use Time::HiRes qw ( time );
my $begin = time;
use EVEcommon;
my $trust = $ENV{'HTTP_EVE.TRUSTED'} || 'undef';
print header,"\n",
start_html("BPO Calc"),"\n";
my $url = $q->url({absolute=>1,});
$url =~ s,:8\d/,/,;
print h1(a({href=>$url,},"BPO Calc")),"\n";
my @sp = ();
my $debug = $q->param("debug") || $q->url_param("debug") || 0;
if ($debug) { push @sp, "debug=1"; }
## TODO: config
my $vtag = $EVE::Db::vtag;
my @vers = grep { $_->[3] =~ /:(itm|ta[rmt]):/ } @EVE::Db::versions;
my %vers;
my @cvers;
my $versname = {};
my $vers;
for (@vers) {
$vers = $_->[0];
die "dupe vers $vers" if exists $vers{$vers};
$vers{$vers} = $_;
push @cvers, $vers;
$versname->{$vers} = $_->[2]." -- ".$vers;
}
my $opt_d = $vers{$vers}->[1];
my $dbe = $q->param("db") || $q->url_param("db") || "";
my $db = ($dbe =~ /^(\w+)$/i) ? lc $1 : "";
if ($db) {
if ($db eq 'sisi') {
$opt_d = "dbz_$db";
} elsif ($db =~ /^(tq|ccp|dbo)$/) {
$db = $vers;
}
if ($vers{$db}) {
$opt_d = $vers{$db}->[1];
}
if ($db && $q->url_param("db")) {
push @sp, "db=$db";
}
} else {
$db = $vers;
}
die "no db" unless $opt_d;
die "bad db" unless $opt_d =~ /^\w+$/;
die "invalid db $db" unless exists $vers{$db};
my $submit = $url;
if (@sp) { $submit .= "?".join("&",@sp); }
my @parm = ();
my $patt = $q->param("patt") || "";
if ($patt) {
# Delete("patt");
my $lpatt = $patt;
$lpatt =~ s/\s+/%/g;
$lpatt =~ s/(^|$)/%/g;
$lpatt =~ s/%+/%/g;
push @parm, $lpatt;
} else {
goto BEGINHTML;
}
my $pub = $q->param("pub");
my $publ = (defined $pub) ? (1 && $pub) : undef;
my $sth_bpolist = $dbh->prepare_cached(qq{
select distinct
i.typeID,
i.typeName
from
$opt_d.invTypes i,
$opt_d.invBlueprintTypes t
where
t.bluePrintTypeID = i.typeID
${\(defined $publ ? "and i.published = $publ" : "")}
${\($patt ? "and i.typeName like ?" : "")}
}) or die $dbh->errstr;
$sth_bpolist->execute(@parm) or die $sth_bpolist->errstr;
my $rows = $sth_bpolist->fetchall_arrayref();
$sth_bpolist->finish();
my %id_to_bpo = ();
for (@$rows) {
my ($id, $name,) = @$_;
$id_to_bpo{$id} = $name;
}
my $type = $q->param("type");
$type = undef unless $type && $id_to_bpo{$type};
if (!defined $type) { # try to auto-select type
if (scalar(@$rows) == 1) { # just one match?
$type = $rows->[0][0];
} else {
my $rpatt = quotemeta $patt;
my $n;
for (@$rows) {
my $N = $_->[1];
if (!defined $n || length $n > length $N) {
$n = $N;
$type = $_->[0];
}
}
}
}
if ($type) {
my $v;
my $key = "typeversions:$vtag:$type";
$v = $CC->get($key) if defined $CC;
unless (defined $v && keys %$v) {
$v = {};
my ($from, $to, $on, $od, $gen,);
for (@vers) {
my ($n, $d, $D, $f,) = @$_;
my $sth = $dbh->prepare_cached(qq{
select
typeID
from
$d.invTypes
where
typeID = ?
}) or die $dbh->errstr;
$sth->execute($type) or die $sth->errstr;
my $ar = $sth->fetchall_arrayref();
if (defined $ar && @$ar) {
die "morph" unless $ar->[0]->[0] == $type;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
my $vd = &load_data($vers{$n}, $type);
my $vds = Dumper($vd);
my $me = $D." ".$n;
if (!defined $od || $od ne $vds) {
if (defined $od) {
die "no on" unless $on;
$v->{$on} = "v".++$gen.": ".$from." - ".($to||$me);
}
$od = $vds;
$from = $me;
}
$to = $me;
$on = $n;
}
}
$v->{$on} = "v".++$gen.": ".$from." - ".$to;
$CC->set($key, $v) if defined $CC && defined $v && keys %$v;
}
if (defined $v && keys %$v) {
$versname = $v;
@cvers = grep { exists $v->{$_} } @cvers;
}
}
my $me = $q->param("me");
$me = undef unless defined $me && $me =~ /^\s*(-?\d+([\s,]+-?\d+)*)\s*$/;
my %me = (0 => "__base",);
if ($me) {
$me =~ s/[\s,]+/,/g;
$me =~ s/(^,|,$)//g;
my @mes = split /,/, $me;
for (@mes) {
$me{int($_)} = '__requested';
}
}
my $pe = $q->param("pe");
$pe = undef unless defined $pe && $pe =~ /^[\d,]+$/;
my %pe = (0 => "__base",);
if ($pe) {
my @pes = split /,/, $pe;
for (@pes) {
$pe{int($_)} = '__requested';
}
}
my $skme = $q->param("skme");
$skme = 0 unless defined $skme && $skme =~ /^[012345]$/;
my $skpe = $q->param("skpe");
$skpe = 0 unless defined $skpe && $skpe =~ /^[012345]$/;
my $batch = $q->param("batch");
$batch = 1 unless defined $batch && $batch =~ /^\d+$/;
my $wastebatch = 1; # EA change: back to per-run rounding
my @ids_by_name = sort {
lc($id_to_bpo{$a})
cmp
lc($id_to_bpo{$b})
} keys %id_to_bpo;
#print hr, br, start_form(-method=>'get');
BEGINHTML:
print hr, br, $q->start_form({action => $submit,},);
print start_table;
print Tr(td("Version: "),
td({colspan=>2},
$q->popup_menu(-name => 'db',
-values => \@cvers,
-default => $opt_d,
-labels => $versname,
),,),), "\n";
print Tr(td(["Search: ",
$q->textfield(-name => 'patt',
-default => '',
-size => 20,),],),), "\n";
goto ENDHTML unless $patt;
print Tr(td("Select: "),
td({colspan=>2},
$q->popup_menu(-name => 'type',
-values => \@ids_by_name,
-default => $type,
-labels => \%id_to_bpo,
),,),), "\n";
print Tr(td(["ME: ",
$q->textfield(
-name => 'me',
-default => '',
-size => 20,),
"f.ex. 20 or 20,50,100",]),
td({width=>50,},""),
td([ "Metallurgy Level:",
$q->radio_group(
-name => 'skme',
-values => [0,1,2,3,4,5,],
-default => 3,),
])), "\n";
print Tr(td(["PE: ", $q->textfield(-name => 'pe',
-default => '',
-size => 20,),"",
"",
"Research Level:",
$q->radio_group(
-name => 'skpe',
-values => [0,1,2,3,4,5,],
-default => 3,),
])), "\n";
print Tr(td(["Batch: ", $q->textfield(-name => 'batch',
-default => '',
-size => 20,),
# "for waste calculation",
])), "\n";
ENDHTML:
print end_table,"\n";
print $q->submit,
$q->end_form, "\n";
goto EXITHTML unless $type;
# data
my $data = &load_data($vers{$db}, $type);
die "no data" unless defined $data && keys %$data;
my $params = $data->{params};
die "no params" unless defined $params && keys %$params;
my $product = $data->{product};
die "no product" unless defined $product && keys %$product;
my $sellers = $data->{sellers};
die "no sellers" unless defined $sellers;
my $gl = "";
$gl = sprintf '/mybpo?group=%i', $params->{groupID};
if ($ENV{REMOTE_ADDR} =~ /^(10|192)\./) {
$gl .= "&show=all";
}
my $surl = $q->self_url;
$surl =~ s,:8[12345]/,/,;
print hr,h2(
span({title=>"typeID:".$params->{typeID},}, a({href=>"showinfo:$type"}, $params->{typeName})).
" - ".span({style=>'color: green',title=>"groupID:".$params->{groupID},},
($gl ? a({href=>$gl,},$params->{groupName})
: $params->{groupName}),
).
" - ".span({style=>'color: green',title=>"categoryID:".$params->{categoryID},},$params->{categoryName}),
" - ".a({href=>"/hist?type=".$params->{typeID},},"hist"),
" - ".a({href=>$surl},"link")), "\n";
my @sellers = ();
for (@$sellers) {
my ($corp, $cid, $min, $max,) = @$_;
my $sel = a({href=>"showinfo:2//$cid",},$corp);
my $k = "bposellerregions:$opt_d:$vtag:$cid";
my $ar;
$ar = $CC->get($k) if defined $CC;
unless ($ar) {
my $sth = $dbh->prepare_cached(qq{
select distinct
r.regionName
from
$opt_d.mapRegions r,
$opt_d.mapSolarSystems s,
eve.apiStations sta
where
sta.corporationID = ?
and sta.solarSystemID = s.solarSystemID
and s.regionID = r.regionID
}) or dir $dbh->errstr;
$sth->execute($cid) or die $sth->errstr;
$ar = $sth->fetchall_arrayref();
$sth->finish;
$CC->set($k, $ar) if defined $CC && defined $ar;
}
my $sec = sprintf("%.2f-%.2f", $min, $max);
if ($ar && @$ar) {
my $regs = join ", ", sort map({$_->[0]} @$ar);
$sec = span({ style=>'color: green',
title=>$regs,},
$sec,);
}
$sel .= " sec ".$sec;
push @sellers, $sel;
}
my $mwaste = $params->{wasteFactor};
my $metime = $params->{researchMaterialTime};
my $pwaste = $params->{productivityModifier};
my $petime = $params->{researchProductivityTime};
my $ptime = $params->{productionTime}-$params->{productivityModifier};
my $reqs = $data->{reqs};
die "no reqs" unless defined $reqs;
my %reqs_wst=();
for my $r (@$reqs) {
if ($debug) {
print hr,"\n";
print h3("req: ".$_), br, "\n";
for (sort keys %$r) {
printf "%s: %s
\n", $_, defined($r->{$_}) ? $r->{$_} : "[NULL]";
}
print hr, "\n";
}
my $name = $r->{typeName};
$reqs_wst{$name} = {
name => $name,
quant => $r->{quantity},
id => $r->{materialTypeID},
};
}
my $materials = $data->{materials};
die "no materials" unless $materials;
my %reqs_add=();
my (@skills_build, @skills_me, @skills_pe, @skills_copy,);
for my $r (@$materials) {
if ($debug) {
print hr,"\n";
print h3("req: ".$_), br, "\n";
for (sort keys %$r) {
printf "%s: %s
\n", $_, defined($r->{$_}) ? $r->{$_} : "[NULL]";
}
print hr, "\n";
}
if ($r->{categoryName} eq 'Skill') {
if ($r->{activityName} eq 'Manufacturing') {
push @skills_build, $r;
} elsif ($r->{activityName} eq 'Research Time Productivity') {
push @skills_pe, $r;
} elsif ($r->{activityName} eq 'Research Material Productivity') {
push @skills_me, $r;
} elsif ($r->{activityName} eq 'Copying') {
push @skills_copy, $r;
}
} elsif ($r->{activityName} eq 'Manufacturing') {
my $name = $r->{typeName};
my $quant = $r->{quantity};
$reqs_add{$name} = {
name => $name,
quant => $r->{quantity},
cat => $r->{categoryName},
dmg => $r->{damagePerJob},
id => $r->{requiredTypeID},
rec => $r->{recycle},
};
if ($r->{_recycle}) {
for my $R (@{$r->{_recycle}}) {
my $name = $R->{typeName};
next unless $reqs_wst{$name};
$reqs_wst{$name}->{quant} -= $R->{quantity};
if ($reqs_wst{$name}->{quant} <= 0) {
delete $reqs_wst{$name};
};
}
}
}
}
my $maxme = 0;
for my $n (keys %reqs_wst) {
my $quant = $reqs_wst{$n}->{quant};
# my $tme = $mwaste ? int($quant/$mwaste*0.5) : 0;
#14:59 hrm actually (0.02 * BaseWasteFactor * Maxruns * amountOf Mineral) - 1
#15:00 if you stick that in and compare answers, you should see that its right
my $tme = $mwaste ? int($quant*$mwaste*$wastebatch*0.02) : 0;
if ($quant > 0) {
if ($tme*$metime < 365*24*60*60) {
$me{$tme} = $n;
} else {
$maxme = $tme if $tme > $maxme;
}
} else {
warn "negative quantities ('$n' for '$type')in new bpotool?";
next; # wtf. example_ minerals on Hulk
}
}
my $tl = $params->{techLevel};
if (scalar keys %me < 3) {
if ($tl == 2 && !@sellers) {
$me{"-6"} ||= "t2";
$me{"-4"} ||= "t2";
$me{"-2"} ||= "t2";
$me{"-1"} ||= "t2";
} else {
for (10,50,100,300) {
if ($maxme > $_) {
$me{$_} ||= "random";
}
}
}
}
if ($tl == 2 && !@sellers) {
$me{"-4"} ||= "t2";
}
print start_table;
print Tr( td("Produces:"),
td($product->{portionSize}."x ".a({href=>"showinfo:".$product->{typeID},},$product->{typeName}).
" - ".span({style=>'color: green',title=>"groupID:".$product->{groupID},},$product->{groupName}).
" - ".span({style=>'color: green',title=>"categoryID:".$product->{categoryID},},$product->{categoryName}).
" - ".a({href=>"/hist?type=".$product->{typeID},},"hist"),
),
),"\n" ;
#print Tr( td("ProductGroup:"), td($product->{groupID}." - ".$product->{groupName})),"\n" ;
#print Tr( td("ProductCategory:"), td($product->{categoryID}." - ".$product->{categoryName})),"\n" ;
if ($product->{categoryName} eq 'Ship' && $product->{basePrice}) {
my $col = "platinum";
my $bp = 1.0*$product->{basePrice};
my $ic = 0.3*$bp;
print Tr( td("ProductInsurance:"),
td(
span({style=>'color: green',title=>"payout $col",}, &shortprettyisk($bp))." - ".
span({style=>'color: green',title=>"cost $col",}, &shortprettyisk($ic))." == ".
&shortprettyisk($bp-$ic)
)
),"\n" ;
}
#print Tr( td("ProductCategory:"), td($product->{categoryID}." - ".$product->{categoryName})),"\n" ;
print Tr(),"\n";
print Tr( td("Techlevel:"), td($tl)),"\n";
print Tr( td("Baseprice:"), td(prettyisk($params->{basePrice}))),"\n" if $params->{basePrice};
print Tr( td("Sellers:"), td(join(br,@sellers))),"\n" if @sellers;
print Tr(),"\n";
print Tr( td("Base ME Time:"),
td(prettytime($params->{researchMaterialTime})),
td(join br, map {a({href=>"showinfo:".$_->{typeID},}, $_->{typeName}." lvl ".$_->{quantity})} @skills_me),),"\n";
print Tr( td("Base Waste Factor:"), td($params->{wasteFactor}."%")),"\n";
print Tr(),"\n";
print Tr( td("Base PE Time:"),
td(prettytime($params->{researchProductivityTime})),
td(join br, map {a({href=>"showinfo:".$_->{typeID},}, $_->{typeName}." lvl ".$_->{quantity})} @skills_pe),),"\n";
print Tr( td("Base Build Time:"),
td(prettytime($params->{productionTime})),
td(join br, map {a({href=>"showinfo:".$_->{typeID},}, $_->{typeName}." lvl ".$_->{quantity})} @skills_build),),"\n";
print Tr(),"\n";
print Tr( td("Base Copy Time:"), td(prettytime(2*$params->{researchCopyTime}))),"\n";
#20:34 <%Veritech|AFK> ah the copy time
#20:34 <%Veritech|AFK> multiply by 2
#20:34 <%Veritech|AFK> the x2 is a long story
#$batch = $params->{maxProductionLimit} if $batch > $params->{maxProductionLimit};
print Tr( td("Max Runs:"), td($params->{maxProductionLimit}." (batch:$batch)")),"\n";
print end_table,hr,"\n";
if ($debug) {
for (sort keys %$params) {
printf "%s: %s
\n", $_, defined($params->{$_}) ? $params->{$_} : "[NULL]";
}
print hr,"\n";
}
#22:41 <+nagi> Chruker: current working theory ... invBlueprintTypes
# productivitymodifier/productiontime
#22:41 <+Chruker> IIIecho "\t\t\t\tLevel ".$industry.":
# ".time_format(round(($blueprint_info["productionTime"] * (1 -
# (($blueprint_info["productivityModifier"] /
# $blueprint_info["productionTime"]) * ($productivity_level / (1
# + $productivity_level)))) * (1 - (0.04 * $industry))),
# 0))."
\n";
#round(($blueprint_info["productionTime"] *
# (1 - (
# ( $blueprint_info["productivityModifier"] / $blueprint_info["productionTime"]) *
# ($productivity_level / (1 + $productivity_level))
# )
# )
# * (1 - (0.04 * $industry))),
# 0))
for (0..5) {
my $v = 2**$_;
last if $v > $pwaste;
last if $petime*$v > 365*24*60*60;
$pe{$v} = "__exponential";
my $rev = int(($pwaste/$v)+0.5);
next if $petime*$rev > 365*24*60*60;
$pe{$rev} = "__reverse";
}
my $lp;
for (sort {$a <=> $b} keys %pe) {
my $p = int($pwaste*(1/(1+$_)));
if (defined $lp &&
$pe{$_} =~ /^__/ &&
$lp == $p) {
delete $pe{$_};
}
$lp = $p;
}
my @pe = sort {$a <=> $b} keys %pe;
print start_table({border=>1,}),"\n",
Tr(
th(""),
th([map("PE:$_", @pe),]),),"\n";
print Tr({align=>'right',},td("Build Time"),
td([map(prettytime($ptime+($pwaste*(1/(1+$_)))), @pe),],),), "\n";
print Tr({align=>'right',},td("Build Time Waste"),
td([map(prettytime(($pwaste*(1/(1+$_)))), @pe),],),), "\n";
my @ptimes = (
['Base', 1,],
['POS', 0.75,],
);
if ($skpe) {
my $sk = 1-($skpe*0.05);
unless ($skpe == 5) {
push @ptimes, ['Skill', $sk,];
}
push @ptimes, ['Skill & POS', $sk*0.75,];
};
for (sort {$b->[1] <=> $a->[1]} @ptimes) {
my ($n, $f,) = @$_;
print start_Tr, th("$n Lab time"), th(sprintf "x%.2f", $f),
map($_ ? th(prettytime($petime*$_*$f)) : "", @pe),
end_Tr, "\n";
}
print end_table,"\n";
#########
print start_table({border=>1,});
my @me = sort {$a <=> $b} keys %me;
print Tr(
th(["Material", "ISK pu", "Base",]),
th({colspan=>2}, [map("ME:$_", @me),]),), "\n";
print Tr(
td({colspan=>3}, ""),
td([map(("needed","wasted",), @me),]),), "\n";
use EVE::Market;
my $market = EVE::Market->new(
where => "connectedhighsec",
when => 30*24*60*60,
) or die "cant get market";
my %cost = ();
my $missing = 0;
my %cnts = ();
for (keys %reqs_wst) {
$cnts{$_} += $reqs_wst{$_}{quant};
}
for (keys %reqs_add) {
$cnts{$_} += $reqs_add{$_}{quant};
}
for (sort {$cnts{$b} <=> $cnts{$a}} keys %cnts) {
my $wst = $reqs_wst{$_}||{};
my $add = $reqs_add{$_}||{};
my $id = $wst->{id} || $add->{id};
my $name = $wst->{name} || $add->{name};
my $qw = $wst->{quant}||0;
my $qa = $add->{quant}||0;
my $q = $qw + $qa;
my $dmg = $add->{dmg};
my $p = eval { $market->get_price(typeID => $id)->{avg} } || 0;
warn $@ if $@;
my $busy;
my $bpl = "";
my $ar = $data->{"rid:$id"};
if (defined $ar && @$ar) {
die "more than one BP for $id" if scalar @$ar > 1;
my ($bpid,$bpname,$bpt,) = @{$ar->[0]};
$bpl .= " (".a({href=>"showinfo:$bpid",},"BP");
my $turl = $url."?";
$turl .= "type=$bpid";
$turl .= "&patt=".&urlify($bpname);
$bpl .= ",".a({href=>$turl,},"CALC").")";
if ($bpt && $params->{productionTime}) {
# warn "BUSY: $bpt * $q / ".$params->{productionTime};
$busy = ($bpt*$q)/$params->{productionTime};
}
}
print start_Tr({align=>'right',}),
td({align=>'left'}, a({href=>"showinfo:$id",},
#$r->{cat}.": ".
$name,).$bpl),
$p ? td(&shortprettyisk($p)) : td({bgcolor=>'red'}, "n/a"),
td(defined $busy ? span({style=>'color: green',title=>sprintf("%.2f%% busy",$busy*100),},$q) : $q);
$cost{base} += $q*$p;
$missing++ unless $p;
for (@me) {
my $wf = $_ < 0 ?
($mwaste/100)*(abs($_)+1) :
($mwaste/100)/(1+$_);
my $w = int(($wf*$qw*$wastebatch)+0.5);
$cost{$_}{n} += $p*int($q+($w/$wastebatch));
$cost{$_}{w} += $p*int($w/$wastebatch);
# printf STDERR "WASTE: ME:%i WF:%.5f W:%i\n", $_, $wf, $w;
# if ((defined $r->{hasWaste} && $r->{hasWaste}) ||
# (!defined $r->{hasWaste} && $dmg == 1 && $r->{cat} =~ /^(Material|Commodity)$/)) {
if ($qw) {
if ($w) {
print td([$batch*int($q+($w/$wastebatch)), $batch*$w,]);
} else {
print td({bgcolor=>'lightgreen'}, [$batch*$q, 0,]);
}
} else {
if ($dmg > 0 && $dmg < 1) {
my $d = sprintf "%ix%i%%", $batch, int($dmg*100);
my $qq = int(($batch*$dmg*$q)+0.99);
print td([$qq, $d,]);
} else {
print td([$batch*$q, " ",]);
}
}
}
print end_Tr, "\n";
}
my $p = eval { $market->get_price(typeID => $product->{typeID})->{avg} } || 0;
print start_Tr, th("ISK"),
$p ? th(&shortprettyisk($product->{portionSize}*$p)) : th({bgcolor=>'red'}, "n/a"),
th($missing ? {bgcolor=>'red'} : {}, $cost{base} ? &shortprettyisk($cost{base}) : "n/a"),
th($missing ? {bgcolor=>'red'} : {}, [
map( ( &shortprettyisk($cost{$_}{n}), &shortprettyisk($cost{$_}{w}), ), @me),
]),
end_Tr, "\n";
my @mtimes = (
['Base', 1,],
['POS', 0.75,],
);
if ($skme) {
my $sk = 1-($skme*0.05);
unless ($skme == 5) {
push @mtimes, ['Skill', $sk,];
}
push @mtimes, ['Skill & POS', $sk*0.75,];
};
for (sort {$b->[1] <=> $a->[1]} @mtimes) {
my ($n, $f,) = @$_;
print start_Tr, th({colspan=>4}, "$n Lab time"), th(sprintf "x%.2f", $f),
map($_ ?
$_ > 0 ?
th({colspan=>2},prettytime($metime*$_*$f))
: th({colspan=>2}, "")
: "", @me),
end_Tr, "\n";
}
print end_table,"\n";
EXITHTML:
if ($debug) {
print hr,"\n";
for (sort keys %ENV) {
printf "%s: %s%s\n", $_, $ENV{$_}, br;
}
}
my $runtime = time - $begin;
print hr,
"Database: ", $opt_d, br, "\n",
$runtime ? sprintf "Completed in %.3f sec.", $runtime : "",
end_html,"\n";
} # do_bpo
die "never here";
# toolz
sub load_data ($$) {
my ($db, $type,) = @_;
my $opt_d = $db->[1];
#printf STDERR "LOAD: %s ...\n", $opt_d;
my $key = "bpodata:".$EVE::Db::vtag.":$opt_d:$type";
my $d;
$d = $CC->get($key) if defined $CC;
unless (defined $d && keys %$d) {
my $sth_params = $dbh->prepare_cached(qq{
select
i.groupID,
i.typeID,
i.typeName,
i.basePrice,
t.wasteFactor,
t.researchMaterialTime,
t.productivityModifier,
t.researchProductivityTime,
t.productionTime,
t.productivityModifier,
t.techLevel,
t.researchCopyTime,
t.maxProductionLimit,
g.groupName,
c.categoryID,
c.categoryName
from
$opt_d.invBlueprintTypes t,
$opt_d.invTypes i,
$opt_d.invGroups g,
$opt_d.invCategories c
where
i.typeID = ?
and i.typeID = t.blueprintTypeID
and i.groupID = g.groupID
and g.categoryID = c.categoryID
}) or die $dbh->errstr;
$sth_params->execute($type) or die $sth_params->errstr;
$d->{params} = $sth_params->fetchrow_hashref();
$sth_params->finish;
my $sth_product = $dbh->prepare_cached(qq{
select
i.typeID,
i.typeName,
i.groupID,
i.basePrice,
i.portionSize,
g.groupName,
c.categoryID,
c.categoryName
from
$opt_d.invBlueprintTypes t,
$opt_d.invTypes i,
$opt_d.invGroups g,
$opt_d.invCategories c
where
t.blueprintTypeID = ?
and i.typeID = t.productTypeID
and i.groupID = g.groupID
and g.categoryID = c.categoryID
}) or die $dbh->errstr;
$sth_product->execute($type) or die $sth_product->errstr;
$d->{product} = $sth_product->fetchrow_hashref();
$sth_product->finish;
my $seedtab = "eve.invSeeds";
my $seedcond = "";
if ($db->[3] =~ /:trd:/) {
$seedtab = "$opt_d.crpNPCCorporationTrades";
$seedcond = "";
} elsif ($db->[3] =~ /:trdsd:/) {
$seedtab = "$opt_d.crpNPCCorporationTrades";
$seedcond = "and t.supplyDemand > 0";
}
my $nametab;
if ($db->[3] =~ /:en:/) {
$nametab = "$opt_d.eveNames";
} elsif ($db->[3] =~ /:in:/) {
$nametab = "$opt_d.invNames";
} else {
die "no known name strategy";
}
my $sth_sellers = $dbh->prepare_cached(qq{
select
itemName,
itemID,
format(min(security),5),
format(max(security),5)
from
(
select
n.itemName,
n.itemID,
m.security
from
$seedtab t,
$nametab n,
$opt_d.staStations s,
$opt_d.mapSolarSystems m
where
t.typeID = ?
$seedcond
and t.corporationID = n.itemID
and s.corporationID = t.corporationID
and s.solarSystemID = m.solarSystemID
) S
group by
itemName,
itemID
}) or die $dbh->errstr;
$sth_sellers->execute($type) or die $sth_sellers->errstr;
$d->{sellers} = $sth_sellers->fetchall_arrayref();
$sth_sellers->finish;
my %rids = ();
$d->{reqs} = [];
$d->{materials} = [];
if ($db->[3] =~ /:itm:/) {
my $sth_reqs = $dbh->prepare_cached(qq{
select
i.typeName,
t.quantity,
t.materialTypeID
from
$opt_d.invTypeMaterials t,
$opt_d.invTypes i
where
t.typeID = ?
and t.materialTypeID = i.typeID
}) or die $dbh->errstr;
$sth_reqs->execute($d->{product}->{typeID}) or die $sth_reqs->errstr;
while (my $r = $sth_reqs->fetchrow_hashref()) {
next unless $r;
push @{$d->{reqs}}, $r;
$rids{$r->{materialTypeID}}++;
}
$sth_reqs->finish();
my $sth_materials = $dbh->prepare_cached(qq{
select
c.categoryName,
a.activityName,
i.typeID,
i.typeName,
t.quantity,
t.damagePerJob,
t.requiredTypeID,
t.recycle
from
$opt_d.ramTypeRequirements t,
$opt_d.ramActivities a,
$opt_d.invTypes i,
$opt_d.invGroups g,
$opt_d.invCategories c
where
t.typeID = ?
and t.activityID = a.activityID
and t.requiredTypeID = i.typeID
and i.groupID = g.groupID
and g.categoryID = c.categoryID
}) or die $dbh->errstr;
$sth_materials->execute($type) or die $sth_materials->errstr;
while (my $r = $sth_materials->fetchrow_hashref()) {
next unless $r;
if ($r->{recycle}) {
$sth_reqs->execute($r->{requiredTypeID}) or die $sth_reqs->errstr;
my $D = [];
while (my $R = $sth_reqs->fetchrow_hashref()) {
next unless $R;
$R->{quantity} *= $r->{quantity};
push @$D, $R;
}
$sth_reqs->finish();
$r->{_recycle} = $D;
}
push @{$d->{materials}}, $r;
$rids{$r->{requiredTypeID}}++;
}
$sth_materials->finish();
} elsif ($db->[3] =~ /:ta[rmt]:/) {
my $rfrag = ($db->[3] =~ /:tar:/) ? "t.recycle" : "0 as recycle";
my $tfrag = ($db->[3] =~ /:tat:/) ? "TL2MaterialsForTypeWithActivity" : "typeActivityMaterials";
my $afrag = ($db->[3] =~ /:tat:/) ? "activity" : "activityID";
my $aname = ($db->[3] =~ /:bact:/) ? "dbo.ramActivities" : "$opt_d.ramActivities";
my $sth_materials = $dbh->prepare_cached(qq{
select
c.categoryName,
a.activityName,
i.typeID,
i.typeName,
t.quantity,
t.damagePerJob,
t.requiredTypeID,
0 as recycle -- $rfrag
from
$opt_d.$tfrag t,
$aname a,
$opt_d.invTypes i,
$opt_d.invGroups g,
$opt_d.invCategories c
where
t.typeID = ?
and t.$afrag = a.activityID
and i.groupID = g.groupID
and g.categoryID = c.categoryID
and t.requiredTypeID = i.typeID
}) or die $dbh->errstr;
$sth_materials->execute($type) or die $sth_materials->errstr;
while (my $r = $sth_materials->fetchrow_hashref()) {
next unless $r;
if ($r->{activityName} eq 'Manufacturing' &&
($r->{damagePerJob} == 1 && $r->{categoryName} =~ /^(Material|Commodity)$/)) {
my $R = {
'materialTypeID' => $r->{requiredTypeID},
'quantity' => $r->{quantity},
'typeName' => $r->{typeName},
};
push @{$d->{reqs}}, $R;
} else {
push @{$d->{materials}}, $r;
}
$rids{$r->{requiredTypeID}}++;
}
$sth_materials->finish();
} else {
die "no known materials strategy: ".$db->[3];
}
for my $id (keys %rids) {
my $bpsth = $dbh->prepare_cached(qq{
select
b.bluePrintTypeID,
t.typeName,
b.productionTime
from
$opt_d.invBlueprintTypes b,
$opt_d.invTypes t
where
b.productTypeID = ?
and b.bluePrintTypeID = t.typeID
}) or die $dbh->errstr;
$bpsth->execute($id) or die $bpsth->errstr;
$d->{"rid:$id"} = $bpsth->fetchall_arrayref;
$bpsth->finish;
}
####
if (defined $d && keys %$d) {
$CC->set($key, $d) if defined $CC;
}
}
return $d;
}
sub urlify ($){
my ($s,) = @_;
$s =~ s/(\W)/sprintf("%%%02x", ord($1))/ige;
return $s;
}