% weekschedule.cls - A LaTeX class for creating weekly schedule calendars
% Usage:
%   \documentclass{weekschedule}
%   \scheduletitle{Weekly Schedule - Spring 2026}
%   \scheduleauthor{Dr. Smith}
%   \timefrom{8:00}
%   \timeto{18:00}
%   \twelvehourtime  % or \twentyfourhourtime
%   \eventclass{Courses}{173,216,230}  % RGB values
%   \event{Courses}{MATH 101}{Monday,Wednesday,Friday}{9:00}{10:00}
%   \begin{document}
%   \printschedule
%   \end{document}

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{weekschedule}[2026/01/11 Weekly Schedule Class]

% Load base class
\LoadClass[landscape,11pt]{article}

% Required packages
\RequirePackage[margin=0.5in]{geometry}
\RequirePackage{tikz}
\RequirePackage{xcolor}
\RequirePackage{pgfmath}

\pagestyle{empty}

% ============================================
% Configuration variables with defaults
% ============================================
\newcommand{\@scheduletitle}{Weekly Schedule}
\newcommand{\@scheduleauthor}{}
\newcommand{\@starthour}{8}
\newcommand{\@endhour}{18}
\newif\if@usetwentyfourhour
\@usetwentyfourhourfalse

% Layout parameters
\newcommand{\@daywidth}{4.5}
\newcommand{\@hourheight}{1.5}
\newcommand{\@padding}{0.08}

% Week configuration
\newcommand{\@weektype}{workweek}  % workweek, fullweeksunday, fullweekmonday
\newcommand{\@weekdaylist}{Monday,Tuesday,Wednesday,Thursday,Friday}
\newcommand{\@weekdaydisplay}{Monday,Tuesday,Wednesday,Thursday,Friday}
\newcommand{\@daycount}{5}

% ============================================
% User-facing configuration commands
% ============================================
\newcommand{\scheduletitle}[1]{\renewcommand{\@scheduletitle}{#1}}
\newcommand{\scheduleauthor}[1]{\renewcommand{\@scheduleauthor}{#1}}

% Parse time string like "8:00" or "13:30" and store hour
\newcommand{\timefrom}[1]{%
    \@parsetime{#1}%
    \pgfmathtruncatemacro{\@temph}{\@parsedtime}%
    \edef\@starthour{\@temph}%
}

\newcommand{\timeto}[1]{%
    \@parsetime{#1}%
    \pgfmathtruncatemacro{\@temph}{\@parsedtime}%
    \edef\@endhour{\@temph}%
}

% Time format toggles
\newcommand{\twentyfourhourtime}{\@usetwentyfourhourtrue}
\newcommand{\twelvehourtime}{\@usetwentyfourhourfalse}

% Week configuration toggles
\newcommand{\weekworkweek}{%
    \renewcommand{\@weektype}{workweek}%
    \renewcommand{\@weekdaylist}{Monday,Tuesday,Wednesday,Thursday,Friday}%
    \renewcommand{\@weekdaydisplay}{Monday,Tuesday,Wednesday,Thursday,Friday}%
    \renewcommand{\@daycount}{5}%
}

\newcommand{\weekfullsunday}{%
    \renewcommand{\@weektype}{fullweeksunday}%
    \renewcommand{\@weekdaylist}{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday}%
    \renewcommand{\@weekdaydisplay}{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday}%
    \renewcommand{\@daycount}{7}%
}

\newcommand{\weekfullmonday}{%
    \renewcommand{\@weektype}{fullweekmonday}%
    \renewcommand{\@weekdaylist}{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday}%
    \renewcommand{\@weekdaydisplay}{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday}%
    \renewcommand{\@daycount}{7}%
}

% Layout customization
\newcommand{\setdaywidth}[1]{\renewcommand{\@daywidth}{#1}}
\newcommand{\sethourheight}[1]{\renewcommand{\@hourheight}{#1}}
\newcommand{\setpadding}[1]{\renewcommand{\@padding}{#1}}

% ============================================
% Internal time parsing
% ============================================
% Parse time to decimal (e.g., "9:30" -> 9.5)
\def\@parsetime#1{\@@parsetime#1\@nil}
\def\@@parsetime#1:#2\@nil{%
    \pgfmathparse{#1 + #2/60}%
    \edef\@parsedtime{\pgfmathresult}%
}

% ============================================
% Event class definitions (colors)
% ============================================
\newcounter{@numclasses}
\setcounter{@numclasses}{0}
\newcounter{@daypos}

% Define an event class with RGB color
% Usage: \eventclass{ClassName}{R,G,B}
\newcommand{\eventclass}[2]{%
    \definecolor{class@#1}{RGB}{#2}%
    \stepcounter{@numclasses}%
    \expandafter\def\csname @classname\the@numclasses\endcsname{#1}%
}

% ============================================
% Event storage
% ============================================
\newcounter{@numevents}
\setcounter{@numevents}{0}

% Store an event
% Usage: \event{ClassName}{Event Name}{Days}{Start}{End}
% Days can be: Monday, Tuesday, Wednesday, Thursday, Friday (comma-separated)
\newcommand{\event}[5]{%
    \stepcounter{@numevents}%
    \expandafter\def\csname @eventclass\the@numevents\endcsname{#1}%
    \expandafter\def\csname @eventname\the@numevents\endcsname{#2}%
    \expandafter\def\csname @eventdays\the@numevents\endcsname{#3}%
    \expandafter\def\csname @eventstart\the@numevents\endcsname{#4}%
    \expandafter\def\csname @eventend\the@numevents\endcsname{#5}%
}

% ============================================
% Main schedule rendering
% ============================================
\newcommand{\printschedule}{%
    % Title and author
    \begin{center}
    \LARGE\textbf{\@scheduletitle}%
    \ifx\@scheduleauthor\empty\else\\[0.2cm]\Large\@scheduleauthor\fi%
    \end{center}
    \vspace{0.05cm}

    \begin{tikzpicture}[x=1cm, y=1cm]
        % Calculate dynamic day width based on number of days
        % Reserve 1.5cm for time labels, divide remaining width by day count
        \pgfmathsetmacro{\availablewidth}{(\textwidth/1cm) - 1.5}
        \pgfmathsetmacro{\daywidth}{\availablewidth / \@daycount}

        % Store other parameters
        \pgfmathsetmacro{\hourheight}{\@hourheight}
        \pgfmathsetmacro{\padding}{\@padding}
        \pgfmathtruncatemacro{\starthour}{\@starthour}
        \pgfmathtruncatemacro{\endhour}{\@endhour}

        % Draw column headers (days) - iterate through configured day list
        \setcounter{@daypos}{0}
        \@for\@currentday:=\@weekdaylist\do{%
            \node[anchor=south, font=\large\bfseries] at (\the@daypos*\daywidth+\daywidth/2, -\starthour*\hourheight+0.2) {\@currentday};
            \stepcounter{@daypos}%
        }

        % Draw row headers (times)
        \foreach \hour in {\starthour,...,\endhour} {
            \pgfmathtruncatemacro{\displayhour}{mod(\hour-1,12)+1}
            \if@usetwentyfourhour
                \node[anchor=east, font=\small] at (-0.1, -\hour*\hourheight) {\hour:00};
            \else
                \ifnum\hour<12
                    \def\@ampm{AM}
                \else
                    \def\@ampm{PM}
                \fi
                \node[anchor=east, font=\small] at (-0.1, -\hour*\hourheight) {\displayhour:00 \@ampm};
            \fi
        }

        % Draw vertical lines (day separators) - dynamically based on week type
        \foreach \day in {0,...,\@daycount} {
            \draw[gray] (\day*\daywidth, -\starthour*\hourheight) -- (\day*\daywidth, -\endhour*\hourheight);
        }

        % Draw horizontal lines (hour separators)
        \pgfmathsetmacro{\gridwidth}{\@daycount*\daywidth}
        \foreach \hour in {\starthour,...,\endhour} {
            \draw[gray] (0, -\hour*\hourheight) -- (\gridwidth, -\hour*\hourheight);
        }

        % Draw half-hour lines (dashed)
        \pgfmathtruncatemacro{\lasthour}{\endhour-1}
        \foreach \hour in {\starthour,...,\lasthour} {
            \draw[gray, dashed, line width=0.25pt] (0, -\hour*\hourheight-0.5*\hourheight) -- (\gridwidth, -\hour*\hourheight-0.5*\hourheight);
        }

        % Draw all events
        \foreach \evnum in {1,...,\the@numevents} {
            \@drawevent{\evnum}
        }

    \end{tikzpicture}

    \vspace{0.2cm}

    % Legend
    \begin{center}
    \begin{tikzpicture}
        \foreach \clnum in {1,...,\the@numclasses} {
            \pgfmathsetmacro{\xpos}{(\clnum-1)*3.5}
            \edef\@clname{\csname @classname\clnum\endcsname}
            \fill[class@\@clname] (\xpos,0) rectangle (\xpos+0.4,0.3);
            \node[anchor=west] at (\xpos+0.5,0.15) {\@clname};
        }
    \end{tikzpicture}
    \end{center}
}

% ============================================
% Event drawing helper
% ============================================
\newcommand{\@drawevent}[1]{%
    \edef\@evclass{\csname @eventclass#1\endcsname}%
    \edef\@evname{\csname @eventname#1\endcsname}%
    \edef\@evdays{\csname @eventdays#1\endcsname}%
    \edef\@evstart{\csname @eventstart#1\endcsname}%
    \edef\@evend{\csname @eventend#1\endcsname}%
    % Parse times
    \expandafter\@parsetime\expandafter{\@evstart}%
    \let\@startdec\@parsedtime
    \expandafter\@parsetime\expandafter{\@evend}%
    \let\@enddec\@parsedtime
    % Draw for each day
    \@drawforeachday{\@evclass}{\@evname}{\@evdays}{\@startdec}{\@enddec}%
}

\newcounter{@evdaypos}

\newcommand{\@drawforeachday}[5]{%
    % #1=class, #2=name, #3=event days, #4=start, #5=end
    % Iterate through the week's day list and draw event if it's on that day
    \setcounter{@evdaypos}{0}
    \@for\@weekday:=\@weekdaylist\do{%
        \@checkandrawday{#1}{#2}{#3}{#4}{#5}{\@weekday}{\the@evdaypos}%
        \stepcounter{@evdaypos}%
    }%
}

\newcommand{\@checkandrawday}[7]{%
    % #1=class, #2=name, #3=event days string, #4=start, #5=end, #6=dayname, #7=daypos
    % Check if this day is in the event's day list
    \@checkdayinlist{#3}{#6}%
    \if@daymatched
        \@draweventbox{#1}{#2}{#7}{#4}{#5}%
    \fi
}

\newif\if@daymatched

\newcommand{\@checkdayinlist}[2]{%
    % #1 = comma-separated day list, #2 = day to check
    \@daymatchedfalse
    \edef\@daytocheck{#2}%
    \@for\@testday:=#1\do{%
        \edef\@trimmedday{\@testday}%
        \ifnum\pdfstrcmp{\@trimmedday}{\@daytocheck}=0
            \@daymatchedtrue
        \fi
    }%
}

\newcommand{\@draweventbox}[5]{%
    % #1 = class, #2 = name, #3 = day number, #4 = start decimal, #5 = end decimal
    % Note: daywidth, hourheight, padding are already set in parent scope
    % Clamp start and end times to calendar bounds
    \pgfmathsetmacro{\startdec}{max(#4, \@starthour)}
    \pgfmathsetmacro{\enddec}{min(#5, \@endhour)}
    \pgfmathsetmacro{\xstart}{#3*\daywidth+\padding}
    \pgfmathsetmacro{\xend}{#3*\daywidth+\daywidth-\padding}
    \pgfmathsetmacro{\ystart}{-\startdec*\hourheight-\padding}
    \pgfmathsetmacro{\yend}{-\enddec*\hourheight+\padding}
    \pgfmathsetmacro{\ymid}{(\ystart+\yend)/2}
    \pgfmathsetmacro{\xcenter}{#3*\daywidth+\daywidth/2}
    % Draw the box
    \fill[class@#1, rounded corners] (\xstart, \ystart) rectangle (\xend, \yend);
    % Draw the label
    \node[font=\small, align=center] at (\xcenter, \ymid) {#2};
}

\endinput
