import ShaderPack from "../shaders/class"; import {ColorName, ColorProvider, ShaderFunction} from "./d"; import Swatch from "../swatches/class"; import basicShaderPack from "../shaders/basic"; import basicSwatch from "../swatches/basic"; import NameStyle from "./nameStyle"; import proxyDefinition from "./proxy"; import Color from "./color"; export default class TinctManager implements ColorProvider { private proxy; private shaders: ShaderPack[] = [ basicShaderPack ]; private swatches: Swatch[] = [ basicSwatch ]; constructor() { this.proxy = new Proxy(this, proxyDefinition); return this.proxy; } public loadSwatch(swatch: Swatch) { this.swatches.push(swatch); } public hasSwatch(name: string): boolean { return this.swatches.filter((swatch: Swatch) => swatch.getName() === name).length > 0; } public removeSwatch(name: string) { this.swatches = this.swatches.filter((swatch: Swatch) => swatch.getName() !== name); } public removeAllSwatches() { this.swatches = []; } public loadShaderPack(shader: ShaderPack) { this.shaders.push(shader); } public hasShaderPack(name: string): boolean { return this.shaders.filter((shader: ShaderPack) => shader.getName() === name).length > 0; } public removeShaderPack(name: string) { this.shaders = this.shaders.filter((shader: ShaderPack) => shader.getName() !== name); } public removeAllShaderPacks() { this.shaders = []; } public getSwatch(name: string): Swatch { let swatches = this.swatches.filter((swatch: Swatch) => swatch.getName() === name); if (swatches.length === 1) { return swatches[0]; } else { throw new Error(`Could not determine swatch ${name}.\nLoaded swatches are: ${Object.keys(this.swatches).join(", ")}`); } } public hasColor(name: string): boolean { return this.swatches.filter((swatch: Swatch) => swatch.hasColor(name)).length > 0; } public getColor(name: string): Color { for (let i = this.swatches.length - 1; i >= 0; i--) { let swatch = this.swatches[i]; if (swatch.hasColor(name)) { return swatch.getColor(name); } } throw new Error(`Could not find color ${name}.`); } public getColors(): string[] { return this.swatches.map((swatch: Swatch) => swatch.getColors()).reduce((a, b) => [...a, ...b], []); } public hasShade(name: string): boolean { return this.swatches.filter((swatch: Swatch) => swatch.hasShade(name)).length > 0; } public getShade(name: string): Color { for (let i = this.swatches.length - 1; i >= 0; i--) { let swatch = this.swatches[i]; if (swatch.hasShade(name)) { return swatch.getShade(name); } } throw new Error(`Could not find shade ${name}.`); } public getShades(): string[] { return this.swatches.map((swatch: Swatch) => swatch.getShades()).reduce((a, b) => [...a, ...b], []); } public getShaderFunction(name: string, style: NameStyle): ShaderFunction { for (let i = this.shaders.length - 1; i >= 0; i--) { let shader = this.shaders[i]; if (shader.getNameStyle() === style && shader.hasShader(name)) { return shader.getShader(name); } } throw new Error(`Could not find shader ${name}.`); } public destructureName(name: string): ColorName { let swatch = null; let color = null; let prefixShade = null; let suffixShade = null; let [expandable, remainder] = name.split("."); if (remainder) { swatch = expandable; expandable = remainder; } let colorProvider: ColorProvider; if (swatch) { colorProvider = this.getSwatch(swatch); } else { colorProvider = this; } if (colorProvider.getShades().indexOf(expandable) > -1) { color = expandable; } if (!color) { expandable = expandable.toLowerCase(); let availableColors = colorProvider.getColors(); availableColors = availableColors.sort((a, b) => b.length - a.length); for (let i = 0; i < availableColors.length; i++) { let attempt = availableColors[i]; let lcAttempt = attempt.toLowerCase(); let idx = expandable.indexOf(lcAttempt); if (idx > -1) { color = attempt; prefixShade = expandable.substring(0, idx); suffixShade = expandable.substring(idx + attempt.length); break; } } } if (!color) throw new Error(`Failed to destructure ${name}, it is likely malformed`); if (!prefixShade) prefixShade = null; if (!suffixShade) suffixShade = null; return {swatch, color, prefixShade, suffixShade}; } public resolveColor(name: string): Color { try { let {swatch, color, prefixShade, suffixShade} = this.destructureName(name); let colorProvider: ColorProvider; if (swatch) { colorProvider = this.getSwatch(swatch); } else { colorProvider = this; } if (colorProvider.hasColor(color)) { let actualColor = colorProvider.getColor(color); if (prefixShade) { let fn = this.getShaderFunction(prefixShade, NameStyle.PREFIX); actualColor = fn(actualColor, this.proxy); if (actualColor === null) throw new Error(`Could not apply ${prefixShade}`) } if (suffixShade) { let fn = this.getShaderFunction(suffixShade, NameStyle.SUFFIX); actualColor = fn(actualColor, this.proxy); if (actualColor === null) throw new Error(`Could not apply ${suffixShade}`) } return actualColor; } else if (colorProvider.hasShade(color)) { return colorProvider.getShade(color); } } catch (e) { throw new Error(`Error thrown while resolving ${name}\nCaused by: ${e}`); } throw new Error(`Could not find color ${name}`); } }