Karolis' playground schedule / master src / lib / models / parser.ts
master

Tree @master (Download .tar.gz)

parser.ts @masterraw · history · blame

import type { Day, timeperiod, weekDay } from "./models";
export type legacyDay = { [k: string]: { [y: string]: string } };

export const operators = ["gedas", "karolis", "justinas.n", "jonas"];

export function parseRange(s: string) {
  const [startTime, endTime] = s.split("-").map((x) => {
    const [h, m] = x.split(":");
    return parseInt(h) + parseInt(m) / 60;
  });
  return { startTime, endTime };
}

export function parseType(Name: weekDay, day: legacyDay): Day {
  let ops = new Map(operators.map((x) => [x, []]));

  for (const [key, val] of Object.entries<{ [y: string]: string }>(day)) {
    const type = key as "first" | "work";
    for (const [op, periods] of Object.entries(val)) {
      for (const period of periods.split(",")) {
        if (period === "") {
          continue;
        }
        let p = parseRange(period);
        let t = ops.get(op);
        if (!t) {
          t = [];
        }
        ops.set(op, [...t, { type, ...p }]);
      }
    }
  }
  return { Name, operators: ops };
}

function comparePeriods(a: timeperiod, b: timeperiod): number {
  const cmp = a.type.localeCompare(b.type);
  if (cmp != 0) {
    return cmp;
  }
  return a.startTime - b.startTime;
}

function mergeTimeperiods(
  daya: timeperiod[],
  dayb: timeperiod[],
): timeperiod[] {
  let result: timeperiod[] = [];
  const set = [...daya, ...dayb].sort(comparePeriods);
  const t = set.reduce((p, x) => {
    if (p === undefined) {
      return x;
    }
    if (p.type === x.type && p.label === x.label && p.endTime >= x.startTime) {
      p.endTime = Math.max(p.endTime, x.endTime);
      return p;
    }
    result.push(p);
    return x;
  }, undefined);

  if (t !== undefined) {
    result.push(t);
  }
  return result;
}

function timeperiodFrom(
  time: number,
): (p: timeperiod) => timeperiod | undefined {
  return (period: timeperiod) => {
    if (period.endTime <= time) {
      return undefined;
    }
    return {
      ...period,
      startTime: Math.max(period.startTime, time),
    };
  };
}

function timeperiodTo(time: number): (p: timeperiod) => timeperiod | undefined {
  return (period: timeperiod) => {
    if (period.startTime >= time) {
      return undefined;
    }
    return {
      ...period,
      endTime: Math.min(period.endTime, time),
    };
  };
}

function periodFilter(
  periods: timeperiod[],
  mapfilterFunc: (p: timeperiod) => timeperiod | undefined,
): timeperiod[] {
  if (periods === undefined) {
    return [];
  }
  return periods.reduce((a, y) => {
    const t = mapfilterFunc(y);
    if (t !== undefined) {
      a.push(t);
    }
    return a;
  }, []);
}

function spliceTimeperdiods(
  daya: timeperiod[],
  dayb: timeperiod[],
  time: number,
): timeperiod[] {
  const dayafiltered = periodFilter(daya, timeperiodTo(time));

  const daybfiltered = periodFilter(dayb, timeperiodFrom(time));
  const res = mergeTimeperiods(dayafiltered, daybfiltered);
  return res;
}

export function spliceDays(daya: Day, dayb: Day, time: number): Day {
  const opsSet = new Set([...daya.operators.keys(), ...dayb.operators.keys()]);

  return {
    Name: daya.Name,
    operators: new Map(
      [...opsSet].map((x) => {
        return [
          x,
          spliceTimeperdiods(
            daya.operators.get(x),
            dayb.operators.get(x),
            time,
          ),
        ];
      }),
    ),
  };
}