/*
 * Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.jsp.java;

import com.caucho.jsp.JspParseException;
import com.caucho.util.L10N;
import com.caucho.vfs.WriteStream;
import com.caucho.xml.QName;

import java.io.IOException;
import java.util.Locale;

public class JspDirectiveTag extends JspNode {
  private static final QName IMPORT = new QName("import");
  private static final QName DISPLAY_NAME = new QName("display-name");
  private static final QName BODY_CONTENT = new QName("body-content");
  private static final QName DYNAMIC_ATTRIBUTES
    = new QName("dynamic-attributes");
  private static final QName SMALL_ICON = new QName("small-icon");
  private static final QName LARGE_ICON = new QName("large-icon");
  private static final QName DESCRIPTION = new QName("description");
  private static final QName EXAMPLE = new QName("example");
  private static final QName LANGUAGE = new QName("language");
  private static final QName PAGE_ENCODING = new QName("pageEncoding");
  private static final QName IS_EL_IGNORED = new QName("isELIgnored");
  private static final QName DEFERRED_AS_LITERAL
    = new QName("deferredSyntaxAllowedAsLiteral");
  private static final QName TRIM_WHITESPACES
    = new QName("trimDirectiveWhitespaces");
  
  private static final QName IS_VELOCITY_ENABLED =
    new QName("isVelocityEnabled");
  
  static final L10N L = new L10N(JspDirectiveTag.class);

  private String _import;
  
  /**
   * Adds an attribute.
   *
   * @param name the attribute name
   * @param value the attribute value
   */
  public void addAttribute(QName name, String value)
    throws JspParseException
  {
    if (! _gen.isTag())
      throw error(L.l("@tag directive is only allowed in tag files"));
    
    JavaTagGenerator gen = (JavaTagGenerator) _gen;

    if (IS_EL_IGNORED.equals(name)) {
      boolean isIgnored = value.equals("true");

      if (_parseState.isELIgnoredPageSpecified() &&
          isIgnored != _parseState.isELIgnored())
        throw error(L.l("isELIgnored values conflict"));

      _parseState.setELIgnored(isIgnored);
      _parseState.setELIgnoredPageSpecified(true);
    }
    /*
    else if (name.equals("isScriptingInvalid"))
      _parseState.setScriptingInvalid(value.equals("true"));
    */
    else if (IS_VELOCITY_ENABLED.equals(name))
      _parseState.setVelocityEnabled(value.equals("true"));
    else if (PAGE_ENCODING.equals(name)) {
      String oldEncoding = _parseState.getPageEncoding();
      
      if (oldEncoding != null && ! value.equals(oldEncoding))
        throw error(L.l("pageEncoding '{0}' conflicts with previous value of pageEncoding '{1}'.  Check the .jsp and any included .jsp files for conflicts.", value, oldEncoding));

      _parseState.setPageEncoding(value);
      _parseState.setCharEncoding(value);
    }
    else if (LANGUAGE.equals(name)) {
      if (! value.equals("java"))
        throw error(L.l("'{0}' is not supported as a JSP scripting language.",
                        value));
    }
    else if (IMPORT.equals(name)) {
      _import = value;
      
      _parseState.addImport(value);
    }
    else if (DISPLAY_NAME.equals(name)) {
      String oldValue = gen.getDisplayName();
      
      if (oldValue != null && ! oldValue.equals(value))
        throw error(L.l("@tag display-name '{0}' conflicts with previous value '{1}'.  The display-name attribute may only be specified once.",
                        value, oldValue));

      
      gen.setDisplayName(value);
    }
    else if (SMALL_ICON.equals(name)) {
      String oldValue = gen.getSmallIcon();
      
      if (oldValue != null && ! oldValue.equals(value))
        throw error(L.l("@tag small-icon '{0}' conflicts with previous value '{1}'.  The small-icon attribute may only be specified once.",
                        value, oldValue));

      
      gen.setSmallIcon(value);
    }
    else if (LARGE_ICON.equals(name)) {
      String oldValue = gen.getLargeIcon();
      
      if (oldValue != null && ! oldValue.equals(value))
        throw error(L.l("@tag large-icon '{0}' conflicts with previous value '{1}'.  The large-icon attribute may only be specified once.",
                        value, oldValue));

      
      gen.setLargeIcon(value);
    }
    else if (DESCRIPTION.equals(name)) {
      String oldValue = gen.getDescription();
      
      if (oldValue != null && ! oldValue.equals(value))
        throw error(L.l("@tag description '{0}' conflicts with previous value '{1}'.  The description attribute may only be specified once.",
                        value, oldValue));

      
      gen.setDescription(value);
    }
    else if (EXAMPLE.equals(name)) {
      String oldValue = gen.getExample();
      
      if (oldValue != null && ! oldValue.equals(value))
        throw error(L.l("@tag example '{0}' conflicts with previous value '{1}'.  The example attribute may only be specified once.",
                        value, oldValue));

      
      gen.setExample(value);
    }
    else if (DYNAMIC_ATTRIBUTES.equals(name)) {
      String oldValue = gen.getDynamicAttributes();
      
      if (oldValue != null && ! oldValue.equals(value))
        throw error(L.l("@tag dynamic-attributes '{0}' conflicts with previous value '{1}'.  The dynamic-attributes attribute may only be specified once.",
                        value, oldValue));
      else if (gen.findAttribute(value) != null) {
        throw error(L.l("@tag dynamic-attributes '{0}' conflicts with an attribute.",
                        value));
      }
      else if (gen.findVariable(value) != null) {
        throw error(L.l("@tag dynamic-attributes '{0}' conflicts with a variable.",
                        value));
      }
      
      gen.setDynamicAttributes(value);
    }
    else if (BODY_CONTENT.equals(name)) {
      String oldValue = gen.getBodyContent();
      
      if (oldValue != null && ! oldValue.equals(value)) {
        throw error(L.l("@tag body-content '{0}' conflicts with previous value '{1}'.  The body-content attribute may only be specified once.",
                        value, oldValue));
      }

      if (value.equals("scriptless")
          || value.equals("tagdependent")
          || value.equals("empty")) {
      }
      else
        throw error(L.l("'{0}' is an unknown body-content value for the JSP tag directive attribute.  'scriptless', 'tagdependent', and 'empty' are the allowed values.",
                      value));

      gen.setBodyContent(value);
    }
    else if (DEFERRED_AS_LITERAL.equals(name)) {
      _parseState.setDeferredSyntaxAllowedAsLiteral(value.equals("true"));
    }
    else if (TRIM_WHITESPACES.equals(name)) {
      if (value.equals("true"))
        _parseState.setTrimWhitespace(true);
      else if (value.equals("false"))
        _parseState.setTrimWhitespace(false);
      else
        throw error(L.l("trimDirectiveWhitespaces expects 'true' or 'false' at '{0}'",
                        value));
    }
    else {
      throw error(L.l("'{0}' is an unknown JSP tag directive attribute.  The valid attributes are: body-content, deferredSyntaxAllowedAsLiteral, display-name, dynamic-attributes, example, isELIgnored, language, large-icon, pageEncoding, small-icon, trimDirectiveWhitespaces.",
                      name.getName()));
    }
  }
  
  protected String getRelativeUrl(String value)
  {
    if (value.length() > 0 && value.charAt(0) == '/')
      return value;
    else
      return _parseState.getUriPwd() + value;
  }

  /**
   * Charset can be specific as follows:
   *  test/html; z=9; charset=utf8; w=12
   */
  static String parseCharEncoding(String type)
    throws JspParseException
  {
    type = type.toLowerCase(Locale.ENGLISH);
    int i;
    char ch;
    while ((i = type.indexOf(';')) >= 0 && i < type.length()) {
      i++;
      while (i < type.length() && ((ch = type.charAt(i)) == ' ' || ch == '\t'))
        i++;

      if (i >= type.length())
        return null;

      type = type.substring(i);
      i = type.indexOf('=');
      if (i >= 0) {
        if (! type.startsWith("charset"))
          continue;

        for (i++;
             i < type.length() && ((ch = type.charAt(i)) == ' ' || ch == '\t');
             i++) {
        }

        type = type.substring(i);
      }
      
      for (i = 0;
           i < type.length() && (ch = type.charAt(i)) != ';' && ch != ' ';
           i++) {
      }

      return type.substring(0, i);
    }

    return null;
  }
  
  /**
   * Called when the tag ends.
   */
  public void endAttributes()
    throws JspParseException
  {
    if (! _gen.isTag())
      throw error(L.l("tag directive is only allowed in tag files."));
  }
  
  /**
   * Return true if the node only has static text.
   */
  public boolean isStatic()
  {
    return true;
  }

  /**
   * Generates the XML text representation for the tag validation.
   *
   * @param os write stream to the generated XML.
   */
  public void printXml(WriteStream os)
    throws IOException
  {
    JavaTagGenerator gen = (JavaTagGenerator) _gen;
    
    os.print("<jsp:directive.tag");
    os.print(" jsp:id=\"" + gen.generateJspId() + "\"");

    if (_parseState.isELIgnoredPageSpecified())
      os.print(" el-ignored='" + _parseState.isELIgnored() + "'");

    if (_import != null)
      os.print(" import='" + _import + "'");
    
    /*
    if (! _parseState.isScriptingEnabled())
      os.print(" scripting-enabled='false'");
    */
    String dynAttr = gen.getDynamicAttributes();
    if (dynAttr != null)
      os.print(" dynamic-attributes='" + dynAttr + "'");

    os.print("/>");
  }

  /**
   * Generates the code for the tag
   *
   * @param out the output writer for the generated java.
   */
  public void generate(JspJavaWriter out)
    throws Exception
  {
  }
}
