aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src/Net-ICal-Libical/lib/Net/ICal/Libical')
-rw-r--r--libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Component.pm175
-rw-r--r--libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Duration.pm160
-rw-r--r--libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Period.pm359
-rw-r--r--libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Property.pm173
-rw-r--r--libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Time.pm468
5 files changed, 1335 insertions, 0 deletions
diff --git a/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Component.pm b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Component.pm
new file mode 100644
index 0000000000..c25297c111
--- /dev/null
+++ b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Component.pm
@@ -0,0 +1,175 @@
+#!/usr/bin/perl
+# -*- Mode: perl -*-
+#======================================================================
+# FILE: Component.pm
+# CREATOR: eric 1 Mar 01
+#
+# DESCRIPTION:
+#
+#
+# $Id$
+# $Locker$
+#
+# (C) COPYRIGHT 2000, Eric Busboom, eric@softwarestudio.org
+#
+# This package is free software and is provided "as is" without express
+# or implied warranty. It may be used, redistributed and/or modified
+# under the same terms as perl itself. ( Either the Artistic License or the
+# GPL. )
+#
+#
+#======================================================================
+
+
+
+package Net::ICal::Libical::Component;
+use Net::ICal::Libical;
+
+use strict;
+
+sub new{
+ my $class = shift;
+ my $ical_str = shift; # Ical data in string form
+ my $self = {};
+
+ $self->{'comp_p'} = Net::ICal::Libical::icalparser_parse_string($ical_str);
+
+ die "Can't parse string into component" if !$self->{'comp_p'};
+
+ bless $self, $class;
+}
+
+sub new_from_ref {
+ my $class = shift;
+ my $r = shift;
+ my $self = {};
+
+ $self->{'comp_p'} = $r;
+
+ bless $self, $class;
+}
+
+# Destroy must call icalcomponent_free() if icalcomponent_get_parent()
+# returns NULL
+sub DESTROY {
+ my $self = shift;
+
+ my $c = $self->{'comp_p'};
+
+ if($c && !Net::ICal::Libical::icalcomponent_get_parent($c)){
+ Net::ICal::Libical::icalcomponent_free($c);
+ }
+
+}
+
+# Return an array of all properties of the given type
+sub properties{
+
+ my $self = shift;
+ my $prop_name = shift;
+
+ my @props;
+
+ if(!$prop_name){
+ $prop_name = 'ANY';
+ }
+
+ # To loop over properties
+ # $comp_p = $self->{'comp_p'}
+ # $p = icallangbind_get_first_property($comp_p,$prop_name)
+ # $p = icallangbind_get_next_property($comp_p,$prop_name)
+
+ my $c = $self->{'comp_p'};
+ my $p;
+
+ for($p = Net::ICal::Libical::icallangbind_get_first_property($c,$prop_name);
+ $p;
+ $p = Net::ICal::Libical::icallangbind_get_next_property($c,$prop_name)){
+
+ my $d_string = Net::ICal::Libical::icallangbind_property_eval_string($p,"=>");
+ my %dict = %{eval($d_string)};
+
+ $dict{'ref'} = $p;
+
+ # Now, look at $dict{'value_type'} or $dict{'name'} to construct a
+ # derived class of Property. I'll do this later.
+
+ my $prop;
+
+ if($dict{'value_type'} eq 'DATE' or $dict{'value_type'} eq 'DATE-TIME'){
+ $prop = new Net::ICal::Libical::Time(\%dict);
+ } elsif($dict{'value_type'} eq 'DURATION' ) {
+ $prop = new Net::ICal::Libical::Duration(\%dict);
+ } else {
+ $prop = new Net::ICal::Libical::Property(\%dict);
+ }
+
+ push(@props,$prop);
+
+ }
+
+
+ return @props;
+
+}
+
+
+sub add_property {
+
+ # if there is a 'ref' key in the prop's dict, then it is owned by
+ # an icalcomponent, so dont add it again. But, you may check that
+ # it is owned by this component with:
+ # icalproperty_get_parent(p->{'ref'}') != $self->{'comp_p'}
+
+ # If there is no 'ref' key, then create one with $p->{'ref'} =
+ # icalproperty_new_from_string($p->as_ical_string)
+
+}
+
+sub remove_property {
+
+# If $p->{'ref'} is set, then remove the property with
+# icalcomponent_remove_property() }
+}
+
+# Return an array of all components of the given type
+sub components {
+
+ my $self = shift;
+ my $comp_name = shift;
+
+ my @comps;
+
+ if(!$comp_name){
+ $comp_name = 'ANY';
+ }
+
+ my $c = $self->{'comp_p'};
+ my $p;
+
+ for($p = Net::ICal::Libical::icallangbind_get_first_component($c,$comp_name);
+ $p;
+ $p = Net::ICal::Libical::icallangbind_get_next_component($c,$comp_name)){
+
+ push(@comps, Net::ICal::Libical::Component->new_from_ref($p));
+
+ }
+
+ return @comps;
+
+}
+
+
+sub add_component {}
+
+sub remove_component {}
+
+sub as_ical_string {
+ my $self = shift;
+
+ return Net::ICal::Libical::icalcomponent_as_ical_string($self->{'comp_p'})
+}
+
+
+
+1;
diff --git a/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Duration.pm b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Duration.pm
new file mode 100644
index 0000000000..13ec9c437e
--- /dev/null
+++ b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Duration.pm
@@ -0,0 +1,160 @@
+#=============================================================================
+#
+# This package is free software and is provided "as is" without express
+# or implied warranty. It may be used, redistributed and/or modified
+# under the same terms as perl itself. (Either the Artistic License or
+# the GPL.)
+#
+#=============================================================================
+
+=head1 NAME
+
+Net::ICal::Duration -- represent a length of time
+
+=head1 SYNOPSIS
+
+ use Net::ICal;
+ $d = Net::ICal::Duration->new("P3DT6H15M10S");
+ $d = Net::ICal::Duration->new(3600); # 1 hour in seconds
+
+=head1 DESCRIPTION
+
+I<Duration> Represents a length of time, such a 3 days, 30 seconds or
+7 weeks. You would use this for representing an abstract block of
+time; "I want to have a 1-hour meeting sometime." If you want a
+calendar- and timezone-specific block of time, see Net::ICal::Period.
+
+=cut
+
+#=============================================================================
+
+package Net::ICal::Libical::Duration;
+use Net::ICal::Libical::Property;
+use strict;
+use Carp;
+@Net::ICal::Libical::Duration::ISA = qw ( Net::ICal::Libical::Property );
+
+=head1 METHODS
+
+=head2 new
+
+Create a new I<Duration> from:
+
+=over 4
+
+=item * A string in RFC2445 duration format
+
+=item * An integer representing a number of seconds
+
+=cut
+
+sub new {
+ my $package = shift;
+ my $arg = shift;
+ my $self;
+
+ if (ref($arg) == 'HASH'){
+ # Construct from dictionary
+ $self = Net::ICal::Libical::Property::new($package,$arg);
+ my $val=Net::ICal::Libical::icalproperty_get_value_as_string($self->{'ref'});
+ $self->{'dur'} = Net::ICal::Libical::icaldurationtype_from_string($val);
+
+ return $self;
+
+ } elsif ($arg =~ /^[-+]?\d+$/){
+ # Seconds
+ $self = Net::ICal::Libical::Property::new($package,'DURATION');
+ $self->{'dur'} = Net::ICal::Libical::icaldurationtype_new_from_int($arg);
+ } elsif ($arg) {
+ # iCalendar string
+ $self = Net::ICal::Libical::Property::new($package,'DURATION');
+ $self->{'dur'} = Net::ICal::Libical::icaldurationtype_new_from_string($arg);
+ } else {
+ die;
+ }
+
+ $self->_update_value();
+ return $self;
+
+}
+
+sub _update_value {
+ my $self = shift;
+
+ die "Can't find internal icalduration reference" if !$self->{'dur'};
+
+ $self->value(Net::ICal::Libical::icaldurationtype_as_ical_string($self->{'dur'}));
+
+}
+=head2 clone()
+
+Return a new copy of the duration.
+
+=cut
+
+sub clone {
+ die "Not Implemented";
+
+}
+
+
+=head2 is_valid()
+
+Determine if this is a valid duration (given criteria TBD).
+
+=cut
+
+sub is_valid {
+
+ die "Not Implemented;"
+
+}
+
+=head2 seconds()
+
+Set or Get the length of the duration as seconds.
+
+=cut
+
+sub seconds {
+ my $self = shift;
+ my $seconds = shift;
+
+ if($seconds){
+ $self->{'dur'} =
+ Net::ICal::Libical::icaldurationtype_from_int($seconds);
+ $self->_update_value();
+ }
+
+ return Net::ICal::Libical::icaldurationtype_as_int($self->{'dur'});
+
+}
+
+=head2 add($duration)
+
+Return a new duration that is the sum of this and $duration. Does not
+modify this object.
+
+=cut
+
+sub add {
+ my ($self, $duration) = @_;
+
+ return new Duration($self->seconds() + $duration->seconds());
+}
+
+
+=head2 subtract($duration)
+
+Return a new duration that is the difference between this and
+$duration. Does not modify this object.
+
+=cut
+
+sub subtract {
+ my ($self, $duration) = @_;
+
+ return new Duration($self->seconds() - $duration->seconds());
+}
+
+1;
diff --git a/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Period.pm b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Period.pm
new file mode 100644
index 0000000000..ecf29f3370
--- /dev/null
+++ b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Period.pm
@@ -0,0 +1,359 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl -*-
+#======================================================================
+#
+# This package is free software and is provided "as is" without express
+# or implied warranty. It may be used, redistributed and/or modified
+# under the same terms as perl itself. ( Either the Artistic License or the
+# GPL. )
+#
+# $Id$
+#
+# (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+#
+# $Log
+#======================================================================
+
+
+=pod
+=head1 NAME
+
+Net::ICal::Period -- represent a period of time
+
+=head1 SYNOPSIS
+
+ use Net::ICal;
+ $p = new Net::ICal::Period("19970101T120000","19970101T123000");
+ $p = new Net::ICal::Period("19970101T120000","PT3W2D40S");
+ $p = new Net::ICal::Period(time(),3600);
+ $p = new Net::ICal::Period(
+ new Net::ICal::Time("19970101T120000",
+ "America/Los_Angeles"),
+ new Net::ICal::Duration("2h"));
+
+=head1 DESCRIPTION
+
+Use this to make an object representing a block of time on a
+real schedule. You can either say, "This event starts at 12
+and ends at 2" or "This event starts at 12 and lasts 2 hours."
+
+These two ways of specifying events can be treated differently
+in schedules. If you say, "The meeting is from 12 to 2, but I
+have to leave at 2," you are implying that the start date and
+end date are fixed. If you say, "I have a 2-hour drive to
+Chicago, and I need to leave at 4," you are saying that it will
+take 2 hours no matter when you leave, and that moving the start
+time will slide the end time correspondingly.
+
+=head1 BASIC METHODS
+
+=cut
+
+
+#=========================================================================
+
+package Net::ICal::Period;
+use strict;
+use Net::ICal::Time;
+use Net::ICal::Duration;
+
+use UNIVERSAL qw(isa);
+
+#-------------------------------------------------------------------------
+
+=pod
+=head2 new($time, $time|$duration)
+
+Creates a new period object given to parameters: The first must be a
+I<Time> object or valid argument to Net::ICal::Time::new.
+
+The second can be either:
+
+=pod
+
+=over 4
+
+=item * a I<Time> object
+
+=item * a valid argument to Net::ICal::Time::new.
+
+=item * a I<Duration> object
+
+=item * a valid argument to Net::ICal::Duration::new.
+
+=back
+
+Either give a start time and an end time, or a start time and a duration.
+
+=cut
+
+sub new{
+ my $package = shift;
+ my $arg1 = shift;
+ my $arg2 = shift;
+ my $self = {};
+
+ # Is the string in RFC2445 Format?
+ if(!$arg2 and $arg1 =~ /\//){
+ my $tmp = $arg1;
+ ($arg1,$arg2) = split(/\//,$tmp);
+ }
+
+
+ if( ref($arg1) eq 'Net::ICal::Time'){
+ $self->{START} = $arg1->clone();
+ } else {
+ $self->{START} = new Net::ICal::Time($arg1);
+ }
+
+
+ if(isa($arg2,'Net::ICal::Time')){
+ $self->{END} = $arg2->clone();
+ } elsif (isa($arg2,'Net::ICal::Duration')) {
+ $self->{DURATION} = $arg2->clone();
+ } elsif ($arg2 =~ /^P/) {
+ $self->{DURATION} = new Net::ICal::Duration($arg2);
+ } else {
+ # Hope that it is a time string
+ $self->{END} = new Net::ICal::Time($arg2);
+ }
+
+ return bless($self,$package);
+}
+
+#--------------------------------------------------------------------------
+=pod
+=head2 clone()
+
+Create a copy of this component
+
+=cut
+# XXX implement this
+sub clone {
+ return "Not implemented";
+}
+
+#----------------------------------------------------------------------------
+=pod
+=head2 is_valid()
+
+Return true if:
+ There is an end time and:
+ Both start and end times have no timezone ( Floating time) or
+ Both start and end time have (possibly different) timezones or
+ Both start and end times are in UTC and
+ The end time is after the start time.
+
+ There is a duration and the duration is positive
+
+=cut
+
+# XXX implement this
+
+sub is_valid {
+ return "Not implemented";
+}
+
+#---------------------------------------------------------------------------
+=pod
+=head2 start([$time])
+
+Accessor for the start time of the event as a I<Time> object.
+Can also take a valid time string or an integer (number of
+seconds since the epoch) as a parameter. If a second parameter
+is given, it'll set this Duration's start time.
+
+=cut
+
+sub start{
+ my $self = shift;
+ my $t = shift;
+
+ if($t){
+ if(isa($t,'Net::ICal::Time')){
+ $self->{START} = $t->clone();
+ } else {
+ $self->{START} = new Net::ICal::Time($t);
+ }
+ }
+
+ return $self->{START};
+}
+
+#-----------------------------------------------------------------
+=pod
+=head2 end([$time])
+
+Accessor for the end time. Takes a I<Time> object, a valid time string,
+or an integer and returns a time object. This routine is coupled to
+the I<duration> accessor. See I<duration> below for more imformation.
+
+=cut
+
+sub end{
+
+ my $self = shift;
+ my $t = shift;
+ my $end;
+
+ if($t){
+ if(isa($t,'Net::ICal::Time')){
+ $end = $t->clone();
+ } else {
+ $end = new Net::ICal::Time($t);
+ }
+
+ # If duration exists, use the time to compute a new duration
+ if ($self->{DURATION}){
+ $self->{DURATION} = $end->subtract($self->{START});
+ } else {
+ $self->{END} = $end;
+ }
+ }
+
+ # Return end time, possibly computing it from DURATION
+ if($self->{DURATION}){
+ return $self->{START}->add($self->{DURATION});
+ } else {
+ return $self->{END};
+ }
+
+}
+
+#----------------------------------------------------------------------
+=pod
+=head2 duration([$duration])
+
+Accessor for the duration of the event. Takes a I<duration> object and
+returns a I<Duration> object.
+
+Since the end time and the duration both specify the end time, the
+object will store one and access to the other will be computed. So,
+
+if you create:
+
+ $p = new Net::ICal::Period("19970101T120000","19970101T123000")
+
+And then execute:
+
+ $p->duration(45*60);
+
+The period object will adjust the end time to be 45 minutes after
+the start time. It will not replace the end time with a
+duration. This is required so that a CUA can take an incoming
+component from a server, modify it, and send it back out in the same
+basic form.
+
+=cut
+
+sub duration{
+ my $self = shift;
+ my $d = shift;
+ my $dur;
+
+ if($d){
+ if(isa($d,'Net::ICal::Duration')){
+ $dur = $d->clone();
+ } else {
+ $dur = new Net::ICal::Duration($d);
+ }
+
+ # If end exists, use the duration to compute a new end
+ # otherwise, set the duration.
+ if ($self->{END}){
+ $self->{END} = $self->{START}->add($dur);
+ } else {
+ $self->{DURATION} = $dur;
+ }
+ }
+
+ # Return duration, possibly computing it from END
+ if($self->{END}){
+ return $self->{END}->subtract($self->{START});
+ } else {
+ return $self->{DURATION};
+ }
+
+}
+
+#------------------------------------------------------------------------
+=pod
+
+=head2 as_ical()
+
+Return a string that holds the RFC2445 text form of this duration
+
+=cut
+sub as_ical {
+ my $self = shift;
+ my $out;
+
+ $out = $self->{START}->as_ical() ."/";
+
+ if($self->{DURATION}){
+ $out .= $self->{DURATION}->as_ical()
+ } else {
+ $out .= $self->{END}->as_ical()
+ }
+
+ return $out;
+
+}
+
+
+#------------------------------------------------------------------------
+=pod
+
+=head2 test()
+
+A set of developers' tests to make sure the module's working properly.
+
+=cut
+
+# Run this with a one-liner:
+# perl -e "use lib('/home/srl/dev/rk/reefknot/base/'); use Net::ICal::Period; Net::ICal::Period::test();"
+# adjusted for your environment.
+sub test {
+
+ print("--------- Test Net::ICal::Period --------------\n");
+
+
+ my $p = new Net::ICal::Period("19970101T180000Z/19970102T070000Z");
+ print $p->as_ical()."\n";
+ die if $p->as_ical() ne "19970101T180000Z/19970102T070000Z";
+
+ $p = new Net::ICal::Period("19970101T180000Z/PT5H30M");
+ print $p->as_ical()."\n";
+ die if $p->as_ical() ne "19970101T180000Z/PT5H30M";
+
+ $p->duration("PT5H30M10S");
+ print $p->as_ical()."\n";
+ die if $p->as_ical() ne "19970101T180000Z/PT5H30M10S" ;
+
+ $p->duration(new Net::ICal::Duration("P10DT30M5S"));
+ print $p->as_ical()."\n";
+ die if $p->as_ical() ne "19970101T180000Z/P10DT30M5S" ;
+
+ $p->end("19970101T183000Z");
+ print $p->as_ical()."\n";
+ die if $p->as_ical() ne "19970101T180000Z/PT30M" ;
+
+ $p = new Net::ICal::Period("19970101T180000Z/19970102T070000Z");
+
+ $p->end("19970101T183000Z");
+ print $p->as_ical()."\n";
+ die if $p->as_ical() ne "19970101T180000Z/19970101T183000Z" ;
+
+ $p->duration("P1DT1H10M");
+ print $p->as_ical()."\n";
+ die if $p->as_ical() ne "19970101T180000Z/19970102T191000Z" ;
+
+
+
+}
+
+1;
+
+
+__END__
+
diff --git a/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Property.pm b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Property.pm
new file mode 100644
index 0000000000..0aef347c43
--- /dev/null
+++ b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Property.pm
@@ -0,0 +1,173 @@
+#!/usr/bin/perl
+# -*- Mode: perl -*-
+#======================================================================
+# FILE: Property.pm
+# CREATOR: eric 1 Mar 01
+#
+# DESCRIPTION:
+#
+#
+# $Id$
+# $Locker$
+#
+# (C) COPYRIGHT 2000, Eric Busboom, eric@softwarestudio.org
+#
+# This package is free software and is provided "as is" without express
+# or implied warranty. It may be used, redistributed and/or modified
+# under the same terms as perl itself. ( Either the Artistic License or the
+# GPL. )
+#
+#
+#======================================================================
+
+use Net::ICal::Libical::Property;
+
+
+package Net::ICal::Libical::Property;
+use strict;
+
+
+sub new {
+
+ my $class = shift;
+ my $arg = shift;
+ my $self = {};
+ my $kind;
+
+ if(ref($arg) == 'HASH'){
+
+ $self->{'ref'} = $arg->{'ref'};
+
+ } else {
+ $kind = Net::ICal::Libical::icalproperty_string_to_kind($arg);
+ $self->{'ref'} = Net::ICal::Libical::icalproperty_new($kind);
+ }
+
+ die "Did not get icalproperty ref in Net::ICal::Libical::Property::new " if !$self->{'ref'};
+
+ bless $self, $class;
+}
+
+
+sub DESTROY {
+ my $self = shift;
+
+ my $r = $self->{'ref'};
+
+ if($r && !Net::ICal::Libical::icalproperty_get_parent($r)){
+ Net::ICal::Libical::icalproperty_free($self->{'ref'});
+ }
+}
+
+sub name {
+ my $self = shift;
+ my $str;
+
+ die if !$self->{'ref'};
+
+ $str = Net::ICal::Libical::icalproperty_as_ical_string($self->{'ref'});
+
+ $str =~ /^([A-Z\-]+)\n/;
+
+ return $1;
+
+}
+
+#Get/Set the internal reference to the libical icalproperty """
+sub prop_ref {
+ my $self = shift;
+ my $p_r = shift;
+
+ if($p_r){
+ $self->{'ref'} = $p_r;
+ }
+
+ return $self->{'ref'};
+
+}
+
+
+#Get/set the RFC2445 representation of the value. Dict value 'value'
+sub value {
+ my $self = shift;
+ my $v = shift;
+ my $kind = shift;
+
+ my $vt;
+ if($v){
+
+ if ($kind) {
+ $self->{'VALUE'} = $kind;
+ $vt = $kind;
+ }
+ elsif ($self->{'VALUE'}) {
+ $vt = $self->{'VALUE'};
+ }
+ else {
+ $vt = 'NO'; # Use the kind of the existing value
+ }
+
+
+ Net::ICal::Libical::icalproperty_set_value_from_string($self->{'ref'},$v,$vt);
+
+ }
+
+ return Net::ICal::Libical::icalproperty_get_value_as_string($self->{'ref'});
+
+}
+
+
+# Get a named parameter
+sub get_parameter{
+ my $self = shift;
+ my $key = shift;
+
+ die "get_parameter: missing parameter name" if !$key;
+
+ $key = uc($key);
+ my $ref = $self->{'ref'};
+
+ my $str = Net::ICal::Libical::icalproperty_get_parameter_as_string($ref,$key);
+
+ if($str eq 'NULL') {
+ return undef;
+ }
+
+ return $str
+
+}
+
+
+# Set the value of the named parameter
+sub set_parameter{
+ my $self = shift;
+ my $key = shift;
+ my $value = shift;
+
+ die "set_parameter: missing parameter name" if !$key;
+ die "set_parameter: missing parameter value" if !$value;
+
+ $key = uc($key);
+ my $ref = $self->{'ref'};
+
+ my $str = Net::ICal::Libical::icalproperty_set_parameter_from_string($ref,$key,$value);
+
+
+ return $self->get_parameter($self);
+
+}
+
+
+sub as_ical_string {
+ my $self = shift;
+ my $str = Net::ICal::Libical::icalproperty_as_ical_string($self->{'ref'});
+
+ $str =~ s/\r//g;
+ $str =~ s/\n\s?//g;
+
+ return $str;
+}
+
+
+
+1;
diff --git a/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Time.pm b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Time.pm
new file mode 100644
index 0000000000..76969ac60d
--- /dev/null
+++ b/libical/src/Net-ICal-Libical/lib/Net/ICal/Libical/Time.pm
@@ -0,0 +1,468 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl -*-
+#======================================================================
+#
+# This package is free software and is provided "as is" without express
+# or implied warranty. It may be used, redistributed and/or modified
+# under the same terms as perl itself. ( Either the Artistic License or the
+# GPL. )
+#
+#
+#======================================================================
+
+
+
+=pod
+
+=head1 NAME
+
+Net::ICal::Time -- represent a time and date
+
+=head1 SYNOPSIS
+
+ $t = new Net::ICal::Time("19970101T120000Z");
+ $t = new Net::ICal::Time("19970101T120000","America/Los_Angeles");
+ $t = new Net::ICal::Time(time(),"America/Los_Angeles");
+
+ $t2 = $t->add(Net::Ical::Duration("1D"));
+
+ $duration = $t->subtract(Net::ICal::Time("19970101T110000Z"))
+
+ # Add 5 minutes
+ $t->min($t->min()+5);
+
+ # Add 5 minutes
+ $t->sec($t->sec()+300);
+
+ # Compare
+ if($t->compare($t2) > 0) {}
+
+=head1 DESCRIPTION
+
+I<Time> represents a time, but can also hold the time zone for the
+time and indicate if the time should be treated as a date. The time
+can be constructed from a variey of formats.
+
+=head1 METHODS
+
+=cut
+
+package Net::ICal::Libical::Time;
+use Net::ICal::Libical::Duration;
+use Net::ICal::Libical::Property;
+use Time::Local;
+use POSIX;
+use Carp qw(confess cluck);
+use strict;
+use UNIVERSAL qw(isa);
+
+@Net::ICal::Libical::Time::ISA = qw(Net::ICal::Libical::Property);
+
+=pod
+
+=head2 new
+
+Creates a new time object given one of:
+
+=over 4
+
+=item * ISO format string
+
+=item * Some other format string, maybe whatever a Date module understands
+
+=item * Integer representing seconds past the POSIX epoch
+
+=back
+
+The optional second argument is the timezone in Olsen place name format,
+which looks like "America/Los_Angeles"; it can be used to get the standard
+offset from UTC, the dates the location goes to and from Daylight Savings
+Time, and the magnitude of the Daylight Savings time offset.
+
+=cut
+
+sub new{
+ my $package = shift;
+ my $arg = shift;
+
+ my $self;
+
+ if (ref($arg) == 'HASH'){
+ # Construct from dictionary
+ $self = Net::ICal::Libical::Property::new($package,$arg);
+ my $val=Net::ICal::Libical::icalproperty_get_value_as_string($self->{'ref'});
+ $self->{'tt'} = Net::ICal::Libical::icaltime_from_string($val);
+
+ return $self;
+
+ } else {
+
+ if ($#_ = 1){
+ # iCalendar string
+ $self = Net::ICal::Libical::Property::new($package,'DTSTART');
+ $self->{'tt'} = Net::ICal::Libical::icaltime_new_from_string($arg);
+ } else {
+ # Broken out time
+ die;
+ }
+
+ $self->_update_value();
+ return $self;
+ }
+
+}
+
+
+sub _update_value {
+ my $self = shift;
+
+ if(!$self->{'tt'}){
+ die "Can't find reference to icaltimetype";
+ }
+
+ $self->value(Net::ICal::Libical::icaltime_as_ical_string($self->{'tt'}));
+
+}
+
+=pod
+
+=head2 clone()
+
+Create a new copy of this time.
+
+=cut
+
+# clone a Time object.
+sub clone {
+ my $self = shift;
+
+ bless( {%$self},ref($self));
+
+ $self->{'ref'} = Net::ICal::Libical::icalproperty_new_clone($self->{'ref'});
+
+}
+
+
+
+=pod
+
+=head2 is_valid()
+
+TBD
+
+=cut
+
+sub is_valid{
+ my $self = shift;
+
+ return Net::ICal::Libical::icaltime_is_null_time($self->{'tt'});
+
+}
+
+
+
+=pod
+
+=head2 is_date([true|false])
+
+Accessor to the is_date flag. If true, the flag indicates that the
+hour, minute and second fields are set to zero and not used in
+comparisons.
+
+=cut
+
+
+sub is_date {
+ my $self = shift;
+ if(@_){
+
+ # Convert to true or false
+ Net::ICal::Libical::icaltimetype_is_date_set($self->{'tt'},
+ !(!($_[0])));
+ }
+
+ return Net::ICal::Libical::icaltimetype_is_date_get($self->{'tt'});
+
+}
+
+
+=pod
+
+=head2 is_utc([true|false])
+
+Is_utc indicates if the time should be interpreted in the UTC timezone.
+
+=cut
+
+sub is_utc {
+ my $self = shift;
+ if(@_){
+
+ # Convert to true or false
+ Net::ICal::Libical::icaltimetype_is_utc_set($self->{'tt'},
+ !(!($_[0])));
+ }
+
+ return Net::ICal::Libical::icaltimetype_is_utc_get($self->{'tt'});
+
+}
+=pod
+
+=head2 timezone
+
+Accessor to the timezone. Takes & Returns an Olsen place name
+("America/Los_Angeles", etc. ) , an Abbreviation, 'UTC', or 'float' if
+no zone was specified.
+
+=cut
+
+sub timezone {
+ my $self = shift;
+ my $tz = shift;
+
+ if($tz){
+ $self->set_parameter('TZID',$tz);
+ }
+
+ return $self->get_parameter('TZID');
+
+}
+
+
+
+=pod
+
+=head2 normalize()
+
+Adjust any out-of range values so that they are in-range. For
+instance, 12:65:00 would become 13:05:00.
+
+=cut
+
+sub normalize{
+ my $self = shift;
+
+ $self->{'tt'} = Net::ICal::Libical::icaltime_normalize($self->{'tt'});
+ $self->value(Net::ICal::Libical::icaltime_as_ical_string($self->{'tt'}));
+
+}
+
+
+=pod
+
+=head2 hour([$hour])
+
+Accessor to the hour. Out of range values are normalized.
+
+=cut
+
+=pod
+=head2 minute([$min])
+
+Accessor to the minute. Out of range values are normalized.
+
+=cut
+
+=pod
+=head2 second([$dsecond])
+
+Accessor to the second. Out of range values are normalized. For
+instance, setting the second to -1 will decrement the minute and set
+the second to 59, while setting the second to 3600 will increment the
+hour.
+
+=cut
+
+=pod
+
+=head2 year([$year])
+
+Accessor to the year. Out of range values are normalized.
+
+=cut
+
+=pod
+
+=head2 month([$month])
+
+Accessor to the month. Out of range values are normalized.
+
+=cut
+
+
+=pod
+
+=head2 day([$day])
+
+Accessor to the month day. Out of range values are normalized.
+
+=cut
+
+sub _do_accessor {
+no strict;
+ my $self = shift;
+ my $type = shift;
+ my $value = shift;
+
+ $type = lc($type);
+
+ if($value){
+ my $set = "Net::ICal::Libical::icaltimetype_${type}_set";
+
+ &$set($self->{'tt'},$value);
+ $self->normalize();
+ $self->_update_value();
+
+ }
+
+ my $get = "Net::ICal::Libical::icaltimetype_${type}_get";
+
+ return &$get($self->{'tt'});
+}
+
+
+sub second {my $s = shift; my $v = shift; return $s->_do_accessor('SECOND',$v);}
+sub minute {my $s = shift; my $v = shift;return $s->_do_accessor('MINUTE',$v);}
+sub hour {my $s = shift; my $v = shift; return $s->_do_accessor('HOUR',$v);}
+sub day {my $s = shift; my $v = shift; return $s->_do_accessor('DAY',$v);}
+sub month {my $s = shift; my $v = shift; return $s->_do_accessor('MONTH',$v);}
+sub year {my $s = shift; my $v = shift; return $s->_do_accessor('YEAR',$v);}
+
+
+=pod
+
+=head2 add($duration)
+
+Takes a I<Duration> and returns a I<Time> that is the sum of the time
+and the duration. Does not modify this time.
+
+=cut
+sub add {
+ my $self = shift;
+ my $dur = shift;
+
+ cluck "Net::ICal::Time::add argument 1 requires a Net::ICal::Duration" if !isa($dur,'Net::ICal::Duration');
+
+ my $c = $self->clone();
+
+ $c->second($dur->as_int());
+
+ $c->normalize();
+
+ return $c;
+
+}
+
+=pod
+
+=head2 subtract($time)
+
+Subtract out a time of type I<Time> and return a I<Duration>. Does not
+modify this time.
+
+=cut
+sub subtract {
+ my $self = shift;
+ my $t = shift;
+
+ cluck "Net::ICal::Time::subtract argrument 1 requires a Net::ICal::Time" if !isa($t,'Net::ICal::Time');
+
+ my $tint1 = $self->as_int();
+ my $tint2 = $t->as_int();
+
+ return new Net::ICal::Duration($tint1 - $tint2);
+
+}
+
+=pod
+
+=head2 move_to_zone($zone);
+
+Change the time to what it would be in the named timezone.
+The zone can be an Olsen placename or "UTC".
+
+=cut
+
+# XXX this needs implementing.
+sub move_to_zone {
+ confess "Not Implemented\n";
+}
+
+
+
+=pod
+
+=head2 as_int()
+
+Convert the time to an integer that represents seconds past the POSIX
+epoch
+
+=cut
+sub as_int {
+ my $self = shift;
+
+ return Net::ICal::Libical::icaltime_as_timet($self->{'tt'});
+}
+
+=pod
+
+=head2 as_localtime()
+
+Convert to list format, as per localtime()
+
+=cut
+sub as_localtime {
+ my $self = shift;
+
+ return localtime($self->as_int());
+
+}
+
+=pod
+
+=head2 as_gmtime()
+
+Convert to list format, as per gmtime()
+
+=cut
+sub as_gmtime {
+ my $self = shift;
+
+ return gmtime($self->as_int());
+
+}
+
+=pod
+
+=head2 compare($time)
+
+Compare a time to this one and return -1 if the argument is earlier
+than this one, 1 if it is later, and 0 if it is the same. The routine
+does the comparision after converting the time to UTC. It converts
+floating times using the system notion of the timezone.
+
+=cut
+sub compare {
+ my $self = shift;
+ my $a = $self->as_int();
+
+ my $arg = shift;
+
+ if(!isa($arg,'Net::ICal::Time')){
+ $arg = new Net::ICal::Time($arg);
+ }
+
+ my $b = $arg->as_int();
+
+ if($a < $b){
+ return -1;
+ } elsif ($a > $b) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+}
+
+1;
+