/*===========================================
            Plant and fireworks
              Martin Robinson
            L-systems iterator
===========================================*/

/*//----------test code--------------
#include <iostream>
#include <string>
#include <map>
#include <vector>

using namespace std;
----------------------------------*/

#include "lsys.hpp"

//private, build map of rule
void Tree::_makeRule(string tmpRuleStr)
{
    rule_t tmpRuleMap;
    size_t a = tmpRuleStr.find('{'),
           b = tmpRuleStr.find(':'),
           c = tmpRuleStr.find(';');
    do
    {
        //cout << tmpRuleStr.substr(a+1,b-a-1) << " " << tmpRuleStr.substr(b+1,c-b-1) << endl;
        tmpRuleMap[tmpRuleStr.substr(a+1,b-a-1)] = tmpRuleStr.substr(b+1,c-b-1);
        a = c;
        b = tmpRuleStr.find(':',a);
        c = tmpRuleStr.find(';',b);
    }while(b<tmpRuleStr.find('}'));
    _rulez.push_back(tmpRuleMap);
}

//public, constructor
Tree::Tree()
{
}

Tree::Tree(string seed)
{
    init(seed);
}

void Tree::init(string seed)     //constructeur
{
    _seed = seed;
    
    size_t start = 0, end = 0;
    do
    {
        start = seed.find('{',end);
        end = seed.find('}',start);
        string tmpRulezStr = seed.substr(start+1, end-start-1);
        //cout << "next " << tmpRulezStr << endl;
        _makeRule(tmpRulezStr);
    }while(seed.find('{',end)<seed.length());
    
    _tree = seed.substr(seed.rfind('}')+1,seed.length()-1);
    //cout << _tree << endl;
    
//    for (int i=0;i<_rulez.size();i++)
//    {
//        cout << "rule number : " << i << endl;
//        for(rule_t::const_iterator it = _rulez[i].begin(); it != _rulez[i].end(); it++)
//        {
//                string key = it->first;
//                string value = it->second;
//                cout << key << " : " << value << endl;
//        }
//    }
}

//public , iterator/generator
//a améliorer:
//des pointeurs si le code devient lent
void Tree::iterate(int index=0, int ruleN=0)
{
    string iteratedTree = "";
    int stackCnt = 0;
    for (int i=0;i<_tree.length();i++)
    {
        string tmpKey = _tree.substr(i,1);
        if (i < index)
            iteratedTree.append(tmpKey);
        else
        {
            if (tmpKey == "[")          //compteur de stack permet de ne faire poussez qu'une seule branche
                stackCnt++;
            else if (tmpKey == "]")
                stackCnt--;
            if (stackCnt < 0)           //nous itereron plus si vrais , seulement recopier les keys
                stackCnt = -1000000;    //s'assurer qu'il ne remontera pas
            if (stackCnt >=0 && _rulez[ruleN].find(tmpKey)!=_rulez[ruleN].end())
                iteratedTree.append(_rulez[ruleN][tmpKey]);
            else
                iteratedTree.append(tmpKey);
            //cout << stackCnt << endl;
        }
    }
    //cout << iteratedTree << endl;
    _tree = iteratedTree;           //replacer l'arbre par le nouveau
}

//public, iteration
const char Tree::operator [] (int index)
{
    if (index < _tree.length())
        return _tree[index];
    return 0;
}

//public, longueure
int Tree::len()
{
    return len(0);
}

int Tree::len(int index=0)
{
    if (!index)
        return _tree.length();
    int stcnt=0,  //compteur de stack
        lncnt=0;  //compteur longueur
    while(stcnt>=0 && index+lncnt<_tree.length())
    {
        if (_tree[index+lncnt] == '[')
            stcnt++;
        else if (_tree[index+lncnt] == ']')
            stcnt--;
        lncnt++;
    }
    return lncnt;
}

//public, afficher la string
void Tree::print()
{
    cout << _tree << endl;
}

//public, retourne la string
Tree::operator string ()
{
    return _tree;
}

void Tree::trim(int i)
{
    _tree.erase(i,len(i)-1);
}

/*//----------test code--------------
int main()
{
    cout << "lsys with map\n";
    
    //Tree tt("{a:aa[+a]-a;x:xx;y:yy;}{b:ab;}{c:abc;}a");
    Tree tt("{o:a[+ao]-ao;}ao");
    tt.iterate();    tt.print();
    tt.iterate();    tt.print();
    tt.iterate(18);    tt.print();

//    for (int i=0;i<tt.len();i++)
//        cout << tt[i];
//    cout << endl;
    cout << (string)tt << endl;
    tt.print();
    
    return 0;
}
//------------------------------------*/
