1<?php
2/**
3 * This file is part of the FreeDSx ASN1 package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace FreeDSx\Asn1\Type;
12
13use DateTime;
14use DateTimeInterface;
15use FreeDSx\Asn1\Exception\InvalidArgumentException;
16
17/**
18 * Generalized / UTC time type.
19 *
20 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
21 */
22class AbstractTimeType extends AbstractType
23{
24    /**
25     * Format the date time to the minutes.
26     */
27    public const FORMAT_HOURS = 'hours';
28
29    /**
30     * Format the date time to the minutes.
31     */
32    public const FORMAT_MINUTES = 'minutes';
33
34    /**
35     * Format the date time to the seconds.
36     */
37    public const FORMAT_SECONDS = 'seconds';
38
39    /**
40     * Format the datetime to the fractional seconds if possible (empty fractionals not allowed), otherwise  to the seconds.
41     */
42    public const FORMAT_FRACTIONS = 'fractions';
43
44    /**
45     * Use local time (ie. no ending timezone specification)
46     */
47    public const TZ_LOCAL = 'local';
48
49    /**
50     * Use a UTC timezone (ie. end with a Z)
51     */
52    public const TZ_UTC = 'utc';
53
54    /**
55     * Use a timezone differential (ie. -0500)
56     */
57    public const TZ_DIFF = 'diff';
58
59    /**
60     * @var string[] Valid datetime formats.
61     */
62    protected $validDateFormats = [];
63
64    /**
65     * @var string[] Valid timezone formats
66     */
67    protected $validTzFormats = [];
68
69    /**
70     * @var string
71     */
72    protected $tzFormat;
73
74    /**
75     * @var string
76     */
77    protected $dateFormat;
78
79    /**
80     * @var DateTimeInterface|null
81     */
82    protected $value;
83
84    /**
85     * @param DateTimeInterface|null $dateTime
86     * @param string $dateFormat Represents the furthest datetime element to represent in the datetime object.
87     * @param string $tzFormat Represents the format of the timezone.
88     */
89    public function __construct(?DateTimeInterface $dateTime, string $dateFormat, string $tzFormat)
90    {
91        $this->setDateTimeFormat($dateFormat);
92        $this->setTimeZoneFormat($tzFormat);
93        parent::__construct($dateTime ?? new DateTime());
94    }
95
96    /**
97     * @param DateTimeInterface $dateTime
98     * @return $this
99     */
100    public function setValue(DateTimeInterface $dateTime)
101    {
102        $this->value = $dateTime;
103
104        return $this;
105    }
106
107    /**
108     * @return DateTimeInterface
109     */
110    public function getValue(): DateTimeInterface
111    {
112        return $this->value;
113    }
114
115    /**
116     * @return string
117     */
118    public function getTimeZoneFormat(): string
119    {
120        return $this->tzFormat;
121    }
122
123    /**
124     * @param string $tzFormat
125     * @return $this
126     */
127    public function setTimeZoneFormat(string $tzFormat)
128    {
129        if (!in_array($tzFormat, $this->validTzFormats)) {
130            throw new InvalidArgumentException(sprintf(
131                'The timezone format %s is not valid. It must be one of: %s',
132                $tzFormat,
133                implode(', ', $this->validTzFormats)
134            ));
135        }
136        $this->tzFormat = $tzFormat;
137
138        return $this;
139    }
140
141    /**
142     * @return string
143     */
144    public function getDateTimeFormat(): string
145    {
146        return $this->dateFormat;
147    }
148
149    /**
150     * @param string $dateFormat
151     * @return $this
152     */
153    public function setDateTimeFormat(string $dateFormat)
154    {
155        if (!in_array($dateFormat, $this->validDateFormats)) {
156            throw new InvalidArgumentException(sprintf(
157                'The datetime format %s is not valid. It must be one of: %s',
158                $dateFormat,
159                implode(', ', $this->validDateFormats)
160            ));
161        }
162        $this->dateFormat = $dateFormat;
163
164        return $this;
165    }
166
167    /**
168     * @param string|int $tagNumber
169     * @param int $class
170     * @param bool $isConstructed
171     * @param DateTimeInterface|null $dateTime
172     * @param string $dateFormat
173     * @param string $tzFormat
174     * @return AbstractTimeType
175     */
176    public static function withTag($tagNumber, int $class, bool $isConstructed, ?DateTimeInterface $dateTime, string $dateFormat, string $tzFormat)
177    {
178        $type = new static($dateTime, $dateFormat, $tzFormat);
179        $type->tagNumber = $tagNumber;
180        $type->taggingClass = $class;
181        $type->isConstructed = $isConstructed;
182
183        return $type;
184    }
185}
186