/**
 * Copyright (c) 2012 to original author or authors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.sonatype.maven.polyglot.groovy.builder.factory;

import groovy.lang.Closure;
import groovy.util.FactoryBuilderSupport;
import groovy.util.Node;
import groovy.util.NodeBuilder;
import org.codehaus.plexus.util.xml.Xpp3Dom;

import java.util.List;
import java.util.Map;

/**
 * Builds object nodes.
 *
 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
 *
 * @since 0.7
 */
public class ObjectFactory extends NamedFactory {
  public ObjectFactory(final String name) {
    super(name);
  }

  @Override
  public boolean isHandlesNodeChildren() {
    return true;
  }

  public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attrs) throws InstantiationException, IllegalAccessException {
    return new Xpp3Dom(getName());
  }

  @Override
  public boolean onNodeChildren(FactoryBuilderSupport builder, Object node, Closure content) {
    Xpp3Dom dom = (Xpp3Dom) node;

    NodeBuilder nodes = new NodeBuilder() {
      @Override
      protected void setClosureDelegate(final Closure c, final Object o) {
        c.setDelegate(this);
        c.setResolveStrategy(Closure.DELEGATE_FIRST);
      }

      @Override
      public void setProperty(final String name, final Object value) {
        this.invokeMethod(name, value);
      }
    };

    content.setDelegate(nodes);
    content.setResolveStrategy(Closure.DELEGATE_FIRST);
    Node root = (Node) nodes.invokeMethod(getName(), content);

    for (Node child : (List<Node>) root.children()) {
      dom.addChild(nodeToXpp3(child));
    }

    return false;
  }

  private Xpp3Dom nodeToXpp3(final Node node) {
    Xpp3Dom dom = new Xpp3Dom((String) node.name());

    Object value = node.value();
    if (value instanceof String) {
      dom.setValue(String.valueOf(value));
    }

    Map attrs = node.attributes();
    for (Object key : attrs.keySet()) {
      dom.setAttribute(String.valueOf(key), String.valueOf(attrs.get(key)));
    }

    for (Object child : node.children()) {
      if (child instanceof Node) {
        dom.addChild(nodeToXpp3((Node) child));
      }
    }

    return dom;
  }
}