#!/usr/bin/perl

#use utf8;
#use strict;

use Encode;
use LWP::UserAgent;
use HTTP::Request::Common;

use CGI;
use JSON;

use Opals::Context;
use Opals::Constant;
use Opals::Log;
use Opals::Eq_SolrIndex;
use Opals::User qw(
    user_currentUserID
);

use Opals::Template qw(
    tmpl_read
    tmpl_write
);
use Opals::Equipment qw(

    eq_record_idGen
    eq_record_findByRId
    eq_record_update_rname
    eq_record_addUpdate
    eq_item_addUpdateBarCodeItemType
    eq_item_addUpdate
    eq_item_deleteBarcode
    eq_item_getMaxIddByRId
    eq_record_add
    eq_category_getList

);

use Opals::Eq_Circulation qw(

    circ_getLoanListByRid

);


my $dbh = Opals::Context->dbh();
END { $dbh->disconnect(); }

my $cgi = CGI->new;
my $input = $cgi->Vars();
my $uIdInfo = user_currentUserID($dbh,$cgi);
my $categoryList    = eq_category_getList($dbh);



    my $inputData = from_json( $input->{'POSTDATA'} );
    my $data    = $inputData->{'data'};
    my $type    = lc($inputData->{'type'});
    my $op      = $inputData->{'op'};

    my $rid = $data->{'rid'};
    my $old_recInfo = getRecordInfo($dbh,$rid);
    my $rec;
    my $action="";
    if ($type eq 'record'){
        if($op =~ m/save/i ){
            $rid = saveRecord($dbh,$data);
            $action = "edit-record";
        }
    }
    elsif ($type eq 'recorditem'){
        if($op =~ m/save/i ){
            $rid = saveRecord($dbh,$data);
            my $items = $data->{'item'};
            $items->{'rid'} = $rid;
            saveItems($dbh,$items);
            $action = "add record-items";
        }    
    }
    elsif ($type eq 'item' ){
        if($op =~ m/save/i){
            saveItem($dbh,$data);
            $action = "edit-item";
        }elsif($op =~ m/remove/i){
            removeItem($dbh,$data);
            $action = "remove-item";
        }elsif($op =~ m/new/i){
            $action = "add-item";
            newItem($dbh,$data);
        }
    }


my $recInfo = getRecordInfo($dbh,$rid);
    
    my $diff;
    $diff->{'changed'} = _recordDiff($old_recInfo, $recInfo);
    $diff->{'rid'} = $rid;
    $diff->{'rec'} = getRecordInfoForLog($dbh,$rid);
    
    my $content_log = to_json($diff);
    my $log = Opals::Log->new(dbh=>$dbh);
    my $params = {
        module      => "eqmnt",
        uid         => $uIdInfo->{'uid'} || 0,
        sessionid   => $uIdInfo->{'sessionid'} || "",
        action      => $action,
        content     => $content_log
    };
    my $logId = $log->log($params);

    $dbh->do("update eq_records set logId=concat(if(logId is NULL || logId= '', '', concat(logId,',')),$logId) where rid=$rid");

    my $eq_solr = Opals::Eq_SolrIndex->new(dbh=>$dbh);
    $eq_solr->eq_slr_updateIndex();



print "Content-type: text/plain\n\n";
print to_json($recInfo,{pretty=>1}); 

exit 0;

sub _recordDiff {
    my ($old,$cur) = @_;
    my $diff;

    for my $key (keys %{$old}){
        if (ref($old->{$key}) ne 'ARRAY'){
            if ($old->{$key} ne $cur->{$key}){
                $diff->{$key} = {   
                    'old'   => $old->{$key}, 
                    'new'   => $cur->{$key}
                };
            }
        }
    }
    my $old_fields;
    foreach my $f (@{$old->{'fields'}}){
        $old_fields->{$f->{'id'}}  = $f->{'value'};
    }
    my $new_fields;
    foreach my $f (@{$cur->{'fields'}}){
        $new_fields->{$f->{'id'}}  = $f->{'value'};
    }
    foreach my $i (1,3,14,16,27,28,33,36) {
        if ($old_fields->{$i} ne $new_fields->{$i}) {
            $diff->{$i} = {
                'old'   => $old_fields->{$i},
                'new'   => $new_fields->{$i}
            };
        }
    }
#item
    my $old_items;
    my $cur_items;
    my $iid=0;
    my $tmp = {};

    foreach my $f (@{$cur->{'items'}}){
        for my $key (keys %{$f}){
            if (ref($f->{$key}) ne 'ARRAY'){
                $iid = ($key eq "iid" )?$f->{$key}:0;
                $tmp->{$key} = $f->{$key} ;
            }
            else{
                $tmp->{$key} = $f->{$key};
            }
        }
        $cur_items->{'items'}->{$iid} = $tmp;
        $iid=0;
    }
    $tmp = {};
    foreach my $f (@{$old->{'items'}}){
        for my $key (keys %{$f}){
            if (ref($f->{$key}) ne 'ARRAY'){
                $iid = ($key eq "iid" )?$f->{$key}:0;
                $tmp->{$key} = $f->{$key} ;
            }
            else{
                $tmp->{$key} = $f->{$key};
            }
        }
        $old_items->{'items'}->{$iid} = $tmp;
        $iid=0;
    }
    my $old_items_fields;
    my $new_items_fields;

    for my $k (sort keys %{$old_items->{'items'}}){
        my $old_item = $old_items->{'items'}->{$k};
        my $cur_item = $cur_items->{'items'}->{$k};
        for my $key (keys %{$old_item}){
            if (ref($old_item->{$key} ne 'ARRAY')) {
                if ($old_item->{$key} ne $cur_item->{$key}){
                    $diff->{'items'}->{$k}->{$key} = {
                        'old'   => $old_item->{$key},
                        'new'   => $cur_item->{$key}
                    };
                }
            }
            if ($key eq "fields"){
                foreach my $f (@{$old_item->{$key}}){
                    $old_items_fields->{$k}->{$f->{'id'}} = $f->{'value'};
                }
                foreach my $f (@{$cur_item->{$key}}){
                    $new_items_fields->{$k}->{$f->{'id'}} = $f->{'value'};
                }
            }
        }
    }
    for my $k (keys %{$old_items_fields}){
        foreach my $i( 5,6,7,8,9,11,18,26,31,37,38,39,40,41,42,43,44,45,46,47,48 ){
            if ($old_items_fields->{$k}->{$i} ne $new_items_fields->{$k}->{$i}){
                $diff->{'items'}->{$k}->{$i} = {
                    'old'   => $old_items_fields->{$k}->{$i},
                    'new'   => $new_items_fields->{$k}->{$i}
                };
            }
        }
    }
    return $diff;
}

sub getRecordInfo {
    
    my ($dbh,$rid) = @_;
    return if (!$rid || $rid <= 0);
    my ($id, $recordInfo) = eq_record_findByRId($dbh,{recordId=>$rid});
    my $itemList = _eq_item_findByRId($dbh, $rid);
    my $onLoanList =  circ_getLoanListByRid($dbh,$rid);
    foreach my $i(@$itemList){
        $i->{'onLoan'} = "";
        foreach my $ol (@$onLoanList){
            if ($ol->{'barcode'} eq $i->{'barcode'}){
                $i->{'onLoan'} = 'onLoan';
            }
        }
    }
    my @iListSorted = sort { $a->{'iid'} cmp $b->{'iid'} || $a->{'copyNo'} cmp $b->{'copyNo'}} @$itemList;
    my $rec = _formatRecInfo($recordInfo,\@iListSorted,$rid);
    return $rec;
}

sub getRecordInfoForLog {
    
    my ($dbh,$rid) = @_;
    my ($id, $recordInfo) = eq_record_findByRId($dbh,{recordId=>$rid});
    my $itemList = _getItemInfoForLog($dbh, $rid);
    my $onLoanList =  circ_getLoanListByRid($dbh,$rid);
    foreach my $i(@$itemList){
        $i->{'onLoan'} = "";
        foreach my $ol (@$onLoanList){
            if ($ol->{'barcode'} eq $i->{'barcode'}){
                $i->{'onLoan'} = 'onLoan';
            }
        }
    }
    my @iListSorted = sort { $a->{'iid'} cmp $b->{'iid'} || $a->{'copyNo'} cmp $b->{'copyNo'}} @$itemList;
    my $rec = _formatRecInfo($recordInfo,\@iListSorted,$rid);

    return $rec;
}

sub _getItemInfoForLog {
    
    my ($dbh, $recId)=@_;
    return undef if ($recId eq '');
    my $sth = $dbh->prepare("select iid, barcode,typeId,copyNo,i.createdDate,r.container from eq_items i inner join eq_records r using(rid) where rid=? && i.barcode not regexp '^\_\_\_'");
    my $sql = " SELECT  d.id, d.name, fdt.dataType, fdt.maxVal, i.id as i_iid, i.rid, i.sfId, i.sfValue 
                FROM    eq_def as d 
                LEFT OUTER JOIN eq_fieldDataType fdt on d.fieldType=fdt.id
                LEFT OUTER JOIN eq_itemFields as i on i.sfId = d.id && i.rid=? && i.iid=? 
                WHERE   d.defType='item' ";
    my $sth_item = $dbh->prepare($sql);
    $sth->execute($recId);
    my @itemList;
    while (my ($iid,$barcode,$typeId,$copyNo,$createdDate,$container) = $sth->fetchrow_array()){
       $sth_item->execute($recId, $iid);
       my @fields;
       my $fCount = 0;
       while(my $f = $sth_item->fetchrow_hashref()){
            push @fields, {
                id      => ($f->{'sfId'})? $f->{sfId}:$f->{'id'},
                value   => $f->{'sfValue'}, 
                name    => $f->{'name'},
            };
       }
       push @itemList, {
            rid     => $recId,
            iid     => $iid,
            barcode => $barcode,
            typeId  => $typeId,
            copyNo  => $copyNo,
            cDate   => $createdDate,
            container=>$container, 
            fields  => \@fields
       };
    }
    $sth->finish;
    $sth_item->finish;
    return \@itemList;
}

sub saveRecord {
    
    my ($dbh,$data) = @_;
    my $rid = $data->{'rid'};
    my $newRecord = 0;
    if (!defined $rid || $rid <=0 || $rid eq ""){
        $rid = eq_record_idGen($dbh);
        $newRecord = 1;
    }
    my $rname = $data->{'name'};
    my $container = $data->{'container'};
    my @categories = $data->{'categories'};
    my $category = "";
    foreach my $c (@categories){
        foreach my $cc (@{$c}){
            if ($cc->{'selected'} eq "true"){
                $category .= ($category eq "")? "":"," ;
                $category .=  $cc->{'id'};
            }
            #if ($cc->{'hasChild'} > 0){
                foreach my $ccc (@{$cc->{'children'}}){
                    if ($ccc->{'selected'} eq "true"){
                        $category .= ($category eq "")? "":"," ;
                        $category .=  $ccc->{'id'};
                    }
                }
            #}
        }
    }
    if ($newRecord){
        eq_record_add($dbh,{rid=>$rid, fValue=>$rname,category=>$category,container=>$container,reqField=>1});
    }
    else{
        eq_record_update_rname($dbh,$rid,$rname,$category,$container);
    }
    foreach my $f (@{$data->{'fields'}}){
        my $id = $f->{'id'};
        my $val = $f->{'value'};
        my $params = {rid=>$rid, fId=>$id, fValue=>$val};
        eq_record_addUpdate($dbh, $params);
    }
    $dbh->do("update eq_records set indexed='0' where rid=$rid");
    return $rid;
}

sub saveItem {
 
    my ($dbh,$data) = @_;
    my $rid= $data->{'rid'};
    my $barcode = $data->{'barcode'};
    my $curBarcode = $data->{'curBarcode'};
    my $copyNo  = $data->{'copyNo'};
    my $typeId  = $data->{'typeId'};
    my $iid     = $data->{'iid'};
    my $params =  { rid =>$rid,
                    iid =>$iid,
                    barcode=>$barcode,
                    typeId=>$typeId, 
                    copyNo=>$copyNo,
                    curBarCode=>$curBarcode,
                };
    eq_item_addUpdateBarCodeItemType($dbh, $params);
    foreach my $f(@{$data->{'fields'}}){
        my $id = $f->{'id'};
        my $val = $f->{'value'};
        my $updateAll = $f->{'updateAll'};
        my $dataType = $f->{'dataType'};
        if ($f->{'dataType'} =~ m/checkboxlist/i){
            $val ="";
            if (ref($f->{'checkedList'}) eq 'ARRAY'){
                $val = join (', ',@{$f->{'checkedList'}});
            }
        }
        $params = {iid=>$iid,rid=>$rid, sfId=>$id,sfValue=>$val};
        eq_item_addUpdate($dbh,$params);
        if ($updateAll == 1){
            $dbh->do("update eq_itemFields set sfValue='$val' where rid=$rid && sfId=$id");
        }
    }
    $dbh->do("update eq_records set indexed='0' where rid=$rid");
}

sub saveItems {
 
    my ($dbh,$data) = @_;
    my $rid= $data->{'rid'};
    my $startBarcode = $data->{'startBarcode'};
    my $curBarcode = 0;
    my $copyNo  = $data->{'copyNo'} || "";
    my $typeId  = $data->{'typeId'};
    my $iid     = $data->{'iid'} || 1;
    my $nItems  = $data->{'nOfItems'};
    my $params = {};
    my $barcode ="";
    for (my $i=0; $i<$nItems;$i++) {
        if ($i<1){
            $barcode = $startBarcode;
        }
        else {
            $barcode = _nextBarcode($barcode);
        }
        $params =  { rid =>$rid,
                    iid =>$iid,
                    barcode=>$barcode,
                    typeId=>$typeId, 
                    copyNo=>$copyNo,
                    curBarCode=>$curBarcode,
                };
        eq_item_addUpdateBarCodeItemType($dbh, $params);
        foreach my $f(@{$data->{'fields'}}){
            my $id = $f->{'id'};
            my $val = $f->{'value'};
            my $dataType = $f->{'dataType'};
            if ($f->{'dataType'} =~ m/checkboxlist/i){
                $val ="";
                if (ref($f->{'checkedList'}) eq 'ARRAY'){
                    $val = join (', ',@{$f->{'checkedList'}});
                }
            }
            $params = {iid=>$iid,rid=>$rid, sfId=>$id,sfValue=>$val};
            eq_item_addUpdate($dbh,$params);
        }
        $iid++;
    }
    $dbh->do("update eq_records set indexed='0' where rid=$rid");
}

sub _nextBarcode {
    my ($barcode) = @_;
=item    
    my $prefix = "";
    $barcode =~ m/(^.*[\D]|^)([\d]+)$/;
    $prefix= $1;           
    my $num = $2;
    my $tmp = $2;
    my $len = length($tmp);
        $tmp =~ s/^0+//;
        $tmp++;
    my $lenTmp = length($tmp);
    my $bc = $prefix . sprintf("%s","0" x ($len - $lenTmp)) . $tmp;
=cut
    my $holdZero="";
    my $flag=1;
    my $char="";
    my $num="";
    my $prefix = "";
    my $len = length($barcode);
   
    for (my $i=0;$i<length($barcode); $i++){
        $char = substr($barcode,length($barcode)-($i+1),1);
        if ( ord($char) > 48 && ord($char)<=57 && $flag){
            $num .= $holdZero . $char;
            $holdZero = "";
        }
        elsif (ord($char) == 48 && $flag){
            $holdZero .= '0';
        }
        else{
            $flag = 0;
            $prefix .= $char;
        }
    }
    $prefix = scalar reverse("$prefix");
    $num    = scalar reverse("$num");

    my @barcodes = ();
    my $tmpBC = $barcode;
    my $n=int($num)+1;
    my $bc = $prefix . $holdZero . $n;
    while ( length($bc) > $len && length($holdZero) > 0){
        $holdZero = substr($holdZero,1,length($holdZero)-1);
        $bc = $prefix . $holdZero . $n;
    }
    return $bc;
}

sub removeItem {
 
    my ($dbh,$data) = @_;
    my $rid=    $data->{'rid'};
    my $barcode = $data->{'barcode'};
    my $copyNo  = $data->{'copyNo'};
    my $typeId  = $data->{'typeId'};
    my $iid     = $data->{'iid'};
    my $params = {rid=>$rid,iid=>$iid,barcode=>$barcode};
    eq_item_deleteBarcode($dbh,$params);
    $dbh->do("update eq_records set indexed='0' where rid=$rid");
    my $eq_solr = Opals::Eq_SolrIndex->new(dbh=>$dbh);
    my $ret = $eq_solr->eq_slr_deleteIndex();
}

sub newItem {
    my ($dbh,$data) = @_;
    my $rid= $data->{'rid'};
    my $barcode = $data->{'startBarcode'};
    my $copyNo  = $data->{'copyNo'};
    my $typeId  = $data->{'typeId'};
    my $nOfItems = $data->{'nOfItems'} || 1;
    my $prefix = "";
    my $suffix = 0;
    my $tmp = substr($barcode,-1);
    my $i = -1;
    my $holdZero="";
    my $flag=1;
    my $char="";
    my $num="";
    my @barcodes = ();
    my $tmpBC = $barcode;
    push @barcodes, $tmpBC;
    for (my $i=1;$i<$nOfItems;$i++){
       $barcode = _nextBarcode($barcode);
       push @barcodes,$barcode;
    }
    my $newIid = eq_item_getMaxIddByRId($dbh,$data->{'rid'});
    $prefix = substr($barcode,0, (length($barcode )- length($suffix)));
    my $params;
    for (my $i=0;$i<$nOfItems;$i++){
        $params = {
            rid     => $data->{'rid'},
            iid     => ++$newIid,
            #barcode => $prefix . $suffix,
            barcode => $barcodes[$i],
            typeId  => $typeId,
        };
        eq_item_addUpdateBarCodeItemType($dbh, $params);
        $suffix++;
        foreach my $f (@{$data->{'fields'}}){
            $params = {
                rid     => $data->{'rid'},
                iid     => $newIid,
                sfId    => $f->{'id'},
                sfValue => $f->{'value'}
            };
            eq_item_addUpdate($dbh,$params);
        }
    }
}

sub _formatRecInfo {
    my ($rec,$items,$rid) = @_;
    my $ret;
    my @fields=();
    my $i=0;
    foreach my $r (@{$rec}){
        if (! $i || $i > 1){
            $ret->{'rid'}   = $r->{'rid'};
            $ret->{'name'}  = $r->{'rname'};
            $ret->{'container'} = ($r->{'container'})? $r->{'container'}:"";
            $ret->{'category'}= $r->{'category'};
            $ret->{'categoryStr'}= $r->{'categoryStr'};
        }
        push @fields, {
            name    => $r->{'name'},
            id      => $r->{'fId'},
            value   => $r->{'fValue'},
        }
    }
    my @tmp = split(',', $ret->{'category'});
    foreach my $i (@{$categoryList}){
        $i->{'selected'} = "false";
        foreach my $t (@tmp){
            if ($t == $i->{'id'}){
                $i->{'selected'} ="true";
            }
        }
        foreach my $k (@{$i->{'children'}}){
            $k->{'selected'} = "false";
            foreach my $t (@tmp){
                if ($t == $k->{'id'}){
                    $k->{'selected'} ="true";
                }
            }
        }
    }
    my @sorted = sort { $a->{'name'} cmp $b->{'name'}} @fields;
    $ret->{'categories'} = $categoryList;
    $ret->{'fields'} = \@sorted;
    $ret->{'items'} = $items;
    $ret->{'rid'} = $rid;
    return $ret;
}
sub _eq_item_findByRId {
    
    my ($dbh, $recordId)=@_;
    return undef if ($recordId eq '');
    my $sth = $dbh->prepare("select iid, barcode,typeId,copyNo,i.createdDate,r.container from eq_items i inner join eq_records r using(rid) where rid=? && i.barcode not regexp '^\_\_\_'");
    my $sql = " SELECT  d.*, fdt.dataType, fdt.maxVal, i.id as i_iid, i.rid, i.sfId, i.sfValue 
                FROM    eq_def as d 
                LEFT OUTER JOIN eq_fieldDataType fdt on d.fieldType=fdt.id
                LEFT OUTER JOIN eq_itemFields as i on i.sfId = d.id && i.rid = ? && i.iid = ? 
                WHERE   d.defType = 'item'  && showOnRecBrief = '1'";
    my $sth_item = $dbh->prepare($sql);
    $sth->execute($recordId);
    my @itemList;
    my $i=0;
    while (my ($iid,$barcode,$typeId,$copyNo,$createdDate,$container) = $sth->fetchrow_array()){
       $sth_item->execute($recordId, $iid);
       my @fields;
       my $fCount = 0;
       while(my $f = $sth_item->fetchrow_hashref()){
            push @fields, {
                id              => ($f->{'sfId'})? $f->{sfId}:$f->{'id'},
                value           => $f->{'sfValue'}, 
                name            => $f->{'name'},
                url_link        => ($f->{'fieldType'} eq '2')?1:0,
                fieldType       => $f->{'fieldType'},
                dataType        => lc($f->{'dataType'}) || "text",
                fieldSize       => $f->{'fieldSize'} || 10,
                showOnRecBrief  => $f->{'showOnRecBrief'},
            };
            if ($f->{'display'}){
                $fCount++;
            }
       }
       push @itemList, {
            rid     => $recordId,
            iid     => $iid,
            barcode => $barcode,
            typeId  => $typeId,
            copyNo  => $copyNo,
            cDate   => $createdDate,
            container=>$container, 
            fields  => \@fields
       };
       $i++;
    }
    $sth->finish;
    $sth_item->finish;
    return \@itemList;
}


