# src/PropertyFactoryShader.js

    import {
    	assert,
    	isSomething,
    } from "akutils";

    import noParentStateErrorMsg from "./noParentStateErrorMsg";
    import Property from "./Property";
    import Shader from "./Shader";
    import StateType from "./StateType";

    /**
    	Specialized shader that uses a {@link StateType} instance to instantiate a {@link Property}.
    	Used by `KeyedApi` for adding child properties to the {@link Property#shader}.

    	@use {@link KeyedApi}
    	@see {@link Shader}
    */
    export default class PropertyFactoryShader {
    	/*
    		Creates a factory that will create a shader for instantiating shadow properties for a property type.

    		Parameters:
    			stateType - StateType instance describing the property
    			parent - the parent Property instance
    	*/
    	constructor(stateType, parent) {
    		this.stateType = stateType;
    		this.parent = parent;
    	}

    	setElementType(stateType) {
    		// ignoring since assuming set in StateType._setupShader() and also contained in the stateType var
    		this.elementType = stateType;
    	}

    	addProperty(name, stateType) {
    		assert( a => a.is(stateType instanceof StateType, `stateType not a StateType`) );

    		if (!this.propertyShaderDefn) {
    			this.propertyShaderDefn = { };
    		}

    		this.propertyShaderDefn[name] = stateType;
    	}

    	shadowProperty(time, name, parentState, parentImpl) {
    		assert( a => a.is(parentState || !this.parent, noParentStateErrorMsg(name, parentImpl)) );

    		// this should never happen but lets be safe
    		if (!isSomething(parentState)) {
    			console.warn(this.noParentStateErrorMsg(name, parentImpl));

    			return null;
    		}

    		const property = this.stateType.createProperty();
    		const shader = property.shader();

    		// set the proprety's parent property
    		property.setParent(this.parent);

    		this._configureShader(shader);

    		return shader.shadowProperty(time, name, parentState, parentImpl);
    	}

    	shouldAutomount() {
    		const PropertyClass = this.stateType._PropertyClass;

    		return PropertyClass.constructor.shouldAutomount && PropertyClass.constructor.shouldAutomount();
    	}

    	_configureShader(shader) {
    		const propertyShaderDefn = this.propertyShaderDefn;

    		if (!propertyShaderDefn) { return }

    		const keys = Object.keys(propertyShaderDefn);
    		var key, type;

    		for (let i=0, len=keys.length; i<len; i++) {
    			key = keys[i];
    			type = propertyShaderDefn[key];

    			shader.addProperty(key, type);
    		}
    	}
    }