package Opals::Eq_SolrSearch;

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

# Version number
$VERSION   = 0.01;      

#use utf8;
use strict;
use Encode;
use LWP::UserAgent;
use HTTP::Request::Common;
use Time::localtime;

my $tm = localtime;

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;
}

################################################################################
# Search Solr
# 
################################################################################

################################################################################
# build Querry
#
sub eq_slr_buildSearchQuery {
    
    my $this = shift;
    my ($input) = @_;
    #my $luceneQuery ="fq=db:equipment&group.ngroups=true&group=true&group.field=rid&facet=true";
    my $luceneQuery ="fq=db:equipment";
    if ($input->{'groupBy'} eq "barcode"){
        #$luceneQuery .= "&group.ngroups=true&group=true&group.field=eq_barcode";
    }
    else{
        $luceneQuery .= "&facet=true&group.ngroups=true&group=true&group.field=rid";
    }
    while (my ($k,$v) = each %{$facetFieldMap}){
        $luceneQuery .= "&facet.field=" . $v;
    }
    my $sTerm       = $input->{'kw'};
    my $sField      = $input->{'sfield'};
    my $sExctMatch  = $input->{'exactmatch'};
    my $sortAttr    = $input->{'sortAttr'};
    my $sortDir     = $input->{'sortOrder'};
    my $offset      = $input->{'offset'};
    my $pSize       = $input->{'pSize'};
    my $searchByCat = $input->{'searchByCat'};
    my $catCode     = $input->{'cat'};
    my $building    = $input->{'bldList'};
    my $notContain  = $input->{'notContain'};
    
    my ($catSearch,$simpleSearch,$advancedSearch) = (0,0,0);
    $catSearch = ($searchByCat  && $searchByCat > 0)? 1: 0;
    $simpleSearch = ($input->{'kw'} && $input->{'kw'} ne "") ? 1:0;
    $advancedSearch = ($input->{'kw1'} ne "" || $input->{'kw2'} ne "" || $input->{'kw3'} ne "")?1:0;

    if ($catSearch == 1) {
        if ($catCode && $catCode > 0){
            $luceneQuery .= "&q=category:($catCode)";
        }
        else{
            $luceneQuery .= "&q=category:\*";
        }
    }
    elsif ($advancedSearch == 1){
        my ($sField1,$sField2,$sField3)= ("","","");
        my ($q,$q1,$q2,$q3)=("","","","");
        if ($input->{'kw1'} ne "" ){
            $q1=$input->{'sfield1'} . ":(" . $input->{'kw1'} . ") ";
        }
        if ($input->{'kw2'} ne "" ){
            $q2 .=$input->{'sfield2'} . ":(" . $input->{'kw2'} . ") ";
        }
        if ($input->{'kw3'} ne "" ){
            $q3 .=$input->{'sfield3'} . ":(" . $input->{'kw3'} . ")";
        }
        $q = $q1;
        if ($q2 ne "" && $q3 ne ""){
            $q .= uc($input->{'cfield1'}) . " (" . $q2 .  uc($input->{'cfield2'}) ." ". $q3 . ")";
        }
        elsif ($q2 ne "" ){
            $q .= uc($input->{'cfield1'}) . " ". $q2;
        }
        $luceneQuery .= "&q=$q";
    }
    else { #simple search
        if ($sField eq "0"){
            if ($sExctMatch && $sExctMatch eq "1"){
                $luceneQuery .= "&q=eq_anywhere_exct:(\"$sTerm\")";
            }else{
                $luceneQuery .= "&q=eq_anywhere:($sTerm)";
            }
        }
        else{
            if ($sExctMatch && $sExctMatch eq "1"){
                $luceneQuery .= "&q=". $sField ."_exct:(\"" . $sTerm ."\")";
            }else{
                if ($notContain && $notContain eq '1') {
                    $luceneQuery .= "&q=!$sField:($sTerm)";
                }
                else{
                    $luceneQuery .= "&q=$sField:($sTerm)";
                }
            }
        }
    }

    if (defined $building && $building ne "" && $building ne '0' ){
        $luceneQuery .= " AND 18:($building)";
    }

    $luceneQuery .= "&start=" . $offset . "&rows=" . $pSize;

    my $sortCond = $sortFieldMap->{$sortAttr};
    if ($sortDir eq "1"){
        $sortDir = "asc";
    }
    else{
        $sortDir = "desc";
    }
        $sortCond =~ s/<sortDir>/$sortDir/g;
    $luceneQuery .= "&sort=$sortCond";
    return "$luceneQuery";
}

sub eq_slr_search {

    my $this = shift;
    my $dbh     = $this->{'dbh'};
    my ($params)= @_;
    my ($hits,@result) = (0,());
    if (!defined $params->{'lQuery'} || $params->{'lQuery'} eq ''){
        return {hits=>0,recordList=>undef};
    }
    my($sHost,$sPort,$sDatabase) = $this->eq_getSolrSrvInfo();
    my $url="http://$sHost:$sPort/solr/$sDatabase/select?" . $params->{'lQuery'} ;

    my $xmlStr = _querySolr($url);
    if ($params->{'displayStyle'} eq "linear"){
        $hits = getSearchHits($xmlStr);
    }
    else{
        $hits = getGroupFound($xmlStr);
    }
    my $rIdList = getRecordIdList($xmlStr);
    my $facetList = getFacetList($xmlStr);
    my $fieldMap = {};
    my $recList = getRecordFields($dbh,$xmlStr,$fieldMap);
    return {hits=>$hits,recordList=>$recList,facetList=>$facetList};
}

sub eq_slr_buildQuery_recordList_json {

    my $this = shift;
    my ($input) = @_;

#    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 $luceneQuery ="fq=db:equipment";
    my $sTerm       = $input->{'kw'};
    my $sField      = $input->{'sfield'};
    my $sExctMatch  = $input->{'exactmatch'};
    my $sortAttr    = $input->{'sortAttr'};
    my $sortDir     = $input->{'sortOrder'};
    my $offset      = $input->{'offset'};
    my $pSize       = $input->{'pSize'};
    my $searchByCat = $input->{'searchByCat'};
    my $catCode     = $input->{'cat'};
    my $building    = $input->{'bldList'} ;
    my $ridList     = $input->{'ridList'};

    my ($catSearch,$simpleSearch,$advancedSearch) = (0,0,0);
    $catSearch = ($searchByCat  && $searchByCat > 0)? 1: 0;
    $simpleSearch = ($input->{'kw'} && $input->{'kw'} ne "") ? 1:0;
    $advancedSearch = ($input->{'kw1'} ne "" || $input->{'kw2'} ne "" || $input->{'kw3'} ne "")?1:0;

    if ($catSearch == 1) {
        if ($catCode && $catCode > 0){
            $luceneQuery .= "&q=category:($catCode)";
        }
        else{
            $luceneQuery .= "&q=category:\*";
        }
    }
    elsif ($advancedSearch == 1){
        my ($sField1,$sField2,$sField3)= ("","","");
        my $q="";
        if ($input->{'kw1'} ne "" ){
            $q=$input->{'sfield1'} . ":(" . $input->{'kw1'} . ") ";
        }
        if ($input->{'kw2'} ne "" ){
            $q .= uc($input->{'cfield1'}) . " ";
            $q .=$input->{'sfield2'} . ": (" . $input->{'kw2'} . ") ";
        }
        if ($input->{'kw3'} ne "" ){
            $q .= uc($input->{'cfield2'}) . " ";
            $q .=$input->{'sfield3'} . ":(" . $input->{'kw3'} . ")";
        }
        $luceneQuery .= "&q=$q";
    }
    else { #simple search
        if ($sField eq "0"){
            if ($sExctMatch && $sExctMatch eq "1"){
                $luceneQuery .= "&q=eq_anywhere_exct:(\"$sTerm\")";
            }else{
                $luceneQuery .= "&q=eq_anywhere:($sTerm)";
            }
        }
        else{
            if ($sExctMatch && $sExctMatch eq "1"){
                $luceneQuery .= "&q=". $sField ."_exct:(\"" . $sTerm ."\")";
            }else{
                $luceneQuery .= "&q=$sField:($sTerm)";
            }
        }
    }

    if (defined $building && $building ne '' && $building ne '0'){
        $luceneQuery .= " AND 18:('$building')";
    }

    if ($ridList eq "all"){
        my $sortCond = $sortFieldMap->{$sortAttr};
        if ($sortDir eq "1"){
            $sortDir = "asc";
        }
        else{
            $sortDir = "desc";
        }
        $sortCond =~ s/<sortDir>/$sortDir/g;
        $luceneQuery .= "&sort=$sortCond";
    }
    else{
        my @rids = split(/,/,$ridList);
        my $ridStr="";
        foreach my $id(@rids){
            $ridStr .= " OR " if $ridStr ne "";
            $ridStr .= "(rid:$id AND eq_name:[* TO *] )";
        }
        $luceneQuery = "&q=(".$ridStr .")";
    }
    $luceneQuery .= "&fl=rid,eq_name,container,category_facet,1,3,14,16,27,28,33,36,copyNo,eq_barcode,categorySrch,typeId,iid,5,6,7,8,11,18,26,31,37,38,39,40,41,42,43,44,45,46,47,48";
    $luceneQuery .= ",bldCode,bldName,bldAddress,bldCity,bldState";
    $luceneQuery .= "&wt=json&rows=2147483647"; #get all records
    return $luceneQuery
}

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 _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;
    }
    else{
        if($xml =~ m/<int name="matches">([\d]+)<\/int>/){
            $hits=$1;
        }
    }
    return $hits;
}

sub getGroupFound {
    my ($xml) = @_;
    my $hits=0;
    #if($xml =~ m/<int name="matches">([\d]+)<\/int>/){
    #    $hits=$1;
    #}
    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 getRecordFields {

    my ($dbh, $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 $showOnSearchFieldMap = getShowOnSearchFields($dbh);
    $showOnSearchFieldMap->{'rid'}      = "rid";
    $showOnSearchFieldMap->{'eq_name'}  = "eq_name";
    $showOnSearchFieldMap->{'category_facet'}  =  "category";
    $showOnSearchFieldMap->{'eq_barcode'}  =  "barcode";
    $showOnSearchFieldMap->{'typeId'}  =  "typeId";
  
    my $category =  getCategoryList($dbh);

    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}){
        foreach my $field(keys %{$showOnSearchFieldMap}){
            if ($recXml =~ m/(<$fieldType) name="$field">(.*?)<\/($fieldType)>/s){
                $record->{$showOnSearchFieldMap->{$field}}= escapeXMLChars($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);
                    push @{$record->{$showOnSearchFieldMap->{$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->{'adddress'};
            $list->{$b->{'code'}}->{'city'} = $b->{'city'};
            $list->{$b->{'code'}}->{'state'} = $b->{'state'};
        }
    }
    return $list;
}

sub getCategoryList {

    my ($dbh) = @_;
    my $sth = $dbh->prepare("select id,name from eq_category");
    my $list;
    $sth->execute();
    while (my $b = $sth->fetchrow_hashref()) {
        $list->{$b->{'id'}} = $b->{'name'};
    }
    return $list;
}

sub escapeXMLChars {

    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 getShowOnSearchFields {

    my ($dbh) = @_;

    my $sth = $dbh->prepare("select id,name, showOnSearch from eq_def where showOnSearch=1");
    my $list;
    $sth->execute();
    while (my $f = $sth->fetchrow_hashref()) {
        $list->{$f->{'id'}} = lc($f->{'id'});
    }
    return $list;
}
#test for SesssionHdl
sub eq_slr_buildSrchQuery_SessionHdl {
    my $this = shift;
    my ($input) = @_;
    my $luceneQuery ="fq=db:equipment";
    $luceneQuery .= "&group.ngroups=true&group=true&group.field=rid";
    my $sTerm       = $input->{'kw'};
    my $sField      = $input->{'sfield'};
    my $sExctMatch  = $input->{'exactmatch'};
    my $sortAttr    = $input->{'sortAttr'};
    my $sortDir     = $input->{'sortOrder'};
    my $offset      = $input->{'offset'};
    my $pSize       = $input->{'pSize'};
    my $searchByCat = $input->{'searchByCat'};
    my $catCode     = $input->{'cat'};
    my $building    = $input->{'bldList'};
    my $notContain  = $input->{'notContain'};
    
    my ($catSearch,$simpleSearch,$advancedSearch) = (0,0,0);
    $catSearch = ($searchByCat  && $searchByCat > 0)? 1: 0;
    $simpleSearch = ($input->{'kw'} && $input->{'kw'} ne "") ? 1:0;
    #$advancedSearch = ($input->{'kw1'} ne "" || $input->{'kw2'} ne "" || $input->{'kw3'} ne "")?1:0;

    if ($catSearch == 1) {
        if ($catCode && $catCode > 0){
            $luceneQuery .= "&q=category:($catCode)";
        }
        else{
            $luceneQuery .= "&q=category:\*";
        }
    }
    else { 
        if ($sField eq "0"){
            if ($sExctMatch && $sExctMatch eq "1"){
                $luceneQuery .= "&q=eq_anywhere_exct:(\"$sTerm\")";
            }else{
                $luceneQuery .= "&q=eq_anywhere:($sTerm)";
            }
        }
        else{
            if ($sExctMatch && $sExctMatch eq "1"){
                $luceneQuery .= "&q=". $sField ."_exct:(\"" . $sTerm ."\")";
            }else{
                if ($notContain && $notContain eq '1') {
                    $luceneQuery .= "&q=!$sField:($sTerm)";
                }
                else{
                    $luceneQuery .= "&q=$sField:($sTerm)";
                }
            }
        }
    }

    if (defined $building && $building ne "" && $building ne '0' ){
        $luceneQuery .= " AND 18:($building)";
    }
    $luceneQuery .= "&fl=rid,eq_name,eq_barcode";
    $luceneQuery .= "&start=" . $offset . "&rows=" . $pSize;

    my $sortCond = $sortFieldMap->{$sortAttr};
    if ($sortDir eq "1"){
        $sortDir = "asc";
    }
    else{
        $sortDir = "desc";
    }
        $sortCond =~ s/<sortDir>/$sortDir/g;
    $luceneQuery .= "&sort=$sortCond";

    return "$luceneQuery";

}

sub eq_slr_search_SessionHdl {

    my $this = shift;
    my $dbh     = $this->{'dbh'};
    my ($params)= @_;
    my ($hits,@result) = (0,());
    if (!defined $params->{'lQuery'} || $params->{'lQuery'} eq ''){
        return {hits=>0,recordList=>undef};
    }
    my($sHost,$sPort,$sDatabase) = $this->eq_getSolrSrvInfo();
    my $url="http://$sHost:$sPort/solr/$sDatabase/select?" . $params->{'lQuery'} ;

    my $xmlStr = _querySolr($url);
    if ($params->{'displayStyle'} eq "linear"){
        $hits = getSearchHits($xmlStr);
    }
    else{
        $hits = getGroupFound($xmlStr);
    }
    my $fieldMap = {};
    #my $recList = getRecordFields_SessionHdl($dbh,$xmlStr,$fieldMap);
    my $recList = getRecordFields($dbh,$xmlStr,$fieldMap);
    return {hits=>$hits,recordList=>$recList};
}

sub getRecordFields_SessionHdl {

    my ($dbh, $xml,$fieldMap) = @_;
    my $showOnSearchFieldMap;
    $showOnSearchFieldMap->{'rid'}      = "rid";
    $showOnSearchFieldMap->{'eq_name'}  = "eq_name";
    $showOnSearchFieldMap->{'eq_barcode'}  =  "barcode";
    my $category =  getCategoryList($dbh);

    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}){
        foreach my $field(keys %{$showOnSearchFieldMap}){
            if ($recXml =~ m/(<$fieldType) name="$field">(.*?)<\/($fieldType)>/s){
                $record->{$showOnSearchFieldMap->{$field}}=$2;
            }
            elsif($recXml =~ m/<arr name="$field">(.*?)<\/arr>/s){
                my $arrXml=$1;
                while($arrXml =~ m/<($fieldType)>(.*?)<\/($fieldType)>(.*)/s){
                    push @{$record->{$showOnSearchFieldMap->{$field}}},{item=>$category->{$2}}  if ($1 eq $3);
                    $arrXml=$4;
                }
            }
        }
        push @recordList, $record if(defined $record);
    }
    return \@recordList;
}


#end test for SesssionHdl
#
#
