/*
 * Solver
 * https://github.com/goliatone/Solver
 *
 * Copyright (c) 2015 goliatone
 * Licensed under the MIT license.
 */
'use strict';

var _inherit = require('util').inherits;
var EventEmitter = require('events').EventEmitter;

var extend = require('gextend');
var Keypath = require('gkeypath');
var Flattener = require('flattener');

var Template = require('./template');

var DEFAULTS = {
    autoinitialize: true,
    clone: true,
    openTag: '${',
    closeTag: '}',
    maxRecursion: 20
};

function Solver(config){
    EventEmitter.call(this);
    config = extend({}, this.constructor.DEFAULTS, config);

    if(config.autoinitialize ) this.init(config);
}

_inherit(Solver, EventEmitter);

Solver.DEFAULTS = DEFAULTS;

Solver.prototype.init = function(config){
    if(this.initialized) return this;
    this.initialized = true;

    extend(this, this.constructor.DEFAULTS, config);

    if(this.template) return this;

    this.template = new Template({
        openTag: this.openTag,
        closeTag: this.closeTag
    });
};

Solver.prototype.solve = function(bean, context){
    context = context || bean;
    var out = this.clone ? extend({}, bean) : {};

    var flat = Flattener.flatten(bean);

    var self = this;
    var value, result, guard;

    Object.keys(flat).map(function(key){
        value = flat[key];

        if(!this.template.needsInterpolation(value)){ return;}

        guard = 0;
        result = value;
        while(this.template.needsInterpolation(result)){
            if(guard++ > self.maxRecursion) {
                self.logger.warn('GSolver max recursion for: %s', result);
                break;
            }
            result = this.template.compile(result, context);
        }
        Keypath.set(out, key, result);

    }, this);

    this.emitNext('solve', out);

    return out;
};

Solver.prototype.emitNext = function(type, payload){
    process.nextTick(function(){
        this.emit(type, payload);
    }.bind(this));

    return this;
};

Solver.prototype.logger = console;

/**
 * Exports module
 */
module.exports = Solver;

@@ -471,16 +471,66 @@
 g: '%7D',%0A
+    objectOpenTag: '@%7B',%0A    objectCloseTag: '%7D',%0A
     maxR
@@ -542,16 +542,16 @@
 ion: 20%0A
-
 %7D;%0A%0Afunc
@@ -1380,16 +1380,215 @@
 %5Bkey%5D;%0A%0A
+        /*%0A         * Solve object references.%0A         */%0A        value = this.keypath(value, context);%0A%0A        if(value !== flat%5Bkey%5D)%7B%0A            return Keypath.set(out, key, value);%0A        %7D%0A%0A
         
@@ -1893,32 +1893,33 @@
 ;%0A            %7D%0A
+%0A
             resu
@@ -1973,16 +1973,17 @@
       %7D%0A
+%0A
         
@@ -2059,24 +2059,24 @@
 ve', out);%0A%0A
-
     return o
@@ -2079,24 +2079,362 @@
 rn out;%0A%7D;%0A%0A
+Solver.prototype.keypath = function(attr, context)%7B%0A    var openTag = this.objectOpenTag,%0A        closeTag = this.objectCloseTag;%0A%0A    if(attr.indexOf(openTag) === 0 && attr.indexOf(closeTag) !== -1)%7B%0A        var path = attr.replace('@%7B', '').replace('%7D', '');%0A        attr = Keypath.get(context, path, attr);%0A    %7D%0A%0A    return attr;%0A%7D;%0A%0A
 Solver.proto

Support object resolution