content: package act.view;
  
  /*-
   * #%L
   * ACT Framework
   * %%
   * Copyright (C) 2014 - 2017 ActFramework
   * %%
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   * #L%
   */
  
  import static org.osgl.http.H.Format.*;
  
  import act.ActResponse;
  import act.app.ActionContext;
  import act.controller.Controller;
  import org.osgl.http.H;
  import org.osgl.mvc.result.*;
  import org.osgl.storage.ISObject;
  import org.osgl.util.E;
  import org.osgl.util.S;
  
  import java.io.File;
  import java.io.InputStream;
  import java.util.*;
  
  /**
   * Render a template with template path and arguments provided
   * by {@link ActionContext}
   */
  public class RenderAny extends Result {
  
      public static final RenderAny INSTANCE = new RenderAny();
  
      private boolean ignoreMissingTemplate = false;
  
      public RenderAny() {
          super(H.Status.OK);
      }
  
      public RenderAny ignoreMissingTemplate() {
          this.ignoreMissingTemplate = true;
          return this;
      }
  
      @Override
      public void apply(H.Request req, H.Response resp) {
          throw E.unsupport("RenderAny does not support " +
                  "apply to request and response. Please use apply(AppContext) instead");
      }
  
      // TODO: Allow plugin to support rendering pdf, xls or other binary types
      public void apply(ActionContext context) {
          Boolean hasTemplate = context.hasTemplate();
          if (null != hasTemplate && hasTemplate) {
              RenderTemplate.get(context.successStatus()).apply(context);
              return;
          }
          H.Format fmt = context.accept();
          if (fmt.isSameTypeWith(UNKNOWN)) {
              // let's guess the request needs HTML
              fmt = HTML;
          }
          Result result = null;
          if (JSON.isSameTypeWith(fmt)) {
              List<String> varNames = context.__appRenderArgNames();
              Map<String, Object> map = new HashMap<>(context.renderArgs());
              if (null != varNames && !varNames.isEmpty()) {
                  for (String name : varNames) {
                      map.put(name, context.renderArg(name));
                  }
              }
              result = new RenderJSON(map);
          } else if (XML.isSameTypeWith(fmt)) {
              List<String> varNames = context.__appRenderArgNames();
              Map<String, Object> map = new HashMap<>();
              if (null != varNames && !varNames.isEmpty()) {
                  for (String name : varNames) {
                      map.put(name, context.renderArg(name));
                  }
              }
              result = new FilteredRenderXML(map, null, context);
          } else if (fmt.isSameTypeWithAny(HTML, TXT, CSV)) {
              if (!ignoreMissingTemplate) {
                  throw E.unsupport("Template[%s] not found", context.templatePath());
              }
              context.nullValueResultIgnoreRenderArgs().apply(context.req(), context.prepareRespForResultEvaluation());
              return;
          } else if (fmt.isSameTypeWithAny(PDF, XLS, XLSX, DOC, DOCX)) {
              List<String> varNames = context.__appRenderArgNames();
              if (null != varNames && !varNames.isEmpty()) {
                  Object firstVar = context.renderArg(varNames.get(0));
                  String action = S.str(context.actionPath()).afterLast(".").toString();
                  if (firstVar instanceof File) {
                      File file = (File) firstVar;
                      result = new RenderBinary(file, action);
                  } else if (firstVar instanceof InputStream) {
                      InputStream is = (InputStream) firstVar;
                      result = new RenderBinary(is, action);
                  } else if (firstVar instanceof ISObject) {
                      ISObject sobj = (ISObject) firstVar;
                      result = new RenderBinary(sobj.asInputStream(), action);
                  }
                  if (null == result) {
                      throw E.unsupport("Unknown render arg type [%s] for binary response", firstVar.getClass());
                  }
              } else {
                  throw E.unexpected("No render arg found for binary response");
              }
          }
          if (null != result) {
              ActResponse<?> resp = context.prepareRespForResultEvaluation();
              result.status(context.successStatus()).apply(context.req(), resp);
          } else {
              throw E.unexpected("Unknown accept content type: %s", fmt.contentType());
          }
      }
  
      public static RenderAny get() {
          return INSTANCE;
      }
  
      public static void clearThreadLocals() {
          RenderTemplate.renderArgsBag.remove();
      }
  
  }
  