package Opals::Date;

require Exporter;
@ISA       = qw(Exporter);
# Symbols to be exported by default
#@EXPORT    = qw(
#    opl_
#);
# Symbols to be exported on request
@EXPORT_OK = qw(
    date_parse
    date_today
    date_deltaWorkDay
    date_deltaWorkDay_bk
    date_deltaMonth
    date_validateWorkday
    date_text
    date_text_lang
    date_time_text
    date_DHM_text
    date_addDeltaWorkday
    date_nearestWorkday
    date_nearestWorkday_bk
    date_f005
    date_now
    date_profileList
    date_getDeadLineDate

    dateTime_parse
    date_deltaWorkDayHour
    date_getDeadLineDateTime
    date_calcHourOverdue
);
# Version number
$VERSION   = 0.01;      

#use utf8;
use strict;
use POSIX qw(
    ceil
    floor
    strftime
);

use Date::Calc::Object qw(
    :all
);
use Date::Calc qw(
    Today 
    Day_of_Week
    Delta_Days 
    Delta_DHMS
    Add_Delta_Days 
    Delta_YMD 
    Date_to_Time
);
use Date::Calendar;
use Date::Calendar::Profiles qw(
    $Profiles
);
use Opals::Context;

# use this system variable to determine whether loan period should include
# holidays 

my $excludeHoliday=Opals::Context->preference("useHolidays");

my @holidays;
my @closingWD;
   @holidays  = getHolidays();
   @closingWD = getClosingWD();
my $openMinutes = getOpenMinutes();

my $dow_long     = {fr=>['Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche'],
                    en=>['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
                    sp=>['Lunes','Martes','Miércoles','Jueves','Viernes','Sábado','Domingo'],
                    pt=>['Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado', 'Domingo'],
                    ar=>['الإثنين','الثلاثاء','الأربعاء','الخميس','الجمعة','السبت','الأحد'],
                    ru=>['Понедельник','Вторник','Среда','Четверг','Пятница','Суббота','Воскресенье'],
                    es=>['lunes','martes','miércoles','jueves','viernes','sábado','domingo']
                   };
my $dow_short    = {fr=>['Lun','Mar','Mer','Jeu','Ven','Sam','Dim'],
                    en=>['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
                    sp=>['Lun','Mar','Mié','Jue','Vie','Sáb','Dom'],
                    pt=>['Seg','Ter','Qua','Qui','Sex','Sáb','Dom'],
                    ar=>['الإثنين','الثلاثاء','الأربعاء','الخميس','الجمعة','السبت','الأحد'],
                    ru=>['Понедельник','Вторник','Среда','Четверг','Пятница','Суббота','Воскресенье'],
                    es=>['lun','mar','mié','jue','vie','sáb','dom']
                   };
my $months_long  = {fr=>['Janvier','Fevrier','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
                    en=>['January','February','March','April','May','June','July','August','September','October','November','December'],
                    sp=>['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'],
                    pt=>['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
                    ar=>['يناير','فبراير','مسيرة','أبريل','قد','يونيو','يوليو','أغسطس','سبتمبر','تشرين الأول','تشرين الثاني','ديسمبر'],
                    ru=>['январь','Февраль','Март' ,'Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
                    es=>['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']                
                   };
my $months_short = {fr=>['Jan','Fev','Mar','Avr','Mai','Juin','Juillet','Août','Sept','Oct','Nov','Déc'],
                    en=>['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
                    sp=>['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'], 
                    pt=>['Jan','Feb','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'], 
                    ar=>['يناير','فبراير','مسيرة','أبريل','قد','يونيو','يوليو','أغسطس','سبتمبر','تشرين الأول','تشرين الثاني','ديسمبر'],
                    ru=>['январь','Февраль','Март' ,'Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
                    es=>['ene','feb','mar','abr','may','jun','jul','ago','sep','oct','nov','dic']  
                   };
my $preposition={en=>{at=>'at'},
                 fr=>{at=>'à'},
                 sp=>{at=>'a las'},
                 pt=>{at=>'a las'},
                 ar=>{at=>'at'},
                 ru=>{at=>'в'},
                 es=>{at=>'a las'}
                };
#Wed, Dec 02, 2009 @ 10:59:45 EST
my $supportLang= '[en][fr][sp][pt][es][ar]';
   
#======================================================================================================================
#  Date: 2007 Aug/09
#
#
#
sub getHolidays {
    
    my $dbh = Opals::Context->dbh();
    my $sth = $dbh->prepare(<<_STH_);
select  dClosed
from    opl_dateClosed
where   closed='1'
        order by dClosed 
_STH_
        $sth->execute;
        while (my $d = $sth->fetchrow_hashref) {
           push  @holidays,date_parse($d->{"dClosed"});
        }
        $sth->finish;
        $dbh->disconnect;
    

    return @holidays;
}
#======================================================================================================================
#  Date: 2007 Aug/09
#
#
#

sub getClosingWD{
    my $dbh = Opals::Context->dbh();
    my @cWD=();
    my ($open) =$dbh->selectrow_array("select weekday  from  opl_openHours  where (open<>'' && open<> 'close')");
    if($open ne ''){
          
        my $sth = $dbh->prepare(<<_STH_);
select weekday 
from  opl_openHours 
where (open='' || open regexp 'close') 
_STH_
        $sth->execute;
        while (my $d = $sth->fetchrow_hashref) {
           push  @cWD,$d->{"weekday"};                  
        }
        $sth->finish;
        $dbh->disconnect;
    }
    else{  #no open hours set default closed days to Sunday and Saturday.
        @cWD=(0,6);
    }
  
  return @cWD;    
}
#======================================================================================================================
sub getOpenMinutes{
    my $dbh = Opals::Context->dbh();
    my $sth=$dbh->prepare("select weekday,open ,close from opl_openHours where open<>'' && close <>''");
    $sth->execute();
    my $openMinutes={};
    while(my($wd,$oh ,$ch) =$sth->fetchrow_array){
        my $close =_converTime2Minute($ch);  
        my $open  =_converTime2Minute($oh);
        push @{$openMinutes->{$wd}},{open=>$open, close=>$close};
    }
    return  $openMinutes;

}
#======================================================================================================================
sub _converTime2Minute{
    my ($time)=@_;
    my @h=split ":",$time;
    my $minute=0;
    if(scalar(@h)==2 ){
        $minute =int($h[0])*60 + int($h[1]);
    }
    return $minute;
}
#=====================================================================
#Mon, Oct 03, 2011 @ 10:45:43 EDT
sub date_calcHourOverdue{
    my($dateTime1, $dateTime2)=@_;
    return 0 if(Date_to_Time($dateTime1->datetime()) > Date_to_Time($dateTime2->datetime()));

#   open              close   open                close
#   |                 |        |                   |
#   ------------------- ...... --------------------
#       |    |    |              |
#      due1  |   ret1            |
#           due2                ret2 
#
 
    my ($year1, $month1, $day1,$hour1,$minute1,$sec1) =$dateTime1->datetime();
    my $d1=Date::Calc->new($year1, $month1, $day1); 
    my ($year2, $month2, $day2,$hour2,$minute2,$sec2) =$dateTime2->datetime();
    my $d2=Date::Calc->new($year2, $month2, $day2); 
    my $minute=0;
    my $wd1 =Day_of_Week($d1->date())%7;
    my $wd2 =Day_of_Week($d2->date())%7;
    if($d1 == $d2){#return on the due date 
        # calculate the remaining  minutes overdue on due date
        if(defined $openMinutes->{$wd2} && !isHoliday($d1)){
            my $mDue  = 60*$hour1 +$minute1;
            my $mRet  = 60*$hour2 +$minute2;
            foreach my $h(@{$openMinutes->{$wd2}}){
                my ($mOpen,$mClose)=($h->{'open'},$h->{'close'});
                if($mDue >= $mOpen && $mDue <= $mClose && $mRet<=$mClose){
                    $minute +=$mRet - $mDue;
                }
                elsif($mRet >$mClose){
                    $minute +=$mClose - $mDue;
                }
                else{
                    $minute +=$mRet -$mOpen ;
                }
            }
        }
    }
    else{ #return after the due date
        # calculate the remaining  minutes overdue on due date 
        if(defined $openMinutes->{$wd1} && !isHoliday($d1)){
            foreach my $h(@{$openMinutes->{$wd1}}){
                my ($mOpen,$mClose)=($h->{'open'},$h->{'close'});
                my $mDue  = 60*$hour1 +$minute1;
                next if($mDue>$mClose);
                if($mDue>=$mOpen &&  $mDue<= $mClose){
                    $minute +=($mClose - $mDue);
                }
                else{
                    $minute +=($mClose - $mOpen);
                }
               

            }
                    }
        $d1 += [0,0,1];
        while($d1 <$d2){# calculate the minutes overdue between due date and date return 
            my $wd =Day_of_Week($d1->date())%7;
            if(defined $openMinutes->{$wd} && !isHoliday($d1)){
                foreach my $h(@{$openMinutes->{$wd}}){
                    $minute += $h->{'close'} -$h->{'open'};
                }
            }
            $d1 += [0,0,1];
        }
        #calucate  minute overdue on date return 
        if(defined $openMinutes->{$wd2} && !isHoliday($d1)){
            my $mRet = 60*$hour2 +$minute2;
            foreach my $h(@{$openMinutes->{$wd2}}){
                if($mRet >=$h->{'open'} && $mRet <=$h->{'close'} ){
                    $minute += $mRet - $h->{'open'};
                }
                else{
                    $minute += $h->{'close'} - $h->{'open'};

                }

            }
        }
    }

    return (floor($minute/60),$minute%60);
    
}

#======================================================================================================================
sub date_calendar {
    my ($useClosingDates) = @_;

    my %gCalProfile;
    
    if ($useClosingDates eq 'true') {
        my $dbh = Opals::Context->dbh();
        my $sth = $dbh->prepare(<<_STH_);
select  *
from    opl_dateClosed
_STH_
        $sth->execute;
        my $cDate;
        my $emptyCount = 0;
        while (my $d = $sth->fetchrow_hashref) {
            $cDate = substr($d->{'dClosed'}, 5);
            $cDate =~ s/-/\//;
#        if (!$d->{'dLabel'}) {
#            $emptyCount++;
#            $d->{'dLabel'} = "Empty Label #$emptyCount";
#        }
            $d->{'dLabel'} = $d->{'dClosed'} . $d->{'dLabel'};
            $gCalProfile{$d->{'dLabel'}} = $cDate;
        }
        $sth->finish;
        $dbh->disconnect;
    }

    return Date::Calendar->new(\%gCalProfile);
}


=item date_

The date_parse() function 

=cut

#======================================================================================================================
sub date_parse {
    my ($dateStr) = @_;

    return unless ($dateStr);

    my ($year, $month, $day);
    if ($dateStr =~ /^([\d]{4})-([\d]{1,2})-([\d]{1,2})/ ||
        $dateStr =~  /^([\d]{4})([\d]{2})([\d]{2})/) {
        ($year, $month, $day) = ($1, $2, $3);
    }
    else{
        unless (($year, $month, $day) = Decode_Date_US($dateStr)) {
            unless (($year, $month, $day) = Decode_Date_EU($dateStr)) {
                 (($year, $month, $day) = Parse_Date($dateStr)) 
            }
        }
    }

    return Date::Calc->new($year, $month, $day);
}


=item date_

The date_() function

=cut
#======================================================================================================================
sub dateTime_parse {
    my ($dateTimeStr) = @_;

    return unless ($dateTimeStr);

    my ($year, $month, $day, $hour, $minute, $second);
    
    unless (($year, $month, $day) = Decode_Date_US($dateTimeStr)) {
        unless (($year, $month, $day) = Decode_Date_EU($dateTimeStr)) {
            unless (($year, $month, $day) = Parse_Date($dateTimeStr)) {
                if ($dateTimeStr =~ /^([\d]{4})-([\d]{1,2})-([\d]{1,2}) ([\d]{1,2}):([\d]{1,2}):([\d]{1,2})/) {
                    ($year, $month, $day, $hour, $minute, $second) = ($1, $2, $3,$4, $5, $6);
                }
                elsif($dateTimeStr =~ /^([\d]{4})-([\d]{1,2})-([\d]{1,2})/){
                    ($year, $month, $day, $hour, $minute, $second) = ($1, $2, $3,0,0,0);
                }
            }
        }
    }

    return Date::Calc->new(1,$year, $month, $day, $hour, $minute, $second);
}

#======================================================================================================================
sub date_today {
    return Date::Calc->today();
}


=item date_

The date_() function

=cut

#======================================================================================================================
sub date_nearestWorkday_bk {
    my ($dateFirst, $dateLast, $date) = @_;

    return $date unless ($dateFirst && $dateLast);
    
    unless ($date) {
        $date = date_today;
    }

    my $gCal = date_calendar('true');
    my ($nwd, $dow, $delta); # $nwd: nearest workday

    $nwd = $date;
    my ($year, $month, $day) = $nwd->date();
    $dow = Day_of_Week($year, $month, $day);
    if (!$gCal->is_full($nwd) && !$gCal->is_half($nwd) &&
        $dow != 6 && $dow != 7 &&
        $nwd >= $dateFirst && $nwd <= $dateLast) {
        return $nwd;
    }

#open ccc, ">/tmp/ccc";
#    my ($year, $month, $day) = $nwd->date();
    $delta = 1;
    while ($delta && $nwd && $nwd <= $dateLast) {
#print ccc "\nf1. $year, $month, $day: $delta\n";
        ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $delta);
        $nwd = $nwd->new($year, $month, $day);
        $dow = Day_of_Week($year, $month, $day);
        
        if ($dow == 6) {
            $delta = 2; #$delta += 2;
        }
        elsif ($dow == 7) {
            $delta = 1; #$delta += 1;
        }
        else {
            $delta = ( $gCal->is_full($nwd) || $gCal->is_half($nwd) ) ? 1 : 0;
        }
#print ccc "f2. $year, $month, $day: $delta\n";

        if (!$delta) {
#close ccc;
            return $nwd;
        }
    }

    $nwd = $date;
    ($year, $month, $day) = $nwd->date();
    $delta = -1;
    while ($delta && $nwd && $nwd >= $dateFirst) {
#print ccc "\np1. $year, $month, $day: $delta\n";
        ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $delta);
        $nwd = $nwd->new($year, $month, $day);
        $dow = Day_of_Week($year, $month, $day);
        if ($dow == 7) {
            $delta = -2;
        }
        elsif ($gCal->is_full($nwd) || $gCal->is_half($nwd) || $nwd > $dateLast) {
            $delta = -1;
        }
        else {
            $delta = 0;
        }
#print ccc "p2. $year, $month, $day: $delta\n";

        if (!$delta) {
#close ccc;
            return $nwd;
        }
    }
}

#======================================================================================================================
sub date_nearestWorkday {
    my ($dateFirst, $dateLast, $date) = @_;
    my $today = date_today();
    if(!$date || $date < $today) {
        $date =$today;
    }

    return $date unless ($dateFirst && $dateLast);
    if($date > $dateLast){
        if($today >$dateLast ){
            return $date;
        }
        else{
            return $dateLast;
        }
    }
    elsif($date < $dateFirst && $today < $dateFirst){
         return $date;
    }  
    else{
        while((isClosed(Day_of_Week($date->date())%7) || isHoliday($date)) && $date < $dateLast){
            $date +=[0,0,1];
        }
    }

    return $date;
}


=item date_

The date_() function

=cut
#======================================================================================================================
#  Date: 2007 Aug/09
#
#
#

sub getNumOfHolidays{
    my($d1,$d2)=@_;
    my $ret=0;  
    if($d1->is_long()){
        $d1=Date::Calc->new($d1->date());
    }
    if($d2->is_long()){
        $d2=Date::Calc->new($d2->date());
    }    
    for(my $i=0; $i<scalar(@holidays) && $holidays[$i]<=$d2 ; $i++){
        if($holidays[$i]>=$d1){
             $ret++;
        }
    }    
    return $ret;
}

#======================================================================================================================
#  Date: 2007 Aug/09
#
#
#
sub getNumOfClosingWD{
    my($d1,$d2)=@_;
    my $ret=0;   
    my ($year1, $month1, $day1)=$d1->date();
    my ($year2, $month2, $day2)=$d2->date();
    my $deltaDays= Delta_Days($year1, $month1, $day1, $year2, $month2, $day2);
       $ret =floor($deltaDays/7) * scalar(@closingWD);

    my $r =$deltaDays%7;
    my $dow_d1 =Day_of_Week($d1->date());
    for(my $dow=$dow_d1; $dow<= $dow_d1+$r; $dow++){
       $ret +=isClosed($dow%7); 
    }
    return $ret;
    
}
#======================================================================================================================
#  Date: 2007 Aug/09
#
#
#
sub isClosed{
    my ($d)= @_;
    for(my $i=0; $i<scalar(@closingWD); $i++){
        if($d==$closingWD[$i]){
            return 1;
        }
    }
    return 0;
}

sub isHoliday{
    my ($d)= @_;
    for(my $i=0; $i<scalar(@holidays); $i++){
        if($d==$holidays[$i]){
            return 1;
        }
    }
    return 0;
}
#======================================================================================================================
#Thu, Sep 29, 2011 @ 11:44:22 EDT
#
sub date_calculateHourOverdue{
    my($dateTime1, $dateTime2)=@_;

}



#======================================================================================================================
sub date_deltaWorkDay_bk {
    my ($date1, $date2) = @_;
    
    return unless ($date1 && $date2);
    
    my $gCal = date_calendar('true');
    return $gCal->delta_workdays($date1, $date2, 1, 0);
}


#======================================================================================================================
#  Date: 2007 Aug/09
#
#
#

sub date_deltaWorkDay{
    my ($date1, $date2) = @_;
    
    return unless ($date1 && $date2);
    my $deltaDays= Delta_Days($date1->date(), $date2->date());
    my $numOfClosedDate = getNumOfClosingWD($date1, $date2)
                        + getNumOfHolidays($date1, $date2);
                        
    return $deltaDays-$numOfClosedDate ;
    
}
=item date_

The date_() function

=cut

sub date_deltaWorkDayHour{
    my ($dateTime1, $dateTime2) = @_;
    
    return unless ($dateTime1 && $dateTime2);
    my ($deltaDays,$delHours,$delMinutes,$delSeconds)= Delta_DHMS($dateTime1->datetime(), $dateTime2->datetime());
    my $numOfClosedDate = getNumOfClosingWD($dateTime1, $dateTime2)
                        + getNumOfHolidays($dateTime1, $dateTime2);
     $deltaDays -= $numOfClosedDate  ;                
    return ($deltaDays,$delHours,$delMinutes) ;
    
}


#======================================================================================================================
sub date_addDeltaWorkday_bk {
    
    my ($date, $deltaWorkDay) = @_;

    return unless ($date);

    my $gCal = date_calendar('false');
    return $gCal->add_delta_workdays($date, $deltaWorkDay);
    
}

#======================================================================================================================
#  Date: 2007 Aug/09
#
#
#
sub date_addDeltaWorkday {
    my ($date, $deltaWorkDay) = @_;
    return unless ($date);
    

    #my $gCal = date_calendar('false');
    while(isClosed(Day_of_Week($date->date()))%7){
         $date += [0,0,-1];
    }

    my $retDate = $date + [0,0,$deltaWorkDay];

    my $numOfClosingDays =0;
    $numOfClosingDays = getNumOfClosingWD($date,$retDate);
    
    $numOfClosingDays +=$excludeHoliday?getNumOfHolidays($date,$retDate):0;

    while($numOfClosingDays >0){
        my $d1 = $retDate + [0,0,1];
        
        $retDate += [0,0,$numOfClosingDays];
        $numOfClosingDays = getNumOfClosingWD($d1,$retDate);
        $numOfClosingDays +=$excludeHoliday?getNumOfHolidays($d1,$retDate):0;        
    }
    return $retDate; 
  
 }

#======================================================================================================================
sub date_deltaMonth{
    my ($date1, $date2)=@_;
    my(@delta);
    @delta =Delta_YMD($date1->year(),$date1->month(),$date1->day(),$date2->year(),$date2->month(),$date2->day());
    return $delta[0]*12 + $delta[1] +1;
}

=item date_

The date_() function

=cut

#======================================================================================================================
sub date_validateWorkday {
    my ($dateDeadline, $deltaDay) = @_;

    return unless ($dateDeadline->is_valid());

    my $today = date_today();
    if ($dateDeadline <= $today) {
        $dateDeadline = date_addDeltaWorkday($today, $deltaDay);
    }

    my $dFirst = Opals::Context->preference('dateFirst');
    my $dLast  = Opals::Context->preference('dateLast');
  
    my $dateFirst = date_parse($dFirst);
    my $dateLast  = date_parse($dLast);
    $dateDeadline = date_nearestWorkday($dateFirst, $dateLast, $dateDeadline);
 

    return $dateDeadline;
}


=item date_

The date_() function

=cut

#======================================================================================================================
sub date_text {
    my ($dateStr, $long,$lang) = @_;
    #($long == 1) || ($long = 0);
     if($long != 1){
         $long=0;
     }
    my ($year, $month, $day);
    
    unless (($year, $month, $day) = Decode_Date_US($dateStr)) {
        unless (($year, $month, $day) = Decode_Date_EU($dateStr)) {
            unless (($year, $month, $day) = Parse_Date($dateStr)) {
                if ($dateStr =~ /^([\d]{4})-([\d]{1,2})-([\d]{1,2})/) {
                    ($year, $month, $day) = ($1, $2, $3);
                }
                else {
                    ($year, $month, $day) = ('1900', '01', '01');
                }
            }
        }
    }
    
    return date_text_lang($year, $month, $day, $long,$lang);
}

=item date_

The date_() function

=cut
#======================================================================================================================
sub date_text_lang {
    my ($year, $month, $day,$long,$lang) = @_;
  

   if(!$lang || !$dow_long->{$lang}){
       $lang =$ENV{'curLang'};
    }
   my $dow;
   my $moy;
   my $retDate="";
   if($long==1){
        $dow= $dow_long->{$lang};
        $moy= $months_long->{$lang};
        $dow= @$dow[Day_of_Week($year,$month,$day) -1];
        $moy = @$moy[$month -1];
       if($lang eq 'fr'){
          $retDate ="$dow $day $moy $year" ;
       }
       elsif($lang eq 'sp' || $lang eq 'es'){
          $retDate ="$dow, $day de $moy de $year" ;
       }
       else{
          $retDate ="$dow, $moy $day $year" ;
       }
   }
   else{
       $dow= $dow_short->{$lang};
       $moy= $months_short->{$lang};
       $dow= @$dow[Day_of_Week($year,$month,$day) -1];
       $moy = @$moy[$month -1];
       if($lang eq 'fr'){
          $retDate ="$dow $day $moy $year" ;
       }
       elsif($lang eq 'sp' || $lang eq 'es'){
          $retDate ="$dow $day $moy $year" ;
       }
       else{
          $retDate ="$dow $moy $day, $year" ;
       }
   }
   return $retDate;
}

#======================================================================================================================
sub date_f005 {
  my @lt = localtime;

  return strftime('%Y%m%d%H%M%S', @lt).".$lt[8]";
}


#======================================================================================================================
sub date_now {
  #return strftime('%Y-%m-%d %H:%M:%S', localtime);
  return strftime('%F %T', localtime);
}


=item date_

The date_() function

=cut

#======================================================================================================================
sub date_profileList {
#    my () = @_;
    my $dProfile = Opals::Context->preference('dateProfile');
    
    my @calProfile;
    my ($country, $state);
    my $profileName;
    foreach my $k (sort keys %{$Profiles}) {
#        $k =~ m/^([\w]{2})-*([\w]*)$/;
#        $country = $1;
#        $state   = $2;
#        $profileName = $country;#code2country($country);
#        if ($state) {
#            $profileName .= ' - ' . $state;
#        }
        $profileName = $k;
        push @calProfile,
            {
                profileCode => $k,
                profileName => $profileName,
                onSelect    => ($k eq $dProfile),
            };
    }

    return \@calProfile;
}


=item date_

The date_() function

=cut

#sub date_ {
#    my () = @_;

#    return ;
#}

#---------------------------------------------------------
sub date_getDeadLineDate{
    my ($lengthDay,$dateStr)= @_;
    my $retDate;
    my $ddate = date_parse($dateStr);
    $ddate = date_today() unless ($ddate);
    
    if($lengthDay>0) {
        $ddate = date_addDeltaWorkday($ddate, $lengthDay);
        $ddate = date_validateWorkday($ddate,$lengthDay);
    }
    my ($year,$month,$day) = $ddate->date();
    $retDate = sprintf("%04d-%02d-%02d 23:59:59",$year,$month,$day);
    return $retDate;
}

#---------------------------------------------------------
#Wed, May 12, 2010 @ 16:30:47 EDT

sub date_getDeadLineDateTime{
    my ($lengthHour,$dateStr)= @_;
    my $retDate;
    
    if($lengthHour<=0) {
        return $dateStr;
    }
     
    my $ddate = dateTime_parse($dateStr);
    $ddate = date_now() unless ($ddate);
    my ($year,$month,$day,$hour,$min,$sec) =  (@$ddate[1],@$ddate[2],@$ddate[3],@$ddate[4],@$ddate[5],@$ddate[6]);
    ($year,$month,$day,$hour,$min,$sec) =Add_Delta_DHMS($year,$month,$day,$hour,$min,$sec,0, $lengthHour,0,0);
    my $dow = Day_of_Week($year, $month, $day);
 
    my $timeStr=validateLibCloseHour($dow,"$hour:$min:$sec");
    $retDate = sprintf("%04d-%02d-%02d $timeStr",$year,$month,$day);

    return $retDate;
}

#---------------------------------------------------------
sub validateLibCloseHour{
    my($wd,$timeStr)=@_;
    my $retval =$timeStr;
    my $dbh = Opals::Context->dbh();
    my $sth =$dbh->prepare(<<_SQL_);
    select if(open<>'',least(cast(? as time),max(cast(close as TIME))),?) from opl_openHours where weekday=?
_SQL_
    $sth->execute($timeStr,$timeStr,$wd);
    if(my ($r)= $sth->fetchrow_array()){
        $retval=$r;
    }
    return $retval;
    
}

#khanh : March 06, 2009
sub date_time_text{
    my ($dateTimeStr, $long, $lang) = @_;
    
    my $date = substr $dateTimeStr , 0 , 10 ; 
    my $time = substr $dateTimeStr, -8 ;
    my $date_format = date_text($date, $long, $lang);
    return $date_format . '/' . $time;

}

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

sub date_DHM_text{
    my ($dateTimeStr, $long, $lang) = @_;
    
    my $date = substr $dateTimeStr , 0 , 10 ; 
    my $time = substr $dateTimeStr, -8,5 ;
       $time  = mil2AmPmTime($time );
    my $date_format = date_text($date, $long, $lang);
    return $date_format . ' ' . $preposition->{$lang}->{'at'}. ' ' . $time;

}
sub mil2AmPmTime{
    my ($time)=@_;
    return $time if($time !~ m/[\d]{1,2}:[\d]{1,2}/g);
    my $amPm ="AM";
    my @hr=split(':',$time);
    if($hr[0]>=12){
        $amPm="PM";
        $hr[0] -=12 if($hr[0]>12);
    }
    return sprintf("%02d:%02d %s",$hr[0],$hr[1],$amPm);

}

1;
