import GrainDescriber from "grain/GrainDescriber"; import { cloneDeep } from "lodash"; import { MarkerData } from "maps/mapMarkers/Markers"; import { User } from "models"; import { pond } from "protobuf-ts/pond"; import { stringToMaterialColour } from "utils/strings"; import { or } from "utils/types"; export class Bin { public settings: pond.BinSettings = pond.BinSettings.create(); public status: pond.BinStatus = pond.BinStatus.create(); public permissions: pond.Permission[] = []; public static create(pb?: pond.Bin): Bin { let my = new Bin(); if (pb) { my.settings = pond.BinSettings.fromObject(cloneDeep(or(pb.settings, {}))); my.status = pond.BinStatus.fromObject(cloneDeep(or(pb.status, {}))); my.permissions = pb.binPermissions; } return my; } public static clone(other?: Bin): Bin { if (other) { return Bin.create( pond.Bin.fromObject({ settings: cloneDeep(other.settings), status: cloneDeep(other.status), binPermissions: cloneDeep(other.permissions) }) ); } return Bin.create(); } public static any(data: any): Bin { return Bin.create(pond.Bin.fromObject(cloneDeep(data))); } public setLocation(long: number, lat: number): void { this.settings.location = pond.Location.create(); this.settings.location.longitude = long; this.settings.location.latitude = lat; } public removeLocation(): void { this.settings.location = null; } public binShape(): pond.BinShape | undefined { return this.settings.specs?.shape; } public diameter(): number { return this.settings.specs?.diameterCm ?? 0; } public height(): number { return this.settings.specs?.heightCm ?? 0; } public sidewallHeight(): number { return this.settings.specs?.advancedDimensions?.sidewallHeight ?? 0; } public roofHeight() : number { return this.settings.specs?.advancedDimensions?.topConeHeight ?? 0; } public hopperHeight() : number { return this.settings.specs?.advancedDimensions?.hopperHeight ?? 0; } public roofAngle() : number { return this.settings.specs?.advancedDimensions?.roofAngle ?? 0; } public hopperAngle() : number { return this.settings.specs?.advancedDimensions?.hopperAngle ?? 0; } public key(): string { return this.settings.key; } public name(): string { return this.settings.name !== "" ? this.settings.name : "Bin " + this.key(); } public grain(): pond.Grain { let g: pond.Grain = pond.Grain.GRAIN_NONE; if (this.settings.inventory) { g = this.settings.inventory.grainType; } return g; } public getLocation(): pond.Location | null | undefined { return this.settings.location; } public binMapped(): boolean { let location = this.getLocation(); return ( location !== undefined && location !== null && location.latitude !== 0 && location.longitude !== 0 ); } public storage(): pond.BinStorage { return !this.settings.storage ? pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN : this.settings.storage; } public customType(): string { let c = ""; if (this.settings.inventory) { if (this.settings.inventory.customGrain){ c = this.settings.inventory.customGrain.name }else{ c = this.settings.inventory.customTypeName; } } return c; } public customGrain(): pond.GrainSettings | undefined { return this.settings.inventory?.customGrain ?? undefined } public empty(): boolean { return this.settings.inventory?.empty || (this.settings.inventory !== undefined && this.settings.inventory !== null && this.bushels() < 5); } public objectType(): pond.ObjectType { return pond.ObjectType.OBJECT_TYPE_BIN; } public objectTypeString(): string { return "Bin"; } public subtype(): string { return this.settings.inventory?.grainSubtype ?? ""; } public grainColour(): string { let colour = ""; if (this.settings.inventory) { if (this.grain() === pond.Grain.GRAIN_CUSTOM) { if (this.customType() !== "") { colour = stringToMaterialColour(this.customType()); } } else { colour = GrainDescriber(this.grain()).colour; } } return colour; } public bushels(): number { let control = this.settings.inventory?.inventoryControl; let bushels = this.settings.inventory?.grainBushels || 0 if (control === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR || control === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_LIBRACART){ bushels = this.status.grainBushels } return bushels } public fillPercent(): number { let fill = 0; if (this.settings.inventory && this.settings.specs) { let bushels = this.settings.inventory.grainBushels if (this.settings.inventory.inventoryControl === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR || this.settings.inventory.inventoryControl === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_LIBRACART){ bushels = this.status.grainBushels } fill = Math.round( (bushels / this.settings.specs.bushelCapacity) * 100 ); } return fill; } public grainName(): string { if (this.grain() !== pond.Grain.GRAIN_INVALID) { if (this.grain() === pond.Grain.GRAIN_CUSTOM) { return this.customType(); } else { return GrainDescriber(this.grain()).name; } } else { return "None"; } } public binFillCap(): string { let fillCap = ""; if (this.settings.specs && this.settings.inventory) { fillCap = this.settings.inventory.grainBushels + "/" + this.settings.specs.bushelCapacity; } return fillCap; } public location(): pond.Location | undefined | null { let loc = this.settings.location; return loc; } public fanID(): number { return this.settings.fanId; } public supportedGrain(): boolean { let s = false; if ( this.grain() !== pond.Grain.GRAIN_NONE && this.grain() !== pond.Grain.GRAIN_CUSTOM && this.grain() !== pond.Grain.GRAIN_INVALID ) { s = true; } return s; } public getMarkerData( clickFunc?: (event: React.PointerEvent, index: number, isMobile: boolean) => void, updateFunc?: (location: pond.Location) => void ): MarkerData { let m: MarkerData = { centered: true, longitude: this.location()?.longitude ?? 0, latitude: this.location()?.latitude ?? 0, title: this.name(), colour: this.grainColour(), visibleLevels: { min: 17 }, graphPercent: this.fillPercent(), customSize: this.settings.theme?.height, details: [this.name() + ", " + this.binFillCap()], clickFunc: clickFunc, updateFunc: updateFunc }; return m; } /** * returns the bushels per tonne set in the bins settings, if not set will return 1 * @returns 1 or bushels per tonne */ public bushelsPerTonne(): number { //trying to avoid a divide by 0 error by only returning a value greater than 0 //since to get the weight you divide the current bushels by the bushels per tonne let bpt = 1; if (this.settings.inventory) { if (this.settings.inventory.bushelsPerTonne > 0) { bpt = this.settings.inventory.bushelsPerTonne; } } return bpt; } public grainInventory(user: User): number { let grain = this.bushels() if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.bushelsPerTonne() > 1){ grain = this.bushels() / this.bushelsPerTonne() }else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.bushelsPerTonne() > 1){ grain = this.bushels() / (this.bushelsPerTonne() * 0.907) } return Math.round(grain*100)/100 } /** * gets the enum value for the inventory control in the bins inventory */ public inventoryControl(): pond.BinInventoryControl { let c = pond.BinInventoryControl.BIN_INVENTORY_CONTROL_UNKNOWN; if (this.settings.inventory) { return this.settings.inventory.inventoryControl; } return c; } public upperTempThreshold(): number { return this.settings.highTemp } public lowerTempThreshold(): number { return this.settings.lowTemp } public targetMoisture(): number { return this.settings.inventory?.targetMoisture ?? 0 } }