/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *   This file is part of
 *       _______   ______________  ______     _____
 *      / ____/ | / /  _/ ____/  |/  /   |   |__  /
 *     / __/ /  |/ // // / __/ /|_/ / /| |    /_ <
 *    / /___/ /|  // // /_/ / /  / / ___ |  ___/ /
 *   /_____/_/ |_/___/\____/_/  /_/_/  |_| /____/.
 *
 *   Copyright © 2003-2010 Brain Control, all rights reserved.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef LSYS2_SYMBOL_HPP
#define LSYS2_SYMBOL_HPP

#include "../../eshared.hpp"
#include "rule.hpp"

class eLsys2_Symbol {
public:
    eLsys2_Symbol() : m_growTimeMean(1.0f), m_growTimeRandomization(1.0f) {
    }

	eBool applyRandomRule(eLsys2_Evaluator* state, eU32 parent, eLSys2_Context& context) const {
		if(rules.size() == 0)
			return false;

		eF32 rSum = 0.0f;
		for(eU32 i = 0; i < rules.size(); i++)
			rSum += rules[i]->probability(context);
		if(rSum == 0.0f)
			return false;

		eF32 remaining = rSum * eRandomF();
		eU32 ruleIdx = 0;
		while(true) {
			eF32 p = rules[ruleIdx]->probability(context);
			if((ruleIdx > rules.size()) || (remaining < p))
				break;
			remaining -= p;
		}

		rules[ruleIdx]->apply(state, parent, context);
        return true;
	}

    virtual eU32 init(void* state) const { return -1;};
    virtual	void execute(eU32 instanceHandle, void* state, eF32 blendWeight, eF32 energy, const eF32* parameters, eLSys2_Context& context) const {};
    virtual	void prepare(eU32 instanceHandle, void* state, eF32 blendWeight, eF32 energy) const {};

    void addRule(eLsys2_Rule* rule) {
        this->rules.append(rule);
    }

    void removeRule(eLsys2_Rule* rule) {
        for(eU32 i = 0; i < this->rules.size(); i++)
            if(rules[i] == rule) {
                this->rules.removeAt(i);
                break;
            }
    }

    eF32 getInstanceGrowTime() const {
        return m_growTimeMean * (1.0f + m_growTimeRandomization * (eRandomF() * 2.0f - 1.0f));
    }

    void setGrowProperties(eF32 mean, eF32 randomization) {
        m_growTimeMean = mean;
        m_growTimeRandomization = randomization;
    }

private:
	eArray<eLsys2_Rule*> rules;
    eF32    m_growTimeMean;
    eF32    m_growTimeRandomization;
};

#endif // LSYS2_SYMBOL_HPP
