package Opals::Eq_SolrIndex;

#require Exporter;
#@ISA       = qw(Exporter);

# Version number
$VERSION   = 0.01;      
use utf8;

#use utf8;
use strict;
use Encode;
use LWP::UserAgent;
use HTTP::Request::Common;
use Time::localtime;
use constant IND_UPDATE_BATCH_SIZE => 20;
use Opals::Equipment qw(

    eq_categoryMapList

);

my $tm = localtime;
my $dateToday = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday, $tm->hour, $tm->min, $tm->sec);

my $sortFieldMap={
    eq_name =>'eq_name_sort+<sortDir>,1_sort+<sortDir>,3_sort+<sortDir>,rid_sort+<sortDir>',
    1 => '1_sort+<sortDir>,eq_name_sort+<sortDir>,3_sort+<sortDir>,rid_sort+<sortDir>',
    3 => '3_sort+<sortDir>,eq_name_sort+<sortDir>,1_sort+<sortDir>,rid_sort+<sortDir>',
};

my $facetFieldMap = {
    category=>"category_facet",
    building=>"building_facet"
};

sub new {

    my $class = shift;
    my (%param) = (@_);
    my $dbh = $param{'dbh'};
    return unless $dbh;
    my $this = {
        dbh => $dbh,
    };
    bless $this, $class;
    return $this;
}

################################################################################
# Indexer 
# build docs get input from database (_getDataFromDB())
#

sub eq_slr_updateIndex {
    
    my $this = shift;
    my $dbh = $this->{'dbh'};
    my $catMapList = eq_categoryMapList($dbh);
    my $ridList = $this->eq_getDocList_update();
    while (scalar(@$ridList) > 0) {
        my $ridListStr = join (",", @$ridList);
        if (scalar(@$ridList)> 0){
            if ($this->eq_slr_doDeleteIndex($ridList)){
                my $rs = $this->_getDataFromDB({ridList=>$ridListStr});
                my $doc = $this->eq_getDocListfromRecordList({recordset=>$rs, catMapList=>$catMapList});
                if($this->_postRequest("<add>$doc</add>") &&  $this->_postRequest("<commit/>")){
                    $dbh->do("update eq_records set indexed = '1' where rid in ($ridListStr)");
                }
            }
        }
        $ridList = $this->eq_getDocList_update();
    }
    $dbh->do("update eq_csvImport set status='done' where (countImported>0 && countImported=countProcessed) && (status='indexing')");
}

sub eq_slr_deleteIndex {

    my $this = shift;
    my $dbh = $this->{'dbh'};
    my $bcList = $this->_getDeletedBarcodeList({size=>10});
    my $ret="";
    while(scalar(@{$bcList}) > 0){
        my @bcCondArr=();
        my @ridList = ();
        foreach my $bc(@{$bcList}){
            $bc->{'barcode'} =~ s/^\s+|\s+$//g;
            if ($bc->{'barcode'} ne ""){
                push @bcCondArr,"eq_barcode:$bc->{'barcode'}";
                push @ridList, $bc->{'rid'};
            }
        }
        my $ridListStr = join ("," , @ridList);
        my $bcCond = join( " OR ", @bcCondArr);
        if ($this->eq_slr_doDeleteIndex(\@ridList)) {
        #if($this->_postRequest("<delete><query>db:equipment AND($bcCond)</query></delete>")){
        #    $this->_postRequest("<commit/>");
        $dbh->do("update eq_records set indexed='1' where rid in ($ridListStr)");
            $bcList = $this->_getDeletedBarcodeList({size=>10});
        #    $ret .= $bcCond;
        }
        else{
            last;
        }
    }
    return $ret;
}
sub eq_slr_doDeleteIndex {

    my $this = shift;

    my $ridList = shift; 
    my $ridCond="";
    my @ridCondArr=();

    foreach my $rid(@$ridList){
        if ($rid ne ""){
            push @ridCondArr,"rid:$rid";
        }
    }
    my $ridCond = join( " OR ", @ridCondArr);
    if($this->_postRequest("<delete><query>db:equipment AND($ridCond)</query></delete>")){
        $this->_postRequest("<commit/>");
        return 1;
    }
    return 0;
}

sub _getDeletedBarcodeList {
    my $this = shift;
    my $dbh = $this->{'dbh'};
    my ($params) = @_;
    my $size = $params->{'size'} || 1;
    my @list = ();
    my $sql = "select i.rid,i.barcode from eq_items i inner join eq_records r using(rid) where i.deleted ='1' && r.indexed='0' limit $size";
    my $sth = $dbh->prepare($sql);
    $sth->execute();
    while ( my ($rid,$barcode) = $sth->fetchrow_array){
        $barcode =~ s/^_*(.+?)(_[\d]+)?$/$1/;
        push @list, {
            rid     => $rid,
            barcode => $barcode
        };
    }
    return \@list;
}

sub _getDataFromDB {

    my $this = shift;
    my $dbh = $this->{'dbh'};
    my ($params) = @_;
    my $buildings = getBuildingList($dbh);    
    my $sql = <<_SQL_;
select r.rid,r.rname as name,r.category,r.container,
    i.iid, i.barcode,
    i.typeId,
    i.copyNo,
    i.available
from eq_records r 
inner join eq_items i on r.rid=i.rid && r.deleted='0' && i.deleted='0'
where r.indexed='0' 
_SQL_
#where r.indexed='0' && TIMESTAMPDIFF(minute, r.createdDate,now())> 2
    my $sqlr = <<_SQLR_;
select d.id as id ,fId,fValue  
from eq_def d left outer join eq_recordFields r on d.id=r.fId && r.rid=?
where d.defType='record' 
_SQLR_

    my $sqli = <<_SQLI_;
select d.id as id, sfId, replace(replace(sfValue,CHAR(194),''),CHAR(160),'') as sfValue 
from eq_def d left outer join  eq_itemFields itf on d.id=itf.sfId && itf.rid=? && itf.iid=? 
where d.defType='item' 
_SQLI_

    if (defined $params && $params->{'ridList'} ne "")  {
        $sql .= " && r.rid in (" . $params->{'ridList'} . ") ";
    }
    my @rs = ();  
    my $sth = $dbh->prepare($sql);
    my $sth_r = $dbh->prepare($sqlr);
    my $sth_i = $dbh->prepare($sqli);
    $sth->execute();
    while (my $rec = $sth->fetchrow_hashref()){
        $sth_r->execute($rec->{'rid'});
        my @rf = ();
        while (my $r = $sth_r->fetchrow_hashref()){
            push @rf, {
                id     => $r->{'id'} ,
                value  => $this->_escapeXMLChars($r->{'fValue'}),
            };
        }
        my @itf =();
        my $bldCode= "";
        $sth_i->execute($rec->{'rid'},$rec->{'iid'});
        while(my $i = $sth_i->fetchrow_hashref()){
            push @itf, {
                id    => $i->{'id'},
                value => $this->_escapeXMLChars($i->{'sfValue'}),
            };
            if ($i->{'id'} eq '18' && $i->{'sfValue'} ne "" && $bldCode eq ""){  
                $bldCode = $i->{'sfValue'};    
            }
        }
        if ($bldCode ne ""){
            push @itf, {id    => "bldCode",     value => $bldCode } ;
            push @itf, {id    => "bldName",     value => $this->_escapeXMLChars($buildings->{$bldCode}->{'name'}) };
            push @itf, {id    => "bldAddress",  value => $this->_escapeXMLChars($buildings->{$bldCode}->{'address'}) };
            push @itf, {id    => "bldCity",     value => $this->_escapeXMLChars($buildings->{$bldCode}->{'city'}) };
            push @itf, {id    => "bldState",    value => $this->_escapeXMLChars($buildings->{$bldCode}->{'state'}) };
        }
        else{
            push @itf, {id    => "bldCode",     value => ""} ;
            push @itf, {id    => "bldName",     value => ""} ;
            push @itf, {id    => "bldAddress",  value => ""} ;
            push @itf, {id    => "bldCity",     value => ""} ;
            push @itf, {id    => "bldState",    value => ""} ;
        }
        push @rs , {
            rid     => $rec->{'rid'},
            eqName  => $rec->{'name'},
            name    => $rec->{'name'},
            category=> $rec->{'category'},
            container=> $rec->{'container'},
            barcode => ($rec->{'barcode'})? $rec->{'barcode'}:$rec->{'rid'} . "_NOBC",
            iid     => $rec->{'iid'},
            typeId  => $rec->{'typeId'},
            copyNo  => $rec->{'copyNo'},
            available=>$rec->{'available'},
            rfs     => \@rf,
            itfs    => \@itf,
        };
    }
    $sth->finish;
    $sth_r->finish;
    return \@rs;
}

sub eq_getDocListfromRecordList {

    my $this = shift;
    my ($params) = @_;
    my $rs = $params->{'recordset'};
    my $catMapList = $params->{'catMapList'};

    my $docXml = "";
    my @tmpArr= ();
    my $cat = "";
    foreach my $r (@{$rs}){
        @tmpArr= ();
        $docXml .= "<doc>";
        $docXml .= "<field name=\"db\">equipment</field>";
        $docXml .= "<field name=\"id\">" . "eq_" . $this->_escapeXMLChars($r->{'barcode'}) . "</field>";
        $docXml .= "<field name=\"rid\">" .  $r->{'rid'} . "</field>";
        $docXml .= "<field name=\"eq_name\">" .  $this->_escapeXMLChars($r->{'eqName'}) . "</field>";
        @tmpArr= split (/,/,$r->{'category'});
        if (scalar(@tmpArr)>0){
            foreach my $c (@tmpArr){
                $docXml .= "<field name=\"category\">" . $c . "</field>";
            }
        }
        else{
            $docXml .= "<field name=\"category\">" .  $r->{'category'} . "</field>";
        }
        
        if (scalar(@tmpArr)>0){
            foreach my $c (@tmpArr){
                $cat = ($catMapList->{$c})? $catMapList->{$c} : "";
                $docXml .= "<field name=\"categorySrch\">" . $cat . "</field>";
            }
        }
        else{
            $cat = ($catMapList->{$r->{'category'}})?$catMapList->{$r->{'category'}} : "";
            $docXml .= "<field name=\"categorySrch\">" . $cat . "</field>";
        }
        $docXml .= "<field name=\"container\">" . $this->_escapeXMLChars($r->{'container'}) . "</field>";
        $docXml .= "<field name=\"eq_barcode\">" . $this->_escapeXMLChars($r->{'barcode'}) . "</field>";
        $docXml .= "<field name=\"iid\">" .  $r->{'iid'} . "</field>";
        $docXml .= "<field name=\"typeId\">" .  $this->_escapeXMLChars($r->{'typeId'}) . "</field>";
        $docXml .= "<field name=\"copyNo\">" .  $this->_escapeXMLChars($r->{'copyNo'}) . "</field>";
        $docXml .= "<field name=\"available\">" .  $r->{'available'} . "</field>";
        if ($r->{'rfs'}) {
            foreach my $rf (@{$r->{'rfs'}}){
                $docXml .= "<field name=\"" . $rf->{'id'} . "\">" . $this->_escapeXMLChars($rf->{'value'}) . "</field>";
                #$docXml .= "<field name=\"" . $rf->{'id'} . "\">" . $rf->{'value'}  . "</field>";
            }
        }
        if ($r->{'itfs'}) {
            foreach my $itf (@{$r->{'itfs'}}){
                $docXml .= "<field name=\"" . $itf->{'id'} . "\">" . $this->_escapeXMLChars($itf->{'value'}) . "</field>";
                #$docXml .= "<field name=\"" . $itf->{'id'} . "\">" . $itf->{'value'} . "</field>";
            }
        }
        $docXml .= "</doc>";
    }
    return $docXml;
}

sub eq_getSolrSrvInfo {

    my $sHost   = Opals::Context->config('sHost');
    my $sPort   = Opals::Context->config('sPort');
    my $sDatabase = Opals::Context->config('zDatabase');
    return ($sHost,$sPort,$sDatabase);
}

sub eq_getDocList_update {
    my $this = shift;
    my $dbh = $this->{'dbh'};

    my $sth = $dbh->prepare("select rid from eq_records where indexed ='0' order by rid limit 20");
    my @ridList = ();
    $sth->execute();
    while(my $rec = $sth->fetchrow_hashref){
        push @ridList, $rec->{'rid'};
    }
    return \@ridList;
}

sub _postRequest {
    
    my $this = shift;
    my ($xml) = @_;

    my($sHost,$sPort,$sDatabase) = $this->eq_getSolrSrvInfo();
    
    my $url = "http://$sHost:$sPort/solr/$sDatabase/update";
    my $req = HTTP::Request->new(POST => $url);
    my $timeout = 600;
    my $ua = LWP::UserAgent->new(agent => 'OPALS');
    $ua->timeout($timeout);
    $ua->agent("SolrHTTPUpdateHandlerAgent");
    $req->content_type('Content-type:text/xml; charset=utf-8');
    $req->content($xml);
    my $res = $ua->request($req);
    return $res->is_success;
}

sub _querySolr{

    my($url)=@_;
    my $timeout = 600;
    my $userAgent = LWP::UserAgent->new(agent   => 'OPALS', timeout=>$timeout);
    my $request = HTTP::Request->new(GET => $url); 
    my $response = $userAgent->request($request );
    return $response->content;
}

sub getSearchHits {
    my ($xml) = @_;
    my $hits=0;
    if($xml =~ m/<result name="response" numFound="([\d]+)" start="([\d]+)"\/*>/){
        $hits=$1;
    }
    return $hits;
}

sub getGroupFound {
    my ($xml) = @_;
    my $hits=0;
    if($xml =~ m/<int name="ngroups">([\d]+)<\/int>/){
        $hits=$1;
    }
    return $hits;
}

sub getRecordIdList {
    
    my ($xml) = @_;
    my @rId = ();
    my $tmpXml = $xml;
    my $recXml="";
    while($tmpXml =~ m/<doc>(.*?)<\/doc>(.*)/s){
        $recXml=$1;
        $tmpXml=$2;
        if($recXml =~ m/<str name="rid">(.*?)<\/str>/s){
            push @rId, $1;
        }
    }
    return \@rId;
}

sub getFacetList {

    my ($xml) = @_;
    my $tmpXml;
    my $facetList=[];
    while (my ($k,$v) = each %{$facetFieldMap}){
        $tmpXml = $xml;
        if($tmpXml =~ /<lst name="$v">(.*?)<\/lst>/){
            $tmpXml = $1;
            my $fList=[];
            while($tmpXml =~ m/<int name="(.*?)">(.*?)<\/int>(.*)/s){
                my $fc=$1;
                $tmpXml = $3;
                push @$fList, {field=>$1,value=>$2} if ($fc ne '');
            }
            push @$facetList, {field=>$v,facetList=>$fList} ;   
        }
    }
    return $facetList;
}

sub getRsCategoryFacet {
    
    my ($xml) = @_;
    my $tmpXml = $xml;
    my $categoryFactList = [];
    if($tmpXml =~ /<lst name="category_facet">(.*?)<\/lst>/){
        $tmpXml = $1;
        while($tmpXml =~ m/<int name="(.*?)">(.*?)<\/int>(.*)/s){
            push @$categoryFactList, {
                field=>$1,
                value=>$2
            };
            $tmpXml = $3;
        }
    }
    return $categoryFactList;
}

sub getRsBuildingFacet {
    
    my ($xml) = @_;
    my $tmpXml = $xml;
    my $buildingFactList = [];
    if($tmpXml =~ /<lst name="building_facet">(.*?)<\/lst>/){
        $tmpXml = $1;
        while($tmpXml =~ m/<int name="(.*?)">(.*?)<\/int>(.*)/s){
            push @$buildingFactList, {
                field=>$1,
                value=>$2
            };
            $tmpXml = $3;
        }
    }
    return $buildingFactList;
}

sub _escapeXMLChars {

    my $this = shift;
    my ($str) = @_;
    $str =~ s/&/&amp;/sg;
    $str =~ s/</&lt;/sg;
    $str =~ s/>/&gt;/sg;
    $str =~ s/"/&quot;/sg;
    $str =~ s/'/&apos;/sg;
    return $str;
}

sub getRecordFields {

    my ($xml,$fieldMap) = @_;
    my $fieldMap = {
        rid             =>  "rid",
        eq_name         =>  "eq_name",
        category_facet  =>  "category",
        1               =>  "manufacturer",
        3               =>  "model",
        eq_barcode      =>  "barcode",
        5               =>  "serialNumber",
        38              => "status",
        11              => "location",
        41              => "assignedLName",
        46              => "cartNumber",
    };
    my $category = {
        29  => "Computer Equipment",
        30  => "Laptop"
    };

    my @recordList = ();
    my $record;
    my $tmpXml = $xml;
    my $recXml;
    my $fieldType="str|float|int|date";
    while ( $tmpXml =~ m/<doc>(.*?)<\/doc>(.*)/s ) {
        $recXml=$1;
        $tmpXml=$2;
        $record=undef;
        foreach my $field(keys %{$fieldMap}){
            if ($recXml =~ m/(<$fieldType) name="$field">(.*?)<\/($fieldType)>/s){
                $record->{$fieldMap->{$field}}=$2;
            }
            elsif($recXml =~ m/<arr name="$field">(.*?)<\/arr>/s){
                my $arrXml=$1;
                while($arrXml =~ m/<($fieldType)>(.*?)<\/($fieldType)>(.*)/s){
                    push @{$record->{$fieldMap->{$field}}},{item=>$category->{$2}}  if ($1 eq $3);
                    $arrXml=$4;
                }
            }
        }
        push @recordList, $record if(defined $record);
    }
    return \@recordList;
}

sub getBuildingList {

    my ($dbh) = @_;
    my $sql= <<_SQL_;
select code,name,address,city,state from eq_locationDirectory order by code;
_SQL_

    my $sth = $dbh->prepare($sql);
    my $list;
    $sth->execute();
    while (my $b = $sth->fetchrow_hashref()) {
        if (!$list->{$b->{'code'}}){
            $list->{$b->{'code'}}->{'code'} = $b->{'code'};
            $list->{$b->{'code'}}->{'name'} = $b->{'name'};
            $list->{$b->{'code'}}->{'address'} = $b->{'address'};
            $list->{$b->{'code'}}->{'city'} = $b->{'city'};
            $list->{$b->{'code'}}->{'state'} = $b->{'state'};
        }
    }
    return $list;
}

=item
sub eq_slr_updateIndexFromDB {
    
    my $this = shift;
    my $dbh = $this->{'dbh'};
    my ($params) = @_;
    my $rs = $this->_getDataFromDB();
    my $recordFields = "recordFields";
    my $docXml = "<add>";
    my $counter = 0;
    my @tmpArr= ();
    my $catMapList = eq_categoryMapList($dbh);

    foreach my $r (@{$rs}){
        @tmpArr= ();
        $docXml .= "<doc>";
        $docXml .= "<field name=\"db\">equipment</field>";
        $docXml .= "<field name=\"id\">" . "eq_" . $this->_escapeXMLChars($r->{'barcode'}) . "</field>";
        $docXml .= "<field name=\"rid\">" .  $r->{'rid'} . "</field>";
        $docXml .= "<field name=\"eq_name\">" .  $this->_escapeXMLChars($r->{'eqName'}) . "</field>";
        @tmpArr= split (/,/,$r->{'category'});
        if (scalar(@tmpArr)>0){
            foreach my $c (@tmpArr){
                $docXml .= "<field name=\"category\">" . $c . "</field>";
            }
        }
        else{
            $docXml .= "<field name=\"category\">" .  $r->{'category'} . "</field>";
        }
        if (scalar(@tmpArr)>0){
            foreach my $c (@tmpArr){
                $docXml .= "<field name=\"categorySrch\">" . $catMapList->{$c} . "</field>";
            }
        }
        else{
            $docXml .= "<field name=\"categorySrch\">" . $catMapList->{$r->{'category'}} . "</field>";
        }
        $docXml .= "<field name=\"container\">" .  $r->{'container'} . "</field>";
        $docXml .= "<field name=\"eq_barcode\">" .  $r->{'barcode'} . "</field>";
        $docXml .= "<field name=\"iid\">" .  $r->{'iid'} . "</field>";
        $docXml .= "<field name=\"typeId\">" . $this->_escapeXMLChars($r->{'typeId'}) . "</field>";
        $docXml .= "<field name=\"copyNo\">" .  $r->{'copyNo'} . "</field>";
        $docXml .= "<field name=\"available\">" .  $r->{'available'} . "</field>";
        if ($r->{'rfs'}) {
            foreach my $rf (@{$r->{'rfs'}}){
                $docXml .= "<field name=\"" . $rf->{'id'} . "\">" . $rf->{'value'} . "</field>";
            }
        }
        if ($r->{'itfs'}) {
            foreach my $itf (@{$r->{'itfs'}}){
                $docXml .= "<field name=\"" . $itf->{'id'} . "\">" . $itf->{'value'} . "</field>";
            }
        }
        $docXml .= "</doc>";
    }
    $docXml .= "</add>";
    if ($this->_postRequest($docXml) && $this->_postRequest("<commit/>")){
        $dbh->do("update eq_records set indexed='1' where indexed='0' && deleted='0'");
    }
    return $docXml;
}
=cut

1;

################################################################################



