CourseInsights / src / datasetProcessor / DatasetProcessor.ts
DatasetProcessor.ts
Raw
import { InsightDatasetKind, InsightError, NotFoundError } from "../controller/IInsightFacade";
import InsightFacade from "../controller/InsightFacade";
import JSZip from "jszip";
import DatasetPersister from "./DatasetPersister";
import { DatasetSection, DatasetRoom, DatasetBuilding } from "./DatasetSection";
import DatasetValidator from "./DatasetValidator";
import DatasetParser from "./DatasetParser";

export default class DatasetProcessor {
	private insightFacade: InsightFacade;

	constructor(insightFacade: InsightFacade) {
		this.insightFacade = insightFacade;
	}

	public async processAddDataset(id: string, content: string, kind: InsightDatasetKind): Promise<string[]> {
		if (!new DatasetValidator(this.insightFacade).validateDataset(id, content, kind)) {
			throw new InsightError("validateDataset");
		}

		try {
			const zip = await JSZip().loadAsync(content, { base64: true });

			let dataset: DatasetSection[] | DatasetRoom[];
			if (kind === InsightDatasetKind.Sections) {
				dataset = await this.processAddDatasetSection(zip);
			} else {
				dataset = await this.processAddDatasetRoom(zip);
			}

			if (dataset.length === 0) {
				throw new InsightError("no valid dataset sections|rooms");
			}

			this.insightFacade.datasetIds.push(id);
			this.insightFacade.insights.push({ id, kind, numRows: dataset.length });
			this.insightFacade.datasets.set(id, dataset);

			const persister = new DatasetPersister();
			await Promise.all([
				persister.persistWriteDataset("data/_datasetIds.json", this.insightFacade.datasetIds),
				persister.persistWriteDataset("data/_insightDatasets.json", this.insightFacade.insights),
				persister.persistWriteDataset(`data/${id}.json`, dataset),
			]);

			return this.insightFacade.datasetIds;
		} catch (err) {
			throw new InsightError(`processAddDataset ${err}`);
		}
	}

	public async processAddDatasetSection(zip: JSZip): Promise<DatasetSection[]> {
		try {
			if (!zip.files["courses/"]) {
				throw new InsightError("zip is not courses/ folder");
			}

			const fileContents: string[] = await Promise.all(
				Object.values(zip.folder("courses")!.files).map(async (file) => file.async("text"))
			);

			return new DatasetParser(this.insightFacade).parseDataset(fileContents);
		} catch (err) {
			throw new InsightError(`processAddDatasetSection ${err}`);
		}
	}

	public async processAddDatasetRoom(zip: JSZip): Promise<DatasetRoom[]> {
		try {
			const index = zip.files["index.htm"];
			if (!index) {
				throw new InsightError("zip doesn't have index.htm file");
			}
			if (!zip.files["campus/discover/buildings-and-classrooms/"]) {
				throw new InsightError("zip doesn't have campus/discover/buildings-and-classrooms/ folder");
			}

			const fileContent: string = await index.async("text");

			const parser = new DatasetParser(this.insightFacade);
			const buildings: DatasetBuilding[] = await parser.parseBuilding(fileContent);

			const rooms: DatasetRoom[] = [];
			await Promise.all(
				buildings.map(async (building) => {
					const path = building.href.substring(2);
					const htmFile = zip.files[path];
					if (!htmFile) {
						return;
					}

					const roomFile = await htmFile.async("text");

					const datasetRooms: DatasetRoom[] = parser.parseRoom(roomFile, building);

					rooms.push(...datasetRooms);
				})
			);

			return rooms;
		} catch (err) {
			throw new InsightError(`processAddDatasetRoom ${err}`);
		}
	}

	public async processRemoveDataset(id: string): Promise<string> {
		const validator = new DatasetValidator(this.insightFacade);
		if (!validator.validateId(id)) {
			throw new InsightError("validateId");
		}
		if (!validator.validateRemoval(id)) {
			throw new NotFoundError("validateRemoval");
		}

		try {
			this.insightFacade.datasetIds = this.insightFacade.datasetIds.filter((iD) => iD !== id);
			this.insightFacade.insights = this.insightFacade.insights.filter((insight) => insight.id !== id);
			this.insightFacade.datasets.delete(id);
			const persister = new DatasetPersister();
			await Promise.all([
				persister.persistWriteDataset("data/_datasetIds.json", this.insightFacade.datasetIds),
				persister.persistWriteDataset("data/_insightDatasets.json", this.insightFacade.insights),
				persister.persistDeleteDataset("data/" + id + ".json"),
			]);
			return id;
		} catch (err) {
			throw new InsightError(`processRemoveDataset ${err}`); //maybe unnecessary, only for safety
		}
	}
}