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
}
}
}