1// Copyright (C) 2019 Storj Labs, Inc.
2// See LICENSE for copying information.
3
4/**
5 * Options is a set of options used for VDatePicker.vue.
6 */
7export class Options {
8    public constructor(
9        public mondayFirstWeek: string[] = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
10        public sundayFirstWeek: string[] = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
11        public month: string[] = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
12        public color = {
13            checked: '#2683FF',
14            header: '#2683FF',
15            headerText: '#444C63',
16        },
17        public inputStyle = {
18            'visibility': 'hidden',
19            'width': '0',
20        },
21        public overlayOpacity: number = 0.5,
22        public dismissible: boolean = true,
23    ) {}
24}
25
26/**
27 * DayItem is used to store information about day cell in calendar.
28 */
29export class DayItem {
30    public constructor(
31        public value: number,
32        public inMonth: boolean,
33        public unavailable: boolean,
34        public checked: boolean,
35        public moment: Date,
36        public action: DayAction = DayAction.Default,
37        public today: boolean = false,
38    ) {}
39
40    public equals(dateToCompare: Date): boolean {
41        const isDayEqual = this.moment.getDate() === dateToCompare.getDate();
42        const isMonthEqual = this.moment.getMonth() === dateToCompare.getMonth();
43        const isYearEqual = this.moment.getFullYear() === dateToCompare.getFullYear();
44
45        return isDayEqual && isMonthEqual && isYearEqual;
46    }
47}
48
49/**
50 * DayAction is enum represents month change direction on day click.
51 */
52export enum DayAction {
53    Next,
54    Previous,
55    Default,
56}
57
58/**
59 * DateStamp is cozy representation of Date for view.
60 */
61export class DateStamp {
62    public constructor(
63        public year: number,
64        public month: number,
65        public day: number,
66    ) {}
67
68    public fromDate(date: Date): void {
69        this.year = date.getFullYear();
70        this.month = date.getMonth();
71        this.day = date.getDate();
72    }
73}
74
75/**
76 * DisplayedType is enum represents view type to show in calendar to check.
77 */
78export enum DisplayedType {
79    Day,
80    Month,
81    Year,
82}
83
84/**
85 * DateGenerator is utility class used for generating DayItem and year lists for calendar.
86 */
87export class DateGenerator {
88    private current: DateStamp;
89    private isSundayFirst: boolean;
90    private now = new Date();
91
92    public populateDays(current: DateStamp, isSundayFirst: boolean): DayItem[] {
93        this.current = current;
94        this.isSundayFirst = isSundayFirst;
95
96        const days: DayItem[] = [];
97
98        this.populateSelectedMonthDays(days);
99        this.populatePreviousMonthDays(days);
100        this.populateNextMonthDays(days);
101        this.markToday(days);
102
103        return days;
104    }
105
106    public populateYears(): number[] {
107        const year = new Date().getFullYear();
108        const years: number[] = [];
109        for (let i = year - 99; i <= year; i++) {
110            years.unshift(i);
111        }
112
113        return years;
114    }
115
116    private populateSelectedMonthDays(days: DayItem[]): void {
117        const daysInSelectedMonth = new Date(this.current.year, this.current.month + 1, 0).getDate();
118        const currentMonth = this.now.getMonth();
119
120        for (let i = 1; i <= daysInSelectedMonth; i++) {
121            const moment = new Date(this.current.year, this.current.month, this.current.day, 23, 59);
122            moment.setDate(i);
123
124            days.push(
125                new DayItem(
126                    i,
127                    this.current.month !== currentMonth || (this.current.month === currentMonth && i <= this.now.getDate()),
128                    false,
129                    false,
130                    moment,
131                ),
132            );
133        }
134    }
135
136    private populatePreviousMonthDays(days: DayItem[]): void {
137        const previousMonth = new Date(this.current.year, this.current.month, this.current.day);
138        previousMonth.setMonth(previousMonth.getMonth() - 1);
139
140        const firstDate = new Date(this.current.year, this.current.month, this.current.day);
141        firstDate.setDate(1);
142        let firstDay = firstDate.getDay();
143
144        if (firstDay === 0) firstDay = 7;
145        const daysInPreviousMonth = new Date(previousMonth.getFullYear(), previousMonth.getMonth() + 1, 0).getDate();
146
147        for (let i = 0; i < firstDay - (this.isSundayFirst ? 0 : 1); i++) {
148            const moment = new Date(this.current.year, this.current.month, this.current.day, 23, 59);
149            moment.setDate(1);
150            moment.setMonth(moment.getMonth() - 1);
151            moment.setDate(new Date(moment.getFullYear(), moment.getMonth() + 1, 0).getDate() - i);
152
153            days.unshift(
154                new DayItem(
155                    daysInPreviousMonth - i,
156                    false,
157                    false,
158                    false,
159                    moment,
160                    DayAction.Previous,
161                ),
162            );
163        }
164    }
165
166    private populateNextMonthDays(days: DayItem[]): void {
167        const passiveDaysAtFinal = 42 - days.length;
168
169        for (let i = 1; i <= passiveDaysAtFinal; i++) {
170            const moment = new Date(this.current.year, this.current.month, this.current.day, 23, 59);
171            moment.setMonth(moment.getMonth() + 1);
172            moment.setDate(i);
173
174            days.push(
175                new DayItem(
176                    i,
177                    false,
178                    false,
179                    false,
180                    moment,
181                    DayAction.Next,
182                ),
183            );
184        }
185    }
186
187    private markToday(days: DayItem[]): void {
188        const daysCount = days.length;
189
190        for (let i = 0; i < daysCount; i++) {
191            const day: DayItem = days[i];
192
193            if (day.equals(this.now)) {
194                day.today = true;
195                break;
196            }
197        }
198    }
199}
200
201/**
202 * DateFormat is utils class for date formatting to string.
203 */
204export class DateFormat {
205
206    /**
207     * getUSDate transforms date into US date format string.
208     * @param date - Date to format
209     * @param separator - symbol for joining date string
210     * @returns formatted date string
211     */
212    public static getUTCDate(date: Date, separator: string): string {
213        const month = date.getUTCMonth() + 1;
214        const day = date.getUTCDate();
215        const year = date.getUTCFullYear();
216
217        return [month, day, year].join(separator);
218    }
219}
220