#!/usr/bin/perl

#use utf8;
use strict;
use CGI;
use Encode;
use PDF::Create;
use POSIX qw(
    floor
    ceil
);

use Opals::Context;

use Time::localtime;

use Opals::Date qw(
    date_parse
    date_today
    date_text
    date_f005
);

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

use Opals::Locale qw(
    loc_getMsgFile
    loc_write
    
);

use Opals::Transaction qw(
    trans_getUnpaidChargeList
    trans_getBalance
    );


use Opals::Mail qw(
    mail_enqueueMail
    mail_validateEmail
);
my $dbh = Opals::Context->dbh();
END { $dbh->disconnect(); }

my $cgi    = CGI->new;
my $input  = $cgi->Vars();



my $pref   = tmpl_preference($dbh);
my $libname    = decode('utf8', $pref->{'libname'});
   $libname    =~ s/<br>/ /g;
   $libname    =~ s/&amp;/&/g;
my $libAddress = decode('utf8', $pref->{'libAddress'});
my $libCity    = decode('utf8', $pref->{'libCity'});
my $libState   = decode('utf8', $pref->{'libState'});
my $libZip     = decode('utf8', $pref->{'libZip'});
my $libPhone   = decode('utf8', $pref->{'libPhone'});
my $libFax     = decode('utf8', $pref->{'libFax'});
my $libEmail   = decode('utf8', $pref->{'libEmail'});

#-------------------------------------------------------------------------------------

my $op       = $input->{'op'}; #print or email
my $sort1    = $input->{'sort1'};
my $sort2    = $input->{'sort2'};
my $optTitle = $input->{'optTitle'};
my $optBilg  = $input->{'optBilg'};
my $prtType  = $input->{'prtType'};
my $optPrice = $input->{'optPrice'};
my $optPage  = $input->{'optPage'};
my $printGreeting =$input->{'optGreeting'};

my $msgTopCbox = $input->{'msgTopCbox'};
my $msgBotCbox = $input->{'msgBotCbox'};
my $srcCall    = $input->{'srcCall'};
my $incOpt     = $input->{'incOpt'};

my @msgArr=();
my @lang;
my $l;
if($optBilg eq 'enSp'){
   @lang=('en','sp');
   $l ='en';
}
elsif($optBilg eq 'frOnly'){
   @lang=('fr');
   $l='fr';
}
else{
   @lang=('en');
   $l='en';
}
#-------------------------------------------------------------------------------------
use constant    X_PAGE         =>  612;
use constant    X_LEFT_MARGIN  =>  25;
use constant    X_RIGHT_MARGIN =>  25;
use constant    Y_PAGE         =>  792;
use constant    X_TABLE        =>  558;
use constant    ROW_HEIGHT     =>   18;
use constant    ROW_HEIGHT_10  =>   12;
use constant    X_ADDRESS      =>   86;
use constant    Y_ADDRESS_FR   =>   772;
use constant    Y_ADDRESS_TO   =>   640;
use constant    Y_BODY         =>   578;
use constant    HEADER_HEIGHT_1=>   50;
use constant    HEADER_HEIGHT_2=>   50;
use constant    FOOTER_HEIGHT  =>   20;


   my $todayStr ="";                         
   my  $inMsgTop = decode('utf8',$input->{'msgTop'});
       $inMsgTop =~ s/_EOL_/\n/;
       $inMsgTop =~ s/\n+/\n/;
      
   my  $inMsgBot = decode('utf8',$input->{'msgBot'});
       $inMsgBot =~ s/_EOL_/\n/;
       $inMsgBot =~ s/\n+/\n/;
      

    my $mypdf=`/bin/mktemp`;
    my $pdf = new PDF::Create('filename' => $mypdf,
                              'Version'  => 1.2,
                              'PageMode' => 'UseOutlines',
                              'Title'    => 'My title',
                         );

    my $root = $pdf->new_page('MediaBox' => [ 0, 0, X_PAGE,Y_PAGE ]);

    my $f1 = $pdf->font('Subtype'  => 'Type1',
                        'Encoding' => 'WinAnsiEncoding',
                        'BaseFont' => 'Helvetica');
    my $f2 = $pdf->font('Subtype'  => 'Type1',
                        'Encoding' => 'WinAnsiEncoding',
                        'BaseFont' => 'Helvetica-Bold');
    my $f3 = $pdf->font('Subtype'  => 'Type1',
                        'Encoding' => 'WinAnsiEncoding',
                        'BaseFont' => 'Times-Italic');

    my $messages= {
        title=>{en=>'Overdue Item(s) Reminder',
                fr=>'Avis de la bibliothèque',
                sp=>'Carta de notificación de tardía'
                },
        messageTo=>{
                en=>'To the parents or guardians of:',
                fr=>'Aux parents de:',
                sp=>'A los padres o guardián de:'
        },
        messageSlip=>{
                en=>'Materials being checked out/renewed: ',
                fr=>'Materials being checked out/renewed: ',
                sp=>'Materials being checked out/renewed: '
        },        
        message1=>{
                en=>'The following items that you borrowed from the library/media center are now past due:',
                fr=>'Les ouvrages ou documents suivants sont en retard.' ,
                sp=>'El libro siguiente prestado de la biblioteca:'
                },
        
       message2=>{
                en=>'Please return any items that may be overdue. Thank you in advance for your cooperation.',
                fr=>'Veuillez les rapporter au plus tôt. Merci de votre collaboration.',
                sp=>'Por favor devuelva el libro lo mas pronto posible.  Gracias por su cooperación.'
                }
        };

    my $itemTblHeader= {
        title       =>{en=>'Title',fr=>'Titre', sp=>'Título' },
        barcode     =>{en=>'Barcode',fr=>'#Code',sp=>'Código'},
        price       =>{en=>'Price',fr=>'Prix',sp=>'Precio'},
        fineType    =>{en=>'Type',fr=>'Type',sp=>'Type'},
        dewey       =>{en=>'Dewey',fr=>'# Classification',sp=>'Clasificación'},
        dateLoan    =>{en=>'Loan Date',fr=>'Date ',sp=>'Fecha'},
        dateDue     =>{en=>'Due Date', fr=>'Date d\'échéance',sp=>'Fecha de vencimiento'},
        date        =>{en=>'Date',fr=>'Date', sp=>'Fecha'},
        amount      =>{en=>'Charge', fr=>'Montant', sp=>'Cantidad' },
        overdue     =>{en=>'Overdue', fr=>'En retard',sp=>'Dias' }

    };
    foreach my $key(keys %{$messages}){
        foreach my $l('en','fr','sp'){
            $messages->{$key}->{$l}=decode('utf8',$messages->{$key}->{$l} );
        }
    }

    foreach my $key(keys %{$itemTblHeader}){
        foreach my $l('en','fr','sp'){
            $itemTblHeader->{$key}->{$l}=decode('utf8',$itemTblHeader->{$key}->{$l} );
        }
    }

   
   my $fineTypeMsg={
        OVERDUE_CHARGED=>'overdue',
        LOST_CHARGED   =>'lost',
        DAMAGE_CHARGED =>'damage' 
      };

   my $headers={
        odNotice        => ['title', 'barcode', 'price', 'dewey', 'dateLoan', 'dateDue'],
        unpaidItem      => ['title', 'barcode', 'fineType', 'date', 'amount']
    };
   my $tblDef={
       odNoticeData=>{
            title   =>{width=>150  , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            barcode =>{width=>100  , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            price   =>{width=>45   , padding=>5 ,font=>$f1,fontSize=>10,align=>'right' },
            dewey   =>{width=>88   , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            dateLoan=>{width=>88   , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            dateDue =>{width=>87   , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  }
           },
       odNoticeData_sub=>{
            title   =>{width=>150  , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            barcode =>{width=>100  , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            price   =>{width=>45   , padding=>5 ,font=>$f1,fontSize=>10,align=>'right' },
            dewey   =>{width=>88   , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            dateLoan=>{width=>88   , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  },
            dateDue =>{width=>87   , padding=>5 ,font=>$f1,fontSize=>10,align=>'left'  }
           },
       odNoticeHeaderMain=>{
            title   =>{width=>150  , padding=>5 ,font=>$f2,fontSize=>10,align=>'center'},
            barcode =>{width=>100  , padding=>5 ,font=>$f2,fontSize=>10,align=>'center'},
            price   =>{width=>45   , padding=>5 ,font=>$f2,fontSize=>10,align=>'center'},
            dewey   =>{width=>88   , padding=>5 ,font=>$f2,fontSize=>10,align=>'center'},
            dateLoan=>{width=>88   , padding=>5 ,font=>$f2,fontSize=>10,align=>'center'},
            dateDue =>{width=>87   , padding=>5 ,font=>$f2,fontSize=>10,align=>'center'}
           },
       odNoticeHeaderSub=>{
            title   =>{width=>150  , padding=>5 ,font=>$f3,fontSize=>10,align=>'center' },
            barcode =>{width=>100  , padding=>5 ,font=>$f3,fontSize=>10,align=>'center' },
            price   =>{width=>45   , padding=>5 ,font=>$f3,fontSize=>10,align=>'center' },
            dewey   =>{width=>88   , padding=>5 ,font=>$f3,fontSize=>10,align=>'center' },
            dateLoan=>{width=>88   , padding=>5 ,font=>$f3,fontSize=>10,align=>'center' },
            dateDue =>{width=>87   , padding=>5 ,font=>$f3,fontSize=>10,align=>'center' }
           },
      unpaidItemData=>{
            title   =>{width=>200   , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            barcode =>{width=>130   , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            fineType=>{width=>55    , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            date    =>{width=>95    , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            amount  =>{width=>78    , padding=>5,font=>$f1,fontSize=>10,align=>'right' }
           },
     unpaidItemData_sub=>{
            title   =>{width=>200   , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            barcode =>{width=>130   , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            fineType=>{width=>55    , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            date    =>{width=>95    , padding=>5,font=>$f1,fontSize=>10,align=>'left'  },
            amount  =>{width=>78    , padding=>5,font=>$f1,fontSize=>10,align=>'right' }
           },
     unpaidItemHeaderMain=>{
            title   =>{width=>200   , padding=>5,font=>$f2,fontSize=>10,align=>'center'},
            barcode =>{width=>130   , padding=>5,font=>$f2,fontSize=>10,align=>'center'},
            fineType=>{width=>55    , padding=>5,font=>$f2,fontSize=>10,align=>'center'},
            date    =>{width=>95    , padding=>5,font=>$f2,fontSize=>10,align=>'center'},
            amount  =>{width=>78    , padding=>5,font=>$f2,fontSize=>10,align=>'center'}
           },
     unpaidItemHeaderSub=>{
            title   =>{width=>200   , padding=>5,font=>$f3,fontSize=>10,align=>'center'},
            barcode =>{width=>130   , padding=>5,font=>$f3,fontSize=>10,align=>'center'},
            fineType=>{width=>55    , padding=>5,font=>$f3,fontSize=>10,align=>'center'},
            date    =>{width=>95    , padding=>5,font=>$f3,fontSize=>10,align=>'center'},
            amount  =>{width=>78    , padding=>5,font=>$f3,fontSize=>10,align=>'center'}
           },
     text_uInfo =>{width=>558   , padding=>5,font=>$f1,fontSize=>10,align=>'center'},
     text_msg1 =>{width=>558   , padding=>5,font=>$f2,fontSize=>10,align=>'center'},
     text_msg2 =>{width=>558   , padding=>5,font=>$f3,fontSize=>10,align=>'center'},
     text_msg3 =>{width=>558   , padding=>5,font=>$f3,fontSize=>10,align=>'center'},
     text_uBalance =>{width=>558  , padding=>35,font=>$f1,fontSize=>10,align=>'right'},

     
     rowHeight=>{
          odNoticeData          =>16,
          odNoticeData_sub      =>12,

          odNoticeHeaderMain    =>16,
          odNoticeHeaderSub     =>12,
          unpaidItemData        =>16,
          unpaidItemData_sub    =>12,
          unpaidItemHeaderMain  =>16,
          unpaidItemHeaderSub   =>12,
          textMsg               =>16,
          text_uInfo            =>10,
          text_msg1             =>10,
          text_msg2             =>12,
          text_msg3             =>16,
          text_uBalance         =>10
      }

           
   };

   
   my $pageN = $root->new_page;

   my $msgTop =formatMsg($pageN,$inMsgTop,"text_msg2",X_TABLE);        
   my $msgBottom =formatMsg($pageN,$inMsgBot,"text_msg2",X_TABLE);
   @$msgTop =(@$msgTop,{type=>'text_msg2',text=>''}) if(scalar(@$msgTop)>0);
   @$msgBottom =({type=>'text_msg2',text=>''} ,@$msgBottom) if(scalar(@$msgBottom)>0);

   saveMsgToPrefTbl($msgTopCbox,$msgBotCbox,$inMsgTop,$inMsgBot);

#----------------------------------------------------------------------------------------------------
sub formatMsg{
    my ($pageN,$msg,$msgType,$msgWidth)=@_;
    my @retMsgArr=();
    my @tmpArr =split(/\n/g,$msg);
    foreach my $m(@tmpArr){
       my $msgArr    =formatStr_nRow($pageN,
                                    $tblDef->{$msgType}->{'font'},
                                    $tblDef->{$msgType}->{'fontSize'},
                                    $m,$msgWidth,100);
       foreach my $s(@$msgArr){
            push @retMsgArr,{type=>$msgType, text=>$s};
       }
    }
    return \@retMsgArr
}

#----------------------------------------------------------------------------------------------------

my $DataRecs;

if ( $sort1 eq '' ){
    $sort1 = "homeroom";
}
if ( !$sort2 ){
    if ( $sort1 eq "username" ) { $sort2 = "title"; }
    else { $sort2 = "username"; }
}

my $dateFrom =  $input->{'dateFrom'};
my $dateTo =    $input->{'dateTo'};
my $dateToday = date_f005();
$dateToday =~ s/([\d]{4})([\d]{2})([\d]{2})[\d]+\.(0|1)/$1-$2-$3/;
$todayStr = date_text($dateToday,1,$l);
$dateFrom = $dateToday if ( !$dateFrom );
$dateTo = $dateToday if ( !$dateTo );

my $pNum = $input->{'pNum'};

=item
#$template->param(odNoticeMsgTop    => $pref->{'odNoticeMsgTop'},
                 odNoticeMsgBottom => $pref->{'odNoticeMsgBottom'}, 
                 ); 
if($input->{'headers'} eq 'true'){
    $template->param(includeHeaders => 1);
}
#    OptionPrintNotice($dbh, $template);
=cut

my $itemOnLoanMsgMap;
if($srcCall eq 'odCirc'){
    $DataRecs = getOverDueNotice($dbh, $sort1, $sort2, $dateFrom, $dateTo, $input);
     foreach my $data(@$DataRecs){
            foreach my $od(@{$data->{'oditems'}}){
                $od->{'type'}='odNoticeData';
            }
     }
    if(defined $input->{'incOpt'} &&  $input->{'incOpt'}  eq 'incUnpaidNotice'){
        foreach my $data(@$DataRecs){
            # Thu, Oct 20, 2011 @ 14:44:01 EDT
            # Add user balance
            my $uBalanceInfo = _getUserBalanceInfo($dbh,$data->{'uid'});
            my $upItemList=trans_getUnpaidChargeList($dbh,$data->{'uid'});
            foreach my $f(@$upItemList){
                $f->{'type'}='unpaidItemData';
                $f->{'barcode'} =~ s/^\_\_\_(.*)_([\d]{3})$/$1/g;
                $f->{'amount'}=$f->{'balance'};
                $f->{'fineType'}=$fineTypeMsg->{$f->{'chargeType'}};
                $f->{'date'}=date_text($f->{'date'}, 0,$l);
            }
            
            $data->{'unpaidItems'} =$upItemList;
            $data->{'balance'}          = $uBalanceInfo->{'balance'};
            
        }
    }
} 
else{
    my $uidList = $input->{'idlist'};
   $DataRecs = getFineNoticeList($dbh,$uidList);
    if(defined $input->{'incOpt'} &&  $input->{'incOpt'}  eq 'incOdNotice'){
        foreach my $data(@$DataRecs){
            my $odItemList=GetUserOverdue($dbh,$data->{'uid'});
            foreach my $od(@$odItemList){
                $od->{'type'}='odNoticeData';
            }
            $data->{'oditems'} =$odItemList;
           

        }
    }
}
my $eSubject='';
if(scalar(@$DataRecs) >0){
    if(defined $op && $op eq 'email'){
        my ($permission, $cookie, $template) = tmpl_read(
        {
            dbh             => $dbh,
            cgi             => $cgi,
            tmplFile        => 'circ/odemail.tmpl',
            reqPermission   => 'notice',
        });
        $itemOnLoanMsgMap =loc_getMsgFile('circ/notice.msg');
        $eSubject = $itemOnLoanMsgMap->{'odRemindTxt'};
        my $contArr = getHTMLContent($dbh,$cgi,$sort1,$DataRecs);
        my ($totalUser,$totalUserHasEmail,$totalUserNoEmail) = (0,0,0);
        $totalUser = scalar(@$contArr);
        my $userHasEmailList ;
        my $userNoEmailList  ;
        if($totalUser >0){
            ($userHasEmailList,$userNoEmailList) = saveContent2Tbls($dbh,$contArr,$eSubject);
            ($totalUserHasEmail,$totalUserNoEmail) = (scalar(@$userHasEmailList),scalar(@$userNoEmailList));
        }
        $template->param(
            totalUser           => $totalUser,
            totalUserHasEmail   => $totalUserHasEmail,
            totalUserNoEmail    => $totalUserNoEmail,
            userHasEmailList    => $userHasEmailList,
            userNoEmailList     => $userNoEmailList,
            email               => 1,
        );
        loc_write($template,$itemOnLoanMsgMap);
        tmpl_write($dbh, $cgi, $cookie, $template);
        
    }
    else{ 
           
        open PDF, "<$mypdf";
        print $cgi->header(
            -type           => 'application/pdf',
            -attachement    => 'OverdueNotice.pdf'
        );
            printOd_pdf($DataRecs);
            while (<PDF>) {
                print $_;
            }
        close PDF;
    }
}

#--------------------------------------------------------
sub getHTMLContent{
    my($dbh,$cgi,$sort1,$DataRecs)=@_;
    my @retCont=();
        my ($permission, $cookie, $template) = tmpl_read(
            {
                dbh             => $dbh,
                cgi             => $cgi,
                tmplFile        => 'circ/email_odUser.inc',
            }
        );

$template->param(incTitle=>$optTitle,incPrice=>$optPrice);

    foreach my $odData(@$DataRecs){
          
       $template->param(
            email       => decode('utf8', $odData->{'email'}),
            uid         => $odData->{'uid'},
            lastname    => decode('utf8',$odData->{'lastname'}),
            firstname   => decode('utf8', $odData->{'firstname'}),
            grade       => $odData->{'grade'},
            homeroom    => $odData->{'homeroom'},
            buildingcode=> $odData->{'buildingcode'},
            teacher     => $odData->{'teacher'},
            );
            
            my $odItem; @$odItem=();
            my $barcodes ='';
            if(defined $odData->{'oditems'} && scalar(@{$odData->{'oditems'}}) >0){
                $odItem = $odData->{'oditems'};
                foreach my $r(@$odItem){
                    $barcodes .= $r->{'barcode'} .',';
                }
                $odData->{'barcodes'} = $barcodes;

            }
            my $upItem; @$upItem=();
            if(defined $odData->{'unpaidItems'} && scalar(@{$odData->{'unpaidItems'}}) >0){
                $eSubject = $itemOnLoanMsgMap->{'odUpRemindTxt'};
                $upItem = $odData->{'unpaidItems'};
            }


            $template->param(
                loanList    => $odItem,
                unpaidList  => $upItem,
                msgTop      => $inMsgTop,
                msgBot      => $inMsgBot
            );
        loc_write($template,$itemOnLoanMsgMap);

        push @retCont,{uid=>$odData->{'uid'},email=>$odData->{'email'},emailcont=>$template->output,barcodes=>$odData->{'barcodes'}};
    }
    return \@retCont;
}
#--------------------------------------------------------
sub  saveContent2Tbls{
    my($dbh,$contArr,$subject)=@_;
    my @userNoEmailList=();
    my @userHasEmailList=();
    my ($to,$uid) = ('',0);
    foreach my $od(@$contArr){
        $to  = $od->{'email'};
        if ($to){        
            $to =~ s/ +/,/g;
            $to =~ s/;+/,/g;
            $to =~ s/,+/,/g;
            $to =~ s/(^,|,$)//g;
        }
        $uid = $od->{'uid'};
        if($to ne '' && mail_validateEmail($to)){
            my $e = mail_enqueueMail($dbh,$uid,{email=>$to,subject=>$subject,content=>$od->{'emailcont'},barcodes=>$od->{'barcodes'}});
            push @userHasEmailList,{uid=>$uid};
        }
        else{
            push @userNoEmailList,{uid=>$uid};
        }
    }

    return (\@userHasEmailList,\@userNoEmailList);
}

    
#--------------------------------------------------------
sub getOverDueNotice{
    my ($dbh,  $sort1, $sort2, $dateFrom, $dateTo, $input)=@_;
    my $DataRecs={};
    if ( $sort1 eq 'username' ){
        $DataRecs = GetOverdueUserNotice($dbh,  $sort1, $sort2, $dateFrom, $dateTo, $input, $input->{'orderby'});
    }
    elsif ( $sort1 eq 'teacher' ){
        $DataRecs = GetOverdueTeacherNotice($dbh, $sort1, $sort2, $dateFrom, $dateTo, $input);
    }
    elsif ( $sort1 eq 'homeroom' ){
        $DataRecs = GetOverdueHomeroomNotice($dbh,$sort1, $sort2, $dateFrom, $dateTo, $input);
    }
    elsif ( $sort1 eq 'grade' ){
        $DataRecs = GetOverdueGradeNotice($dbh, $sort1, $sort2, $dateFrom, $dateTo, $input);
    }
    return $DataRecs;
}  
#--------------------------------------------------------
sub GetOverdueTeacherNotice
{
    my ($dbh, $sort1, $sort2, $dateFrom, $dateTo, $input) = @_;

    my @roomlist = ();
    my @teacherlist = ();
    my @bdinglist = ();
    
    if ( $input->{'whole'} )
    {
        my $sql = "select distinct trim(homeroom) as homeroom, trim(buildingcode) as buildingcode, trim(teacher) as teacher from opl_user order by teacher, buildingcode, homeroom";
        my $query = $dbh->prepare($sql);
        $query->execute();
        while ( my $rec = $query->fetchrow_hashref )
        {
            if ( !$rec->{'homeroom'} ) { $rec->{'homeroom'} = ''; }
            if ( !$rec->{'buildingcode'} ) { $rec->{'buildingcode'} = ''; }
            if ( !$rec->{'teacher'} ) { $rec->{'teacher'} = ''; }

            push @roomlist, $rec->{'homeroom'};
            push @bdinglist, $rec->{'buildingcode'};
            push @teacherlist, $rec->{'teacher'};
        }
        $query->finish;
    }
    else
    {
        @roomlist = split /\$/, $input->{'roomlist'};
        @bdinglist = split /\$/, $input->{'bdinglist'};
        @teacherlist = split /\$/, $input->{'teacherlist'};

        if ( scalar(@roomlist) == 0 ) { push @roomlist, ''; }
        if ( scalar(@bdinglist) == 0 ) { push @bdinglist, ''; }
        if ( scalar(@teacherlist) == 0 ) { push @teacherlist, ''; }
    }


    my $szSQL = "
select  trim(teacher) as teacher, grade, trim(homeroom) as homeroom, trim(buildingcode) as buildingcode, 
        username, userbarcode, u.addrLine1,u.addrLine2,u.city,u.zip,u.state, u.email,
        l.uid, firstname, lastname, phone, i.barcode, i.price, dateLoan, dateDue,
        m.title, m.author, m.pubDate, m.pubName, i.callNumber as dewey, 
        to_days(now()) - to_days(dateDue) as deltaDueDate 
from    opl_user as u, opl_loan as l, opl_marcRecord as m, opl_item as i 
where   u.uid = l.uid && dateReturn is null  
        && l.barcode=i.barcode && i.rid=m.rid && trim(homeroom)=?
        && trim(buildingcode)=? && trim(teacher)=?";

    $szSQL = AddDateConstraint($szSQL, $dateFrom, $dateTo);
    $szSQL .= "order by teacher, buildingcode, homeroom, lastname, firstname, uid";
    my $query = $dbh->prepare($szSQL);
    
    my @DataRecs = ();
    my $nList = scalar(@roomlist);

    for (my $i=0; $i<$nList; $i++)
    {   
        $roomlist[$i] =~ s/^\s+|\s+$//g;
        $bdinglist[$i] =~ s/^\s+|\s+$//g;
        $teacherlist[$i] =~ s/^\s+|\s+$//g;
        #if ( !$roomlist[$i] ) { $roomlist[$i] = ''; }
        #if ( !$bdinglist[$i] ) { $bdinglist[$i] = ''; }
        #if ( !$teacherlist[$i] ) { $teacherlist[$i] = ''; }

        my $bResult = $query->execute($roomlist[$i], $bdinglist[$i], $teacherlist[$i]);
        MakeNotice($query, \@DataRecs);        
    }

    return \@DataRecs;
}
#----------------------------------------------------------------------------------------------------
sub getHeaderRow{
    my ($headerType)=@_;
    my @hRow=();
    my $headerName=$headerType ."HeaderMain";
    my $i=1;
    foreach my $l(@lang){
        my $hr={type    =>$headerName,
                height  =>$tblDef->{'rowHeight'}->{$headerName}
                };
        foreach my $h(@{$headers->{$headerType}}){
             $hr->{$h} =$itemTblHeader->{$h}->{$l};
        }
        $hr->{'border_B'} =($i==scalar(@lang))?1:0;
        $i++;
        push @hRow,$hr;
        $headerName=$headerType ."HeaderSub";
    }
    return \@hRow;
}
            
 #--------------------------------------------------------
sub GetOverdueHomeroomNotice
{
    my ($dbh,  $sort1, $sort2, $dateFrom, $dateTo, $input) = @_;

    my @roomlist = ();
    my @teacherlist = ();
    my @bdinglist = ();
    
    if ( $input->{'whole'} )
    {
        my $sql = "select distinct trim(homeroom) as homeroom, trim(buildingcode) as buildingcode, trim(teacher) as teacher from opl_user order by buildingcode, homeroom, teacher";
        my $query = $dbh->prepare($sql);
        $query->execute();
        
        while ( my $rec = $query->fetchrow_hashref )
        {
            if ( !$rec->{'homeroom'} ) { $rec->{'homeroom'} = ''; }
            if ( !$rec->{'buildingcode'} ) { $rec->{'buildingcode'} = ''; }
            if ( !$rec->{'teacher'} ) { $rec->{'teacher'} = ''; }

            push @roomlist, $rec->{'homeroom'};
            push @bdinglist, $rec->{'buildingcode'};
            push @teacherlist, $rec->{'teacher'};
        }
        $query->finish;
    }
    else
    {
        @roomlist = split /\$/, $input->{'roomlist'};
        @bdinglist = split /\$/, $input->{'bdinglist'};
        @teacherlist = split /\$/, $input->{'teacherlist'};

        if ( scalar(@roomlist) == 0 ) { push @roomlist, ''; }
        if ( scalar(@bdinglist) == 0 ) { push @bdinglist, ''; }
        if ( scalar(@teacherlist) == 0 ) { push @teacherlist, ''; }
    }

    my $szSQL = "
select  trim(teacher) as teacher, grade, trim(homeroom) as homeroom, trim(buildingcode) as buildingcode, 
        username, userbarcode, u.addrLine1,u.addrLine2,u.city,u.zip,u.state, u.email,
        l.uid, firstname, lastname, phone, i.barcode, i.price, dateLoan, dateDue,
        m.title, m.author, m.pubDate, m.pubName, i.callNumber as dewey, 
        to_days(now()) - to_days(dateDue) as deltaDueDate 
from    opl_user as u, opl_loan as l, opl_marcRecord as m, opl_item as i 
where   u.uid = l.uid && dateReturn is null  
        && l.barcode=i.barcode && i.rid=m.rid && trim(homeroom)=?
        && trim(buildingcode)=? && trim(teacher)=?";

    $szSQL = AddDateConstraint($szSQL, $dateFrom, $dateTo);
    $szSQL .= "order by lastname, firstname, uid";

    my $query = $dbh->prepare($szSQL);
    my @DataRecs = ();
    my $nList = scalar(@roomlist);

    for (my $i=0; $i<$nList; $i++)
    {
        $roomlist[$i] =~ s/^\s+|\s+$//g;
        $bdinglist[$i] =~ s/^\s+|\s+$//g;
        $teacherlist[$i] =~ s/^\s+|\s+$//g;
        #if ( !$roomlist[$i] ) { $roomlist[$i] = ''; }
        #if ( !$bdinglist[$i] ) { $bdinglist[$i] = ''; }
        #if ( !$teacherlist[$i] ) { $teacherlist[$i] = ''; }

        my $bResult = $query->execute($roomlist[$i], $bdinglist[$i], $teacherlist[$i]);
        MakeNotice($query, \@DataRecs);
    }
    return \@DataRecs;
}



#--------------------------------------------------------
sub GetOverdueGradeNotice
{
    my ($dbh, $sort1, $sort2, $dateFrom, $dateTo, $input) = @_;

    my @gradelist = ();
    
    if ( $input->{'whole'} )
    {
        my $sql = "select distinct grade from opl_user order by grade";
        my $query = $dbh->prepare($sql);
        $query->execute();
        while ( my $rec = $query->fetchrow_hashref )
        {
            push @gradelist, $rec->{'grade'};
        }
        $query->finish;
    }
    else
    {
        @gradelist = split /\$/, $input->{'gradelist'};
        if ( scalar(@gradelist) == 0 ) { push @gradelist, ''; }
    }

    my $szSQL = "
select  trim(teacher) as teacher, grade, trim(homeroom) as homeroom, trim(buildingcode) as buildingcode, 
        username, userbarcode, u.addrLine1,u.addrLine2,u.city,u.zip,u.state, u.email,
        u.uid, firstname, lastname, phone, i.barcode, i.price, dateLoan, dateDue,
        m.title, m.author, m.pubDate, m.pubName, i.callNumber as dewey, 
        to_days(now()) - to_days(dateDue) as deltaDueDate 
from    opl_user as u, opl_loan as l, opl_marcRecord as m, opl_item as i
where   u.uid = l.uid && dateReturn is null  
        && l.barcode=i.barcode && i.rid=m.rid && grade=?";

    $szSQL = AddDateConstraint($szSQL, $dateFrom, $dateTo);
    $szSQL .= "order by lastname, firstname, uid";

    my $query = $dbh->prepare($szSQL);


    my @DataRecs = ();
    my $nList = scalar(@gradelist);
    for (my $i=0; $i<$nList; $i++)
    {
        #if ( !$gradelist[$i] ) { $gradelist[$i] = ''; }
        if($gradelist[$i] eq 'none'){
            $gradelist[$i] ='';
        }
      
              my $bResult = $query->execute($gradelist[$i]);
   
        MakeNotice($query, \@DataRecs);
    }

    return \@DataRecs;
}



#--------------------------------------------------------
sub  getFineNoticeList{
    my($dbh,$uidList)=@_;
    my @uidArr =  split /,/, $uidList;
    my $upData=undef; 
    foreach my $uid(@uidArr){
        my $info =getUserInfo($dbh,$uid);
        
        if(defined $info->{'uid'} && $info->{'uid'}>0){
            # Thu, Oct 20, 2011 @ 14:44:01 EDT
            # Add user balance
            my $uBalanceInfo = _getUserBalanceInfo($dbh,$uid);
            my @upItemList=trans_getUnpaidChargeList($dbh,$uid);

            if(scalar(@upItemList)>0){
                foreach my $f(@upItemList){
                    $f->{'type'}    ='unpaidItemData';
                    $f->{'barcode'} =~ s/^\_\_\_(.*)_([\d]{3})$/$1/g;
                    $f->{'amount'}  =$f->{'balance'};
                    $f->{'fineType'}=$fineTypeMsg->{$f->{'chargeType'}};
                    $f->{'date'}    =date_text($f->{'date'}, 0,$l);
                    push @{$info->{'unpaidItems'}}, $f;
                }
                $info->{'balance'}          = $uBalanceInfo->{'balance'};
                $upData=[]if(!defined $upData);
                push @$upData,$info;
            }
        }
    }
    return $upData;
}

#--------------------------------------------------------
sub getUserInfo{
    my($dbh,$uid)=@_;

    my $user =$dbh->selectrow_hashref(<<_SQL_);
    select uid,userbarcode,firstname,lastname,teacher,grade,homeroom,buildingcode,
    addrLine1,addrLine2,city,zip,state,phone,yeargraduation
    from opl_user
    where uid= $uid
_SQL_
    if($user &&  $user->{'uid'} && $user->{'addrLine1'} eq ''){
        my $address=getGuardianAddress($dbh,$user->{'uid'});
        $user->{'addrLine1'}=$address->{'addrLine1'};
        $user->{'addrLine2'}=$address->{'addrLine2'};
        $user->{'city'}=$address->{'city'};
        $user->{'zip'}=$address->{'zip'};
        $user->{'state'}=$address->{'state'};
        
    }
    return $user;
}
#--------------------------------------------------------
sub GetUserOverdue{
#Tue, Dec 06, 2011 @ 14:52:31 EST
# Ha add  " datedue < now() " to  " where  dateReturn is null  &&  l.uid=?"
#
    my ($dbh,$uid) = @_;
    my @odList = ();
    
     my $sth = $dbh->prepare(<<_SQL_);
select  i.barcode, i.price, dateLoan, dateDue, 
        m.title, m.author, m.pubDate, m.pubName, i.callNumber as dewey, 
        to_days(now()) - to_days(dateDue) as deltaDueDate 
from    opl_loan as l  inner join opl_item  i  using(barcode) 
        inner join opl_marcRecord m using(rid)
where   dateDue < now() && dateReturn is null  &&  l.uid=?

_SQL_

 $sth->execute($uid);
    while(my $od=$sth->fetchrow_hashref){
        $od->{'dateLoan'} = date_text($od->{'dateLoan'}, 0,$l);
        $od->{'dateDue'} = date_text($od->{'dateDue'}, 0,$l);

        push @odList,$od;
    }
    $sth->finish;
    return \@odList;
}



#--------------------------------------------------------
sub GetOverdueUserNotice
{
    my ($dbh, $sort1, $sort2, $dateFrom, $dateTo, $input, $orderby) = @_;

    my @idlist = ();
    
    if ( $input->{'whole'} )
    {
        my $sql = "select distinct uid from opl_user order by lastname, firstname, uid";
        my $query = $dbh->prepare($sql);
        $query->execute();
        while ( my $rec = $query->fetchrow_hashref )
        {
            push @idlist, $rec->{'uid'};
        }
        $query->finish;
    }
    else
    {
        @idlist = split /\$/, $input->{'idlist'};
    }

    my $szSQL = "
select  trim(teacher) as teacher, grade, trim(homeroom) as homeroom, trim(buildingcode) as buildingcode, 
        username, userbarcode, u.addrLine1,u.addrLine2,u.city,u.zip,u.state, u.email,
        l.uid, firstname, lastname, phone, i.barcode, i.price, dateLoan, dateDue, 
        m.title, m.author, m.pubDate, m.pubName, i.callNumber as dewey, 
        to_days(now()) - to_days(dateDue) as deltaDueDate 
from    opl_user as u, opl_loan as l, opl_marcRecord as m, opl_item as i 
where   u.uid = l.uid && dateReturn is null 
        && l.barcode=i.barcode && i.rid=m.rid && l.uid=?";

    $szSQL = AddDateConstraint($szSQL, $dateFrom, $dateTo);

    if ( $orderby eq 'name' ) { $szSQL .= " order by lastname, firstname, username"; }
    else { $szSQL .= " order by homeroom, lastname, firstname, username"; }
   
    my $query = $dbh->prepare($szSQL);
    my @DataRecs = ();
    my $nList = scalar(@idlist);

    for (my $i=0; $i<$nList; $i++)
    {
        my $bResult = $query->execute($idlist[$i]);
        
        MakeNotice($query, \@DataRecs);
    }
    return \@DataRecs;
}



#--------------------------------------------------------
sub getGuardianEmail{
    my ($dbh,$uid)=@_;
    my $email={};
    my $sth=$dbh->prepare("select gemail email from opl_guardian where uid=$uid limit 1");
    $sth->execute();
    $email =$sth->fetchrow_hashref;
    $sth->finish;
    return $email;	
    
}
#----------------------------------------------------------
sub trimArticle{
    my ($str)=@_;
    $str =~ s/^a |^an |^the //i;
    return $str;
}

#----------------------------------------------------------
sub SecondSort
{
    my ($data, $loanRecs, $sort2) = @_;
    
    if ( $sort2 eq "username" )
    { 
        @$data = sort { $a->{"lastname"} cmp $b->{"lastname"} 
                        || $a->{"firstname"} cmp $b->{"firstname"} 
                        || $a->{"uid"} <=> $b->{'uid'} } @$loanRecs; 
    }
    else { @$data = sort { $a->{$sort2} cmp $b->{$sort2} } @$loanRecs; }

}

#--------------------------------------------------------
sub AddDateConstraint
{
    my ($szSQL, $dateFrom, $dateTo) = @_;
    $szSQL = $szSQL . " && to_days(dateDue) >= to_days('$dateFrom')";
    $szSQL = $szSQL . " && to_days(dateDue) <= to_days('$dateTo')";
    $szSQL = $szSQL . " && dateDue < now()";
    return $szSQL;
}

#----------------------------------------------------------
sub OptionPrintNotice
{
    my ($dbh, $template) = @_;
    
    my $optNotice = Opals::Context->preference('reportGroup');

    my @arrOpt = split /,/, $optNotice;
    my @arrPrint = ();

    foreach my $rec (@arrOpt)
    {
        $rec =~ s/^\s+//;
	    $rec =~ s/\s+$//;
        if ( $rec == 1 )
            { push @arrPrint, {reportHomeroom => 1}; }
        elsif ( $rec == 2 )
            { push @arrPrint, {reportTeacher => 2}; }
        elsif ( $rec == 3 )
            { push @arrPrint, {reportGrade => 3}; }
        else
            { push @arrPrint, {reportPhone => 4}; }
    }
    $template->param(optPrn => \@arrPrint);
}

####################################################
sub trim{
    my $str = shift;
    $str =~ s/^\s+//;
    $str =~ s/\s+$//;
    return $str;

}
####################################################
sub getGuardianAddress{
    my ($dbh,$uid)=@_;
    my $address={};
    my $sth=$dbh->prepare("select gaddrLine1 addrLine1,gaddrLine2 addrLine2,gcity city,gzip zip,gstate state,gemail email from opl_guardian where uid=$uid limit 1");
    $sth->execute();
    $address =$sth->fetchrow_hashref;
    $sth->finish;
    return $address;	
    
}
####################################################
sub getguardianEmail{
    my ($dbh,$uid)=@_;
    my $email={};
    my $sth=$dbh->prepare("select gemail email from opl_guardian where uid=$uid limit 1");
    $sth->execute();
    $email =$sth->fetchrow_hashref;
    $sth->finish;
    return $email;	
    
}

#--------------------------------------------------------
sub MakeNotice
{
    my ($query, $DataRecs) = @_;
    my $iduser = {};
    my $preUid = -1;
    my @loanRecs = ();
    while ( my $loan = $query->fetchrow_hashref() )
    {

        if($loan->{'email'} eq ''){
            my $email=getGuardianEmail($dbh,$loan->{'uid'});
            $loan->{'email'} = $email->{'email'};
        }

        if ( $preUid == -1 ) { $iduser = $loan; }
                       
        if ( $preUid ne $loan->{'uid'} )
        {
		$preUid = $loan->{'uid'};
		if($iduser->{'addrLine1'} eq ''){
		    my $address=getGuardianAddress($dbh,$iduser->{'uid'});
		    $iduser->{'addrLine1'}=$address->{'addrLine1'};
		    $iduser->{'addrLine2'}=$address->{'addrLine2'};
		    $iduser->{'city'}=$address->{'city'};
		    $iduser->{'zip'}=$address->{'zip'};
		    $iduser->{'state'}=$address->{'state'};
		}
            # Prepare the group title
            my @data = @loanRecs;
            if ( scalar(@data) != 0 )
            {	
                push @$DataRecs, { oditems => \@data, firstname => $iduser->{'firstname'}, 
                            lastname => $iduser->{'lastname'}, userbarcode => $iduser->{'userbarcode'},
                            username => $iduser->{'username'}, uid => $iduser->{'uid'},
                            homeroom => $iduser->{'homeroom'}, teacher => $iduser->{'teacher'},
                            grade => $iduser->{'grade'}, phone => $iduser->{'phone'}, 
                            addrLine1=> $iduser->{'addrLine1'},addrLine2   => $iduser->{'addrLine2'},
                            city  => $iduser->{'city'}, zip => $iduser->{'zip'},state => $iduser->{'state'},
                            email => $iduser->{'email'}
};
            }
            @loanRecs = ();
            $iduser = $loan;
        }
        
        # Format each row of data
        $loan->{'dateLoan'} = date_text($loan->{'dateLoan'}, 0,$l);
        $loan->{'dateDue'}  = date_text($loan->{'dateDue'}, 0,$l);
        $loan->{'price'}  =~ s/[a-zA-Z]//g ;
        $loan->{'title'} =~ s/\\/\\\\/g;
        $loan->{'title'} =~ s/\"/\\\"/g;
        push @loanRecs, {
            uid             => $loan->{'uid'},  
            email           => $loan->{'email'},
            grade           => $loan->{'grade'},
            title           => decode('utf8',$loan->{'title'}),
            dewey           => decode('utf8',$loan->{'dewey'}), 
            barcode         => $loan->{'barcode'},
            price           => decode('utf8',$loan->{'price'}),
            dateDue         => decode('utf8',$loan->{'dateDue'}),
            dateLoan        => decode('utf8',$loan->{'dateLoan'}),
            deltaDueDate    => $loan->{'deltaDueDate'},
        };
    }                    
    $query->finish;
    if ( scalar(@loanRecs) != 0 )
    { 
        @loanRecs = sort { lc(trimArticle($a->{"title"})) cmp lc(trimArticle($b->{"title"})) } @loanRecs; 
        push @$DataRecs, {
            oditems     => \@loanRecs,
            firstname   => $iduser->{'firstname'}, 
            lastname    => $iduser->{'lastname'},
            userbarcode => $iduser->{'userbarcode'},
            username    => $iduser->{'username'},
            uid         => $iduser->{'uid'},
            email       => $iduser->{'email'},
            homeroom    => $iduser->{'homeroom'},
            teacher     => $iduser->{'teacher'},
            grade       => $iduser->{'grade'},
            phone       => $iduser->{'phone'},
            addrLine1   => $iduser->{'addrLine1'},
            addrLine2   => $iduser->{'addrLine2'},
            city        => $iduser->{'city'},
            zip         => $iduser->{'zip'},
            state       => $iduser->{'state'},
        }; 
    }
}
#----------------------------------------------------------------------------------------------------
sub formatRowData{
    my ($rData)=@_;
    my @retArr=();
    foreach my $r(@$rData){
        $r->{'border_B'}=1;
        my $type=$r->{'type'};
        my $tDef    = $tblDef->{$type}->{'title'};
        my $f       =$tDef->{'font'};
        my $fs      =$tDef->{'fontSize'};
        my $dddLen = $fs*$pageN->string_width($f,'...') ;
        my $width   =$tDef->{'width'} - $tDef->{'padding'} - $dddLen;
        my $height= $r->{'height'};

        my $titleArr=formatStr_nRow($pageN,$f,$fs,$r->{'title'},$width,2);
        my $deweyArr ;
           @$deweyArr =();
        if($type eq 'odNoticeData' ){
             $tDef    = $tblDef->{$type}->{'dewey'};
             $f       =$tDef->{'font'};
             $fs      =$tDef->{'fontSize'};
             $dddLen = $fs*$pageN->string_width($f,'...') ;
             $width   =$tDef->{'width'} - $tDef->{'padding'} - $dddLen;
             $deweyArr =formatStr_nRow($pageN,$f,$fs,$r->{'dewey'},$width,2)  
        }

        my $subrow=undef;
        if(scalar(@$titleArr)>1){
            $r->{'title'}=@$titleArr[0];
            $r->{'border_B'}=0;
            $subrow->{'title'}  =@$titleArr[1];
            $subrow->{'type'}   = $type ."_sub";
            $subrow->{'border_B'}   =1;
        }
        if(scalar(@$deweyArr)>1){
            $r->{'dewey'}=@$deweyArr[0];
            $r->{'border_B'}=0;
            $subrow->{'dewey'}  =@$deweyArr[1];
            $subrow->{'type'}   = $type ."_sub";
            $subrow->{'border_B'}   =1;
        }
        push @retArr,$r;
        push @retArr,$subrow if(defined $subrow);
       
 
    }
    return \@retArr;

}
#----------------------------------------------------------------------------------------------------
sub formatNoticeData{
    my ($notice,$optPage,$prtType)=@_;
    my $retArr;
       @$retArr=();
    my $totalPage=0;
    my $odItemList;
       @$odItemList=();
    my $upItemList ;
       @$upItemList=();
    @$retArr=(@$msgTop)if(scalar(@$msgTop)>0);

    my $headerRow_od=getHeaderRow('odNotice');
    my $headerRow_unpaid=getHeaderRow('unpaidItem');

    if(defined $notice->{'userInfo'}){
         @$retArr=(@{$notice->{'userInfo'}},@$retArr);
    }
    if(defined $notice->{'oditems'} && scalar(@{$notice->{'oditems'}}) >0){
        $odItemList =formatRowData($notice->{'oditems'}) ;
        @$odItemList =(
                @$headerRow_od,
                @$odItemList);
    }
    if(defined $notice->{'unpaidItems'} && scalar(@{$notice->{'unpaidItems'}}) >0){
        $upItemList =formatRowData($notice->{'unpaidItems'});
          @$upItemList =(
                @$headerRow_unpaid,
                @$upItemList);

    }
    if($srcCall eq 'odCirc'){
        @$retArr =(@$retArr,
                    {type=>'text_msg1',text=>''},
                    {type=>'text_msg1',text=>'Overdue Item List'},
                    @$odItemList
                   );
        if( $input->{'incOpt'}  eq 'incUnpaidNotice' && scalar(@$upItemList)>0){
            @$retArr =(@$retArr,
                        {type=>'text_msg1',text=>''},
                        {type=>'text_msg1',text=>''},
                        {type=>'text_msg1',text=>'Unpaid Item List'},
                        @$upItemList
                     );        
             
        }
    }
    else{
        if(scalar(@$upItemList)>0){
            @$retArr =(@$retArr,
                  {type=>'text_msg1',text=>''},
                  {type=>'text_msg1',text=>'Unpaid Item List'},
                  @$upItemList                 );
        }

        if(defined $notice->{'userBalanceInfo'}){
            @$retArr=(@$retArr,@{$notice->{'userBalanceInfo'}});
        } 
        if($input->{'incOpt'}  eq 'incOdNotice' && scalar @$odItemList){
            @$retArr =(@$retArr,{type=>'text_msg1',text=>''},
                      {type=>'text_msg1',text=>''},
                      {type=>'text_msg1',text=>'Overdue Item List'},
                      @$odItemList
                     );
        }
   }

    @$retArr =(@$retArr,@$msgBottom) if(scalar(@$msgBottom)>0);
    if($prtType eq 'address'){
        for(my $k=0; $k<5;$k++){
            push @$retArr,{type=>'text_msg2',text=>''}; #space line
        }
    }
    ($totalPage,$retArr)=formatPage($retArr,$optPage,$prtType);
    return ($totalPage,$retArr);
}
#----------------------------------------------------------------------------------------------------
 sub printOd_pdf{
    my($odData)=@_; 
    my $subPageCount = 1;
    my ($x,$y)=(X_LEFT_MARGIN,0);
    my ($x1,$x2) =(X_LEFT_MARGIN,X_LEFT_MARGIN + X_TABLE);
    my $totalPage=0;
    my $i=0;
    my $header_Y=0;
    if(!defined $optPage || $optPage >3 || $optPage<1  ){
        $optPage=1;
    }
    my $deviderLine_X=0;
    my $deviderLine_Y=($optPage-$subPageCount)*(Y_PAGE/$optPage);
                $header_Y =$deviderLine_Y -20;
    my $firstTblLine=0; 
    my $row_H=12;
    my $pageCount=1;
    my $firstPage=1;
    my $ii=0;
    foreach my $od(@$odData){
        if($subPageCount == 1 && !$firstPage){
          $pageN = $root->new_page;
        }
        $firstPage=0;
        $y = Y_PAGE - (Y_PAGE /$optPage)*($subPageCount-1) ;
        if($prtType eq 'address'){
            printMailingInfo($pageN,$od);
            for(my $k=0; $k<5;$k++){
                #push @{$od->{'oditems'}},{type=>'text_msg2',text=>''}; #space line
            }
            $y =Y_BODY;
        }
        else{
            my $userInfo=getUserInfo_line($od);
            push @$userInfo,{type=>'text_uInfo',text=>''}; #space line
            $od->{'userInfo'}=\@$userInfo;
            printHeader_handout($pageN,$f1,$x,$y);
            $y = $y - HEADER_HEIGHT_1;

            my $userBalanceInfo=getUserBalance_line($od);
            $od->{'userBalanceInfo'}=\@$userBalanceInfo;

        }
        
        my ($totalPage,$odItem)=formatNoticeData($od,$optPage,$prtType);
        #$totalPage =getTotalPage_od($odItem,$optPage,$prtType);
        $pageCount=1;
        
        foreach my $item(@$odItem){
            $row_H=defined $tblDef->{'rowHeight'}->{$item->{'type'}}?$tblDef->{'rowHeight'}->{$item->{'type'}}:12;
            if($y - $row_H < FOOTER_HEIGHT){
                $y = Y_PAGE - HEADER_HEIGHT_2 ;
                $subPageCount = 1;
                $deviderLine_Y=($optPage-$subPageCount)*(Y_PAGE/$optPage);
                $header_Y =$deviderLine_Y -20;
                $pageN = $root->new_page;
            }
            if(($y - $row_H) < $deviderLine_Y + FOOTER_HEIGHT  ){
                $pageN->line(0,$deviderLine_Y, X_PAGE,$deviderLine_Y );
                $firstTblLine =0;
                #--------------- print header page
                printHeader_handout_2($pageN,$f1,$x, $header_Y,$od);
                #--------------- print footer page
                $pageN->stringr($f1, 10,X_PAGE - X_RIGHT_MARGIN, $deviderLine_Y+10, "Page $pageCount/$totalPage");
                
                $pageCount++;
                $y = $deviderLine_Y - HEADER_HEIGHT_2;
                $subPageCount +=1;
                $deviderLine_Y=($optPage-$subPageCount)*(Y_PAGE/$optPage);
                $header_Y =$deviderLine_Y -20;
            }
            $y -=$row_H;
            if($item->{'border_B'} == 1 ){
                $pageN->line($x1, $y, $x2, $y);
            }
            if($item->{'type'} =~ m/^text/g){
                $firstTblLine=0;
            }
            elsif($firstTblLine ==0 && $item->{'type'} !~ m/text/g ){
                $pageN->line($x1, $y + $row_H, $x2, $y + $row_H);
                $firstTblLine=1;
            }
            $ii++;
            writeRow($pageN,$x1,$y,$x2,$y+$row_H,$item);

        }
        if($subPageCount==$optPage){
                $subPageCount =1;
        }
        else{
            $subPageCount +=1;
        }
        
        if($prtType eq 'address'){
            $pageN->line(300, $y- $row_H, 480,$y- $row_H );
        }

        $pageN->line(0,$deviderLine_Y, X_PAGE,$deviderLine_Y );
        $pageN->stringr($f1, 10,X_PAGE -  X_RIGHT_MARGIN, $deviderLine_Y+10, "Page $pageCount/$totalPage");
        $deviderLine_Y=($optPage-$subPageCount)*(Y_PAGE/$optPage);
        $header_Y =$deviderLine_Y -20;

       } #for( $i=0; $i<scalar(@$odData); $i++)
    $pdf->close;


}
#----------------------------------------------------------------------------------------------------
# START:Thu, Oct 20, 2011 @ 11:29:07 EDT
sub _getUserBalanceInfo{
    my($dbh,$uid) =@_;
    my $uBalanceInfo =undef;
    my $balance = trans_getBalance($dbh,$uid);
    if($balance ==0){
        $uBalanceInfo->{'zeroBalance'}=1;
    }
#
#    my $prevBalance=trans_getLastBalance($dbh,$uid);
#    my $totalFineCharge = trans_getTotalCharge($dbh,$uid);
#    $totalFineCharge = sprintf("%.2f",$totalFineCharge);
#    my $totalFgvPmt =trans_getTotalFgvPmt($dbh,$uid);
#    my $totalUnpaid = $totalFineCharge - $totalFgvPmt + $prevBalance;
#    $balance = sprintf("%.2f",$balance);
#    if($balance>0 && $balance != $totalFineCharge){
#        $uBalanceInfo->{'unBalance'}        = 1;
#        $uBalanceInfo->{'totalFgvPmt'}      = $totalFgvPmt!=0?$totalFgvPmt:0;
#        $uBalanceInfo->{'previousBalance'}  = $prevBalance!=0?$prevBalance:0;         
#    }
    $uBalanceInfo->{'balance'} = $balance>0?$balance:0;
#    $uBalanceInfo->{'totalFineCharge'} = $totalFineCharge!=0?$totalFineCharge:0;

    return $uBalanceInfo;
    
}
#----------------------------------------------------------------------------------------------------
# START:Thu, Oct 20, 2011 @ 11:29:07 EDT
sub print_userBalance{  
    my($pageN,$f1,$x,$y,$odData)=@_;
    my $txt = '';
    return if(!defined $odData->{"balance"} || $odData->{"balance"} ==0);
        $txt =  '   Amount to pay: $' .  $odData->{"balance"};
        $y -= ROW_HEIGHT_10;
        $pageN->stringr($f1, 10, $x,$y ,$txt );
                
    # END:Thu, Oct 20, 2011 @ 11:29:07 EDT
}
#----------------------------------------------------------------------------------------------------
sub printHeader_handout{
    my($pageN,$f1,$x,$y)=@_;
    $pageN->stringr($f1, 10,580, $y-16, $todayStr);
    $pageN->stringc($f1, 14,306, $y-36, $libname);

}
#----------------------------------------------------------------------------------------------------
sub printHeader_handout_2{
    my($pageN,$f1,$x,$y,$od)=@_;
    $pageN->stringl($f2, 10,$x, $y , "$od->{'lastname'}, $od->{'firstname'}");
    my $sWidth= 10 * $pageN->string_width($f2,"$od->{'lastname'}, $od->{'firstname'}");
    $pageN->stringl($f1, 10,$x+$sWidth, $y , " User Barcode: $od->{'userbarcode'}");
}

#----------------------------------------------------------------------------------------------------
sub getUserInfo_line{
    my ($odData)=@_;
    my $optNotice = Opals::Context->preference('reportGroup');
    my $libType = Opals::Context->preference('libraryType');
    my @userInfo=();
    my $lastname  = decode('utf8',$odData->{'lastname'});
    my $firstname  = decode('utf8', $odData->{'firstname'});
    my $classInfo ="";
    if($libType eq 'k-12'){
        $classInfo .= 'Homeroom: ' . $odData->{'homeroom'} if(index($optNotice,'1') >=0);
        $classInfo .= ' Teacher: ' . $odData->{'teacher'}  if(index($optNotice,"2") >=0);
        $classInfo .= ' Grade: ' .   $odData->{'grade'}    if(index($optNotice,"3") >=0);
    }
    push @userInfo,{type=>'text_uInfo',text=>$classInfo};
    my $ubc ="$lastname, $firstname";
       $ubc .= "  " . $odData->{'userbarcode'} if(index($optNotice,"5") >=0 && $odData->{'userbarcode'} ne "");
    push @userInfo,{type=>'text_uInfo',text=>$ubc} ;
    push @userInfo,{type=>'text_uInfo',text=>'Phone: ' . $odData->{'phone'}} if(index($optNotice,"4") >=0 && $odData->{'phone'} ne"");

    return \@userInfo;

}
#----------------------------------------------------------------------------------------------------
sub getUserBalance_line{
    my ($odData)=@_;
    return if(!defined $odData->{"balance"} || $odData->{"balance"} ==0);
       
    my @userBalanceInfo= ();
    my $txt =   sprintf("%72s", ""); 
    $odData->{"balance"} = '0.00' if($odData->{"balance"} ==0);
    $txt .= '   Amount to pay: $'  . $odData->{"balance"};
     
    push @userBalanceInfo,{type=>'text_uBalance',text=>''};
    push @userBalanceInfo,{type=>'text_uBalance',text=>$txt};
    return \@userBalanceInfo;

}


#----------------------------------------------------------------------------------------------------
sub formatPage{
    my($odArr,$optPage,$prtType)=@_;
    my $total=1;
    my @retArr=();
    my $pageH= floor(Y_PAGE /$optPage);
    my $sumRowH=FOOTER_HEIGHT;
    $sumRowH += $prtType eq 'address' ?Y_BODY : HEADER_HEIGHT_1;
    my ($cType,$nType,$cRowH,$nRowH)=(0,0,0,0);
    for(my $i =0; $i< scalar(@$odArr); $i++){
        $cType = @$odArr[$i]->{'type'};
        $cRowH = $tblDef->{'rowHeight'}->{$cType};
        if($i +1 < scalar(@$odArr)) {
            $nType =@$odArr[$i +1]->{'type'};
            $nRowH= $tblDef->{'rowHeight'}->{$nType};
            if($nType =~ m/Data_sub$/g && ($sumRowH + 2*$cRowH )>= $pageH){
                push @retArr,{type=>'text_msg3',text=>''};
                $sumRowH=HEADER_HEIGHT_2 + FOOTER_HEIGHT;
                $total++;
            }
        }

        if($sumRowH +$cRowH  > $pageH){

            $total++;
            $sumRowH=HEADER_HEIGHT_2 + FOOTER_HEIGHT;
        }
        $sumRowH += $cRowH;
        
        push @retArr,@$odArr[$i];
    }
    return ($total,\@retArr);
}

#----------------------------------------------------------------------------------------------------
sub getTotalPage_od_bk{
    my($odArr,$optPage,$prtType)=@_;
    my $total=1;
    my $pageH= floor(Y_PAGE /$optPage);
    my $sumRowH=FOOTER_HEIGHT;
    $sumRowH += $prtType eq 'address' ?Y_BODY : HEADER_HEIGHT_1;
    foreach my $r(@$odArr){
        if($sumRowH +$tblDef->{'rowHeight'}->{$r->{'type'}} > $pageH){
            $total++;
            $sumRowH=HEADER_HEIGHT_2 + FOOTER_HEIGHT;
        }
        $sumRowH += $tblDef->{'rowHeight'}->{$r->{'type'}};
    }
    return $total;
}
#----------------------------------------------------------------------------------------------------
sub printMailingInfo{
    my($pageN,$odData)=@_;
    my @address_fr=();
    my @address_to=();
    my ($x,$y) = ( X_ADDRESS,Y_ADDRESS_FR);

         # Sender address         
    push @address_fr,"$libname ";
    push @address_fr,$libAddress;
    my $tmpAdd = "";
    $tmpAdd .= $libCity  if($libCity ne "");
    $tmpAdd .= ", $libState " if($libState ne "");
    $tmpAdd .= " $libZip " if($libZip ne "");
    push @address_fr,$tmpAdd;
    printInfo($pageN,$f1,\@address_fr,$x,$y);
        # greeting message
    my @msgSender;
    if($printGreeting && $printGreeting eq '1'){
        foreach my $l(@lang){
           push @msgSender, $messages->{'messageTo'}->{$l};
        }   
    }
    my $senderStr = join(" / ",@msgSender);
    $pageN->stringl($f1, 9,$x, Y_ADDRESS_TO +4 , $senderStr);
         # Receiver address
    my $lastname  = decode('utf8',$odData->{'lastname'});
    my $firstname  = decode('utf8', $odData->{'firstname'});
    my $addrLine1  = decode('utf8', $odData->{'addrLine1'});
    my $addrLine2  = decode('utf8', $odData->{'addrLine2'});
    my $city  = decode('utf8', $odData->{'city'});
    my $zip  = decode('utf8', $odData->{'zip'});
    my $state  = decode('utf8', $odData->{'state'});
    push @address_to,"$lastname, $firstname";
    push @address_to,"$addrLine1";
    if($addrLine2 ne ""){
        push @address_to,$addrLine2;
    }
    my $addrLine3  ;
    $addrLine3 = $city;
    $addrLine3 .= ", $state " if($state ne "");
    $addrLine3 .= " $zip " if($zip ne "");
    push @address_to,$addrLine3;
    printInfo($pageN,$f1,\@address_to,$x,Y_ADDRESS_TO);
    my $userBc="";
    $userBc= "User Barcode: " . $odData->{'userbarcode'} if($odData->{'userbarcode'} ne "");
    $pageN->stringr($f1, 10,X_TABLE + X_LEFT_MARGIN,  Y_ADDRESS_TO  ,$userBc );

    print_userBalance($pageN,$f1,X_TABLE + X_LEFT_MARGIN,Y_ADDRESS_TO,$odData);
    $pageN->stringr($f1, 10,X_PAGE - X_RIGHT_MARGIN, Y_PAGE - 20  ,$todayStr );

    
}

#----------------------------------------------------------------------------------------------------
sub printInfo{
    my($pageN,$f1,$info,$x,$y)=@_;
    for(my $i=0;$i<scalar(@$info); $i++){
       $pageN->stringl($f1, 10,$x, $y -($i+1)*ROW_HEIGHT_10  , @$info[$i] );        
    }
    
}
#----------------------------------------------------------------------------------------------------
sub writeCell{
    my($pos,$pageN,$f,$fs,$x,$y,$txtStr)=@_; 
    if ($pos eq "left"){   
        $pageN->stringl($f,$fs,$x,$y,$txtStr);
    }
    elsif ($pos eq "right"){   
        $pageN->stringr($f,$fs,$x,$y,$txtStr);
    }
    else{   
        $pageN->stringc($f,$fs,$x,$y,$txtStr);
    }
   # print $pageN->string_width($f,$txtStr) ." -- $txtStr\n";
}
#----------------------------------------------------------------------------------------------------
# 2007-10-18
# There is a bug in pdf writer which will not write properly if there are unclose 
# open round brakets "(".
# example : string "click here :(to find" will not be write to the pdf file.
# Solution: add ")" if it's missing.
#
sub formatStr{
    my($pageN,$f,$fs,$inStr,$len)=@_;
    my $outStr=$inStr;
    $outStr =~ s/\s+$//g;

    my $sWidth= $fs * $pageN->string_width($f,$outStr);
    if($sWidth<=$len){
        return $outStr;
    }
    while($sWidth > $len){
       $outStr =~ s/\S+$//g;
       $outStr =~ s/\s+$//g;
       $sWidth= $fs * $pageN->string_width($f,$outStr );
    }
    return $outStr  ;
}
#----------------------------------------------------------------------------------------------------
sub formatStr_nRow{
    my($pageN,$f,$fs,$inStr,$len,$nRow)=@_;
    my $outStr=$inStr;
    my @outStrArr=();
    $outStr =~ s/\s+$//g;
    my $n=1;
    my $sWidth= $fs * $pageN->string_width($f,$outStr);
    if($sWidth<=$len){
        $outStr =~ s/(\(|\))/\\$1/g;
        push @outStrArr,$outStr;
        return \@outStrArr;
    }
    while($n<$nRow && $outStr ne ''){
        while($sWidth > $len){
           $outStr =~ s/\S+$//g;
           $outStr =~ s/\s+$//g;
           $sWidth= $fs * $pageN->string_width($f,$outStr );
        }
        push @outStrArr,$outStr;
        $inStr =substr($inStr,length($outStr)); 
        $inStr =~ s/^\s+//g;
        $outStr=$inStr;
        $sWidth= $fs * $pageN->string_width($f,$outStr);
        $n++;
    }
    if($n >=$nRow && $inStr ne ''){
        push @outStrArr,formatStr($pageN,$f,$fs,$inStr,$len);
    }
    foreach my $str(@outStrArr){
         $str=~ s/(\(|\))/\\$1/g;
    }
    return \@outStrArr  ;
}


#----------------------------------------------------------------------------------------------------
sub writeRow{
    my($pageN,$x1,$y1,$x2,$y2,$text)=@_;
      my ($font,$fontSize) = ($f1,10);  
      $font =$tblDef->{$text->{'type'}}->{'font'} if(defined $tblDef->{$text->{'type'}}->{'font'}  );
      if($text->{'type'} =~ m/odNotice|unpaidItem/g){
          writeRow_headerData($pageN,$font,$fontSize,$x1,$y1,$x2,$y2,$text );
      }
      elsif($text->{'type'}=~ m/^text/g){
          writeRowText($pageN,$font,$fontSize,$x1,$y1,$x2,$y2,$text);
      }

}
#----------------------------------------------------------------------------------------------------
sub writeRowText{
    my($pageN,$font,$fontSize,$x1,$y1,$x2,$y2,$text)=@_;
    writeCell('left',$pageN,$font,$fontSize, $x1, $y1 +5,   $text->{'text'}) ;
}
#----------------------------------------------------------------------------------------------------
sub writeRow_headerData{
    my($pageN,$font,$fontSize,$x1,$y1,$x2,$y2,$text)=@_;
 
    my $x=$x1;
    my $type=$text->{'type'};
    my $tDef    = $tblDef->{$type};
    my ($align,$width,$font,$fontSize,$padding);
    $pageN->line($x, $y1, $x,$y2);   
    my $xPos;
    my $columns;
    if($type =~ m/odNotice/g) {
        $columns=$headers->{'odNotice'};
    }
    else{
        $columns=$headers->{'unpaidItem'};
    }
    foreach my $field(@$columns){
        if(($field eq 'title' && $optTitle !=1)||
           ($field eq 'price' && $optPrice !=1)){
            next;
        }
        else{
            $align      =$tDef->{$field}->{'align'};
            $width      =$tDef->{$field}->{'width'};
            $font       =$tDef->{$field}->{'font'};
            $padding    =$tDef->{$field}->{'padding'};
            $fontSize   =$tDef->{$field}->{'fontSize'};
            $xPos =$x;
            if($align eq 'center'){
                $xPos +=ceil($width/2);
            }
            elsif($align eq 'right'){
                $xPos +=$width -$padding;
            }
            else{
                $xPos +=$padding;
            }
            writeCell($align,$pageN,$font,$fontSize,$xPos, $y1 +5, $text->{$field}) ; 
            $x +=$width;
        }
        $pageN->line($x, $y1, $x,$y2);   

    }

    $pageN->line($x2, $y1, $x2,$y2);
} 
#----------------------------------------------------------------------------------------------------
sub saveMsgToPrefTbl{
    my($msgTopCbox,$msgBotCbox,$msgTop,$msgBot)=@_;

    if($msgTopCbox){
        $dbh->do("update opl_preference set val='$msgTop' where var='odNoticeMsgTop'") ;
    }

    if($msgBotCbox){
        $dbh->do("update opl_preference set val='$msgBot' where var='odNoticeMsgBottom'") ;
    }

}
