001/*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019
020package org.crsh.text.ui;
021
022import groovy.lang.Closure;
023import org.crsh.command.CRaSHCommand;
024import org.crsh.shell.impl.command.spi.CommandInvoker;
025import org.crsh.lang.groovy.command.GroovyScriptCommand;
026import org.crsh.command.InvocationContext;
027import org.crsh.command.ScriptException;
028import org.crsh.text.Chunk;
029import org.crsh.text.LineRenderer;
030import org.crsh.text.RenderPrintWriter;
031import org.crsh.text.Renderer;
032
033import java.io.IOException;
034import java.util.LinkedList;
035import java.util.Map;
036
037public class EvalElement extends Element {
038
039  /** The closure to evaluate. */
040  Closure closure;
041
042  public LineRenderer renderer() {
043
044    Object owner = closure.getOwner();
045
046    //
047    final InvocationContext ctx;
048    Object cmd;
049    while (true) {
050      if (owner instanceof CRaSHCommand) {
051        cmd = owner;
052        ctx = ((CRaSHCommand)cmd).peekContext();
053        break;
054      } else if (owner instanceof GroovyScriptCommand) {
055        cmd = owner;
056        ctx = ((GroovyScriptCommand)cmd).peekContext();
057        break;
058      } else if (owner instanceof Closure) {
059        owner = ((Closure)owner).getOwner();
060      } else {
061        throw new UnsupportedOperationException("Cannot resolver owner " + owner + " to command");
062      }
063    }
064
065    //
066    final LinkedList<LineRenderer> renderers = new LinkedList<LineRenderer>();
067
068    //
069    final InvocationContext nested = new InvocationContext() {
070
071      /** . */
072      private LinkedList<Object> buffer = new LinkedList<Object>();
073
074      /** . */
075      private Renderer renderable;
076
077      public CommandInvoker<?, ?> resolve(String s) throws ScriptException, IOException {
078        return ctx.resolve(s);
079      }
080
081      public boolean isPiped() {
082        throw new UnsupportedOperationException();
083      }
084
085      public boolean takeAlternateBuffer() {
086        return false;
087      }
088
089      public boolean releaseAlternateBuffer() {
090        return false;
091      }
092
093      public RenderPrintWriter getWriter() {
094        return ctx.getWriter();
095      }
096
097      public Map<String, Object> getSession() {
098        return ctx.getSession();
099      }
100
101      public Map<String, Object> getAttributes() {
102        return ctx.getAttributes();
103      }
104
105      public int getWidth() {
106        return ctx.getWidth();
107      }
108
109      public int getHeight() {
110        return ctx.getHeight();
111      }
112
113      public String getProperty(String propertyName) {
114        return ctx.getProperty(propertyName);
115      }
116
117      public String readLine(String msg, boolean echo) {
118        return null;
119      }
120
121      public Class getConsumedType() {
122        return Object.class;
123      }
124
125      public void write(Chunk chunk) throws IOException {
126        provide(chunk);
127      }
128
129      public void provide(Object element) throws IOException {
130        Renderer current = Renderer.getRenderable(element.getClass());
131        if (current == null) {
132          current = Renderer.ANY;
133        }
134        if (current != null) {
135          if (renderable != null && !current.equals(renderable)) {
136            flush();
137          }
138          buffer.addLast(element);
139          renderable = current;
140        }
141      }
142
143      public void flush() throws IOException {
144        // We don't really flush, we just compute renderables from the buffer
145        if (buffer.size() > 0) {
146          LineRenderer i = renderable.renderer(buffer.iterator());
147          buffer.clear();
148          renderers.add(i);
149        }
150      }
151
152      public void close() throws IOException {
153        // Nothing to do, except maybe release resources (and also prevent to do any other operation)
154      }
155    };
156
157    if (cmd instanceof CRaSHCommand) {
158      ((CRaSHCommand)cmd).pushContext(nested);
159    } else {
160      ((GroovyScriptCommand)cmd).pushContext(nested);
161    }
162    try {
163      closure.call();
164    }
165    finally {
166      if (cmd instanceof CRaSHCommand) {
167        ((CRaSHCommand)cmd).popContext();
168      } else {
169        ((GroovyScriptCommand)cmd).popContext();
170      }
171    }
172
173    // Be sure to flush
174    try {
175      nested.flush();
176    }
177    catch (IOException e) {
178      e.printStackTrace();
179    }
180
181    //
182    return LineRenderer.vertical(renderers);
183  }
184}